7.代理模式

本文转载:https://blog.kuangstudy.com/index.php/archives/526/

一.代理模式

1.什么是代理模式

为什么要学习代理模式,因为AOP的底层机制就是动态代理!

代理模式:

  • 静态代理

  • 动态代理

学习aop之前 , 我们要先了解一下代理模式!

1570016650994.png

租房案例:

2.静态代理

静态代理角色分析

  • 抽象角色 : 一般使用接口或者抽象类来实现

  • 真实角色 : 被代理的角色

  • 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .

  • 客户 : 使用代理角色来进行一些操作 .

(1)抽象角色:租房Rent.java

1 //抽象角色:租房
2 public interface Rent {
3 
4     void rent();
5 }

(2)真实角色:房东Host.java

1 //真实角色: 房东,房东要出租房子
2 public class Host implements Rent{
3     public void rent() {
4         System.out.println("房屋出租");
5     }
6 }

(3)代理角色:Proxy.java

 1 //代理角色:中介
 2 public class Proxy implements Rent {
 3 
 4     private Host host;
 5     public Proxy() { }
 6     public Proxy(Host host) {
 7         this.host = host;
 8     }
 9 
10     //租房
11     public void rent(){
12         seeHouse();
13         host.rent();
14         fare();
15     }
16     //看房
17     public void seeHouse(){
18         System.out.println("带房客看房");
19     }
20     //收中介费
21     public void fare(){
22         System.out.println("收中介费");
23     }
24 }

(4)租客角色:Client.java

 1 //客户类,一般客户都会去找代理!
 2 public class Client {
 3     public static void main(String[] args) {
 4         //房东要租房
 5         Host host = new Host();
 6         //中介帮助房东
 7         Proxy proxy = new Proxy(host);
 8 
 9         //你去找中介!
10         proxy.rent();
11     }
12 }

3.静态代理优缺点分析

  • 优点:

    • 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务

    • 公共业务交给代理角色,实现了业务分工

    • 公共业务发生扩展的时候,方便集中管理

  • 缺点:

    • 一个真实角色就会产生一个代理角色;代码量就会翻倍,开发效率就会变低

4.静态代理深入理解

(1)业务层抽象接口:UserService.java

1 //抽象角色:增删改查业务
2 public interface UserService {
3     void add();
4     void delete();
5     void update();
6     void query();
7 }

(2)业务层实现类:UserServiceImpl

 1 //真实对象,完成增删改查操作的人
 2 public class UserServiceImpl implements UserService {
 3 
 4     public void add() {
 5         System.out.println("增加了一个用户");
 6     }
 7 
 8     public void delete() {
 9         System.out.println("删除了一个用户");
10     }
11 
12     public void update() {
13         System.out.println("更新了一个用户");
14     }
15 
16     public void query() {
17         System.out.println("查询了一个用户");
18     }
19 }

(3)代理角色:用来添加日志功能UserServiceProxy.java

 1 //代理角色,在这里面增加日志的实现
 2 public class UserServiceProxy implements UserService {
 3     private UserServiceImpl userService;
 4 
 5     public void setUserService(UserServiceImpl userService) {
 6         this.userService = userService;
 7     }
 8 
 9     public void add() {
10         log("add");
11         userService.add();
12     }
13 
14     public void delete() {
15         log("delete");
16         userService.delete();
17     }
18 
19     public void update() {
20         log("update");
21         userService.update();
22     }
23 
24     public void query() {
25         log("query");
26         userService.query();
27     }
28 
29     public void log(String msg){
30         System.out.println("执行了"+msg+"方法");
31     }
32 
33 }

(4)用户类:Client.java

 1 public class Client {
 2     public static void main(String[] args) {
 3         //真实业务
 4         UserServiceImpl userService = new UserServiceImpl();
 5         //代理类
 6         UserServiceProxy proxy = new UserServiceProxy();
 7         //使用代理类实现日志功能!
 8         proxy.setUserService(userService);
 9 
10         proxy.add();
11     }
12 }

(5)总结

  • 我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想

5.动态代理

  • 动态代理和静态代理角色一样

  • 动态代理的代理类是动态生成的,不是我们直接写好的

  • 动态代理大致上分为两大类:(基于接口和基于类的)

    • 基于接口:经典的是JDK的动态代理

    • 基于类:例如:cglib

    • java字节码实现:现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist

    • 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!

