动态代理

打印 上一主题 下一主题

主题 929|帖子 929|积分 2787

咱们来聊聊动态代理,大家最开始听到这个词的时候肯定很懵,我也是这样的。同时大家脑海中肯定也会想到是不是会有静态代理呢?答案是肯定的。想要对动态代理了解透彻,首先需要先了解什么是代理。
1.代理
听到代理这个词,相信大家在心中知道了这个的词的作用与含义。在日常生活中大家肯定见过或者说知道这么些个场景。例如:大家去租房或者说买房,是不是有房屋中介会联系到我们。我们向中介诉说我们的需求,而我们只需要等待,在等待期间中介会根据我们的需求去找到匹配房源,然后向我们推荐。
在上面的场景中,房屋中介代替我们去做了寻找房源的事情,我们可以称房屋中介为代理。
类似的场景还有:商品代购、经纪人等等。
在讲解静态代理和动态之前,咱们先来了解下代理模式。
2.代理模式
代理模式是一种设计模式,它为其他对象提供一个代理以控制对这个对象的访问。在代理模式中,代理对象(Proxy)代表了目标对象(Real Subject),并提供了与目标对象相同的接口。客户端可以通过代理对象间接调用目标对象的方法,而代理对象可以在调用前后增加额外的操作,比如权限检查、日志记录、缓存处理、延迟加载等。
相信有读者看完这段话还是不能理解,没关系。下面咱们用代码实现代理看看,读者后面再来看看这段话相信就有自己的理解了。
3. 静态代理
在先讲解动态代理之前,咱们先讲解什么是静态代理。
定义接口
点击查看代码
  1. package com.demo.proxy;
  2. /**
  3. * 接口
  4. */
  5. public interface Star {
  6.     String sing(String name);
  7.     String dance(String dance);
  8. }
复制代码
定义被代理类
点击查看代码
  1. package com.demo.proxy;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. /**
  5. * 被代理类
  6. */
  7. @Data
  8. @AllArgsConstructor
  9. public class BigStar implements Star{
  10.     private String name;
  11.     @Override
  12.     public String sing(String song) {
  13.         System.out.println(this.name+"正在唱歌:"+song);
  14.         return "谢谢你们喜欢我的歌";
  15.     }
  16.     @Override
  17.     public String dance(String dances){
  18.         System.out.println(this.name+"正在跳舞:"+dances);
  19.         return "谢谢你们喜欢我的舞";
  20.     }
  21. }
复制代码
定义代理类
点击查看代码
  1. package com.demo.proxy;
  2. /**
  3. * 代理类
  4. */
  5. public class StaticProxy implements Star{
  6.     private BigStar bigStar;
  7.     public StaticProxy() {
  8.     }
  9.     public StaticProxy(BigStar bigStar) {
  10.         this.bigStar = bigStar;
  11.     }
  12.     @Override
  13.     public String sing(String name) {
  14.         /*代理对象增强的部分*/
  15.         System.out.println(System.currentTimeMillis());
  16.         /*被代理对象调用方法*/
  17.         String s = bigStar.sing(name);
  18.         /*代理对象增强的部分*/
  19.         System.out.println(System.currentTimeMillis());
  20.         return s;
  21.     }
  22.     @Override
  23.     public String dance(String dance) {
  24.         return null;
  25.     }
  26. }
复制代码
测试
我们来回顾下静态代理的实现:
(1)代理类是自己手工实现的,自己创建一个Java类,表示代理类。
(2)同时你所要代理的目标是确定的。
总结来说静态代理:目标类和代理类实现了相同的接口,在代理类中依赖了目标类,代理类的方法中调用了目标类的方法,并做了一些增强性的工作。
同时也可以发现静态代理的缺点:
(1)当目标类增加了,代理类可能也需要成倍的增加,代理类数量过多。
(2)当你的接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多。
4.动态代理
动态代理指的是:在程序的执行过程中,使用jdk的反射机制,创建代理对象,并动态的指定代理的目标类。
动态代理的实现方式常用有两种:

  • 使用JDK代理。
  • 通过CDLIB代理。
在本文着重讲解JDK动态代理,jdk动态代理中最重要的两个分别是Proxy类和InvocationHandler接口。(要求目标对象必须实现接口
Method
当你有一个 Method 对象,代表了某个类的一个具体方法时,你可以通过调用 invoke() 方法来执行该方法。invoke() 方法接受两个参数:
object:这是要执行方法的对象实例。对于静态方法,这个参数可以是 null。
args:这是一个可变参数列表,包含了传递给目标方法的实际参数值。如果方法没有参数,可以传入一个空数组(new Object[0])。
Proxy类的newProxyInstance方法
点击查看代码
  1. /*参数1:用于指定类加载器 去加载生成的代理类  写法固定:一般用当前类的类加载器
  2.   参数2:用于指定生成的代理长成什么样子,也就是有哪些方法
  3.   参数3:用于指定生成的代理对象 做什么事情InvocationHandler 是个接口*/
  4. public static Object newProxyInstance(ClassLoader loader,
  5.                                           Class<?>[] interfaces,
  6.                                           InvocationHandler h)
复制代码
InvocationHandler接口的invoke方法
点击查看代码
  1. // Object proxy:jdk创建的代理对象,无需赋值
  2. // Method method:目标类中的方法
  3. // Object[] args:目标类中方法的参数
  4. public Object invoke(Object proxy, Method method, Object[] args)
复制代码
动态代理步骤
创建接口,定义目标类要完成的功能
点击查看代码
  1. package com.demo.proxy;
  2. /**
  3. * 接口
  4. */
  5. public interface Star {
  6.     String sing(String name);
  7.     String dance(String dance);
  8. }
复制代码
创建目标类,实现该接口

点击查看代码
  1. package com.demo.proxy;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. /**
  6. * 被代理类
  7. */
  8. @Data
  9. @AllArgsConstructor
  10. @NoArgsConstructor
  11. public class BigStar implements Star{
  12.     private String name;
  13.     @Override
  14.     public String sing(String song) {
  15.         System.out.println(this.name+"正在唱歌:"+song);
  16.         return "谢谢你们喜欢我的歌";
  17.     }
  18.     @Override
  19.     public String dance(String dances){
  20.         System.out.println(this.name+"正在跳舞:"+dances);
  21.         return "谢谢你们喜欢我的舞";
  22.     }
  23. }
复制代码
创建 InvocationHandler 接口的实现类,在invoke()方法中完成代理类的功能
点击查看代码
  1. package com.demo.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. public class MyInvocationHandler implements InvocationHandler {
  5.     private Object target;
  6.     //动态代理,目标对象是活动的,不是固定的,需要传入进来
  7.     public MyInvocationHandler(Object target) {
  8.         this.target = target;
  9.     }
  10.     @Override //回调方法
  11.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  12.         /*代理对象做的事 会在这里写代码*/
  13.         if(method.getName().equals("sing")){
  14.             System.out.println("收钱,20w");
  15.             //return method.invoke(star,args);
  16.         }else if(method.getName().equals("dance")){
  17.             System.out.println("收钱,10w");
  18.             //return method.invoke(star,args);
  19.         }
  20.         return method.invoke(target,args);
  21.     }
  22. }
复制代码
测试

动态代理执行流程

望各位大佬指正补充。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

道家人

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表