一、动态代理模式的基本介绍

  1、代理对象,不需要实现接口,但是目标对象要实现接口,否则不能动态代理;

  2、代理对象的生成,是利用 JDK 的 API,动态的在内存中构建代理对象;

  3、动态代理也叫做:JDK 代理、接口代理

  4、实现步骤

    (1)代理对象和真实对象实现相同的接口;

    (2)代理对象 = Proxy.newProxyInstance();

    (3)使用代理对象调用方法

    (4)增强方法

      增强方法方式:

        ① 增强参数列表

        ② 增强返回值类型

        ③ 增强方法体执行逻辑

 

二、JDK 中生成代理对象的 API

  1、代理类所在包:java.lang.reflect.Proxy

  2、JDK 实现代理只需要使用 newProxyInstance 方法,但是该方法需要接受三个参数,完整的写法是:

1  public static Object newProxyInstance(ClassLoader loader,
2                                           Class<?>[] interfaces,
3                                           InvocationHandler h)

 

 

三、动态代理应用实例

  将上一节的静态代理改进成动态代理模(即:JDK代理模式

  1、UML 类图

    

  2、代码实现:

    接口:

1 /**
2  * 接口
3  */
4 public interface ITeacherDao {
5     void teach(); //授课
6 
7     void sayHello(String name);
8 }

 

    被代理对象(目标对象):

 1 public class TeacherDao implements ITeacherDao{
 2     @Override
 3     public void sayHello(String name) {
 4         System.out.println("Hello," + name);
 5     }
 6 
 7     @Override
 8     public void teach() {
 9         System.out.println("老师授课中。。。");
10     }
11 }

 

    代理工厂:

 1 public class ProxyFactory {
 2 
 3     //维护一个目标对象,Object
 4     private Object target;
 5 
 6     /**
 7      * 通过构造方法,对 target 进行初始化
 8      */
 9     public ProxyFactory(Object target) {
10         this.target = target;
11     }
12 
13     /**
14      *  给目标对象 生成一个代理对象
15      * @return
16      */
17     public Object getProxyInstance() {
18         /**
19          * public static Object newProxyInstance(ClassLoader loader,
20          *                                     Class<?>[] interfaces,
21          *                                     InvocationHandler h)
22          * 参数说明:
23          *  1、ClassLoader loader:
24          *      指定当前目标对象使用的类加载器,获取加载器的方法固定的
25          *  2、Class<?>[] interfaces
26          *      目标对象(被代理对象)实现的接口类型,使用泛型方式确认类型
27          *  3、InvocationHandler h:
28          *      事件处理,执行目标对象的方法时,会触发事件处理器方法,
29          *      会把当前执行的目标对象方法作为一个参数传入
30          */
31         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
32                 target.getClass().getInterfaces(),
33                 new InvocationHandler() {
34 
35                     @Override
36                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
37                         System.out.println("JDK代理开始");
38                         //通过反射机制调用目标对象的方法
39                         Object invoke = method.invoke(target, args);
40                         System.out.println("JDK代理提交");
41                         return invoke;
42                     }
43                 });
44     }
45 }

 

    客户端:

 1 public class Client {
 2     public static void main(String[] args) {
 3         //创建一个目标对象
 4         ITeacherDao target = new TeacherDao();
 5 
 6         //给目标对象创建代理对象,可以转成 ITeacherDAO
 7         ProxyFactory proxyFactory = new ProxyFactory(target);
 8         ITeacherDao proxyInstance = (ITeacherDao)proxyFactory.getProxyInstance();
 9 
10         System.out.println("proxyInstance=" + proxyInstance);
11         //proxyInstance类型=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
12         System.out.println("proxyInstance类型=" + proxyInstance.getClass());
13 
14         //通过代理对象,调用目标对象的方法
15         proxyInstance.teach();
16 
17         proxyInstance.sayHello("Tom");
18     }
19 }

 

四、动态代理应用实例

  我们用买电脑这件事情来叙述一下动态代理:

  当我们想买一个联想电脑,而此时联想电脑公司在北京,我们在西安,如果买电脑还得去北京,比较浪费时间。

  这是在西安有一个联想代理商,我们可以从代理商这里预订一台电脑,而代理商去北京给我们取货。这样就形成了一种动态代理。

  

  在这里:

    北京联想公司=真实对象

    西安联想代理商=代理对象

  这里西安代理商可以把联想电脑销售到西安各地,扩大了销售市场,相当于增强了功能。

  代码演示

  卖电脑的接口类:

1 public interface SaleComputer {
2 
3     public String sale(double money);
4 
5     public void show();
6 }

 

 

  卖电脑真实类:

 1 /**
 2  * 真实类
 3  */
 4 public class Lenovo implements SaleComputer {
 5     @Override
 6     public String sale(double money) {
 7 
 8         System.out.println("花了"+money+"元买了一台联想电脑...");
 9         return "联想电脑";
10     }
11 
12     @Override
13     public void show() {
14         System.out.println("展示电脑....");
15     }
16 }

 

  代理对象类

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 import java.lang.reflect.Proxy;
 4 
 5 public class ProxyTest {
 6 
 7     public static void main(String[] args) {
 8         //1.创建真实对象
 9         Lenovo lenovo = new Lenovo();
10         
11         //2.动态代理增强lenovo对象
12         /*
13             三个参数:
14                 1. 类加载器:真实对象.getClass().getClassLoader()
15                 2. 接口数组:真实对象.getClass().getInterfaces()
16                 3. 处理器:new InvocationHandler()
17          */
18         SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
19 
20             /*
21                 代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
22                     参数:
23                         1. proxy:代理对象
24                         2. method:代理对象调用的方法,被封装为的对象
25                         3. args:代理对象调用的方法时,传递的实际参数
26              */
27             @Override
28             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
29                 /*System.out.println("该方法执行了....");
30                 System.out.println(method.getName());
31                 System.out.println(args[0]);
32 
33 
34 
35 
36 */
37                 //判断是否是sale方法
38                 if(method.getName().equals("sale")){
39                     //1.增强参数
40                     double money = (double) args[0];
41                     money = money * 0.85;
42                     System.out.println("专车接你....");
43                     //使用真实对象调用该方法
44                     String obj = (String) method.invoke(lenovo, money);
45                     System.out.println("免费送货...");
46                     //2.增强返回值
47                     return obj+"_鼠标垫";
48                 }else{
49                     Object obj = method.invoke(lenovo, args);
50                     return obj;
51                 }
52 
53 
54 
55             }
56         });
57 
58         //3.调用方法
59 
60         String computer = proxy_lenovo.sale(8000);
61         System.out.println(computer);
62 
63         proxy_lenovo.show();
64     }
65 }

 

posted on 2021-02-02 21:38  格物致知_Tony  阅读(162)  评论(0编辑  收藏  举报