(1)动态代理实现

JDK的动态代理需要了解两个类

  • 核心 : InvocationHandler 和 Proxy 

  • InvocationHandler:调用处理程序类

  • Proxy:创建动态代理类

抽象租房角色:Rent.java

1 //抽象角色:租房
2 public interface Rent {
3 
4     void rent();
5 }

真实租房角色:Host.java

1 //真实角色: 房东,房东要出租房子
2 public class Host implements Rent {
3     public void rent() {
4         System.out.println("房屋出租");
5     }
6 }

代理角色:ProxyInvocationHandler. java

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 import java.lang.reflect.Proxy;
 4 
 5 public class ProxyInvocationHandler implements InvocationHandler {
 6     private Rent rent;
 7 
 8     public void setRent(Rent rent) {
 9         this.rent = rent;
10     }
11 
12     //生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
13     public Object getProxy(){
14         return Proxy.newProxyInstance(this.getClass().getClassLoader(),
15                 rent.getClass().getInterfaces(),this);
16     }
17 
18     // proxy : 代理类 method : 代理类的调用处理程序的方法对象.
19     // 处理代理实例上的方法调用并返回结果
20     @Override
21     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
22         seeHouse();
23         //核心:本质利用反射实现!
24         Object result = method.invoke(rent, args);
25         fare();
26         return result;
27     }
28 
29     //看房
30     public void seeHouse(){
31         System.out.println("带房客看房");
32     }
33     //收中介费
34     public void fare(){
35         System.out.println("收中介费");
36     }
37 
38 }

租客角色:Client . java

 1 //客户类
 2 public class Client {
 3     public static void main(String[] args) {
 4         //真实角色
 5         Host host = new Host();
 6         //代理实例的调用处理程序
 7         ProxyInvocationHandler pih = new ProxyInvocationHandler();
 8         pih.setRent(host); //将真实角色放置进去!
 9         Rent proxy = (Rent) pih.getProxy(); //动态生成对应的代理类!
10         proxy.rent();
11     }
12 }

(2)动态代理深入理解

  • 我们来使用动态代理实现代理我们后面写的UserService!

  • 我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!

代理角色:ProxyInvocationHandler. java

 1 public class ProxyInvocationHandler implements InvocationHandler {
 2     private Object target;
 3 
 4     public void setTarget(Object target) {
 5         this.target = target;
 6     }
 7 
 8     //生成代理类
 9     public Object getProxy(){
10         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
11                 target.getClass().getInterfaces(),this);
12     }
13 
14     // proxy : 代理类
15     // method : 代理类的调用处理程序的方法对象.
16     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
17         log(method.getName());
18         Object result = method.invoke(target, args);
19         return result;
20     }
21 
22     public void log(String methodName){
23         System.out.println("执行了"+methodName+"方法");
24     }
25 
26 }

客户角色:Client.java

 1 public class Client {
 2     public static void main(String[] args) {
 3         //真实对象
 4         UserServiceImpl userService = new UserServiceImpl();
 5         //代理对象的调用处理程序
 6         ProxyInvocationHandler pih = new ProxyInvocationHandler();
 7         pih.setTarget(userService); //设置要代理的对象
 8         UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
 9         proxy.delete();
10     }
11 }

(3)动态代理的好处

静态代理有的它都有,静态代理没有的,它也有!

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .

  • 公共的业务由代理来完成 . 实现了业务的分工 ,

  • 公共业务发生扩展时变得更加集中和方便 .

  • 一个动态代理 , 一般代理某一类业务

  • 一个动态代理可以代理多个类,代理的是接口!

 6.总结:

(1)静态代理特点:代理类(UserServiceProxy)和被代理类(UserServiceImpl)在编译期间就确定下来了

(2)动态代理特点:

  1. 代理类是在代码运行时才能确定下来的,通过ProxyInvocationHandler创建出代理类

  2. 可以灵活的通过不同的被代理类创建不同的代理类

posted @ 2020-02-18 14:26  All_just_for_fun  阅读(396)  评论(0编辑  收藏  举报