设计模式之cglib动态代理

打印 上一主题 下一主题

主题 939|帖子 939|积分 2821

什么是动态代理呢?
动态代理就是在java历程运行时,通过字节码技术,动态的生成某个类的代理类。在这个代理类中,我们可以做一些额外的操作,一方面仍然保持原有的方法的能力,另外一方面还增强了这些能力。听着是不是AOP有点像,没错,动态代理就是AOP的技术基石。
在这之前我曾经写过两篇相关的文章:
https://www.cnblogs.com/jilodream/p/10611593.html    设计模式之代理模式
https://www.cnblogs.com/jilodream/p/10624940.html     设计模式之Jdk动态代理
而在实现动态代理时,一般会有两种办法:
jdk动态代理(可以点上文链接检察),以及cglib动态代理,
话不多说,我们直接来看如何使用cglib来动态代理:
例子我们还是使用和jdk动态代理雷同的明星/明星代理类这个场景
pom依赖
  1. 1         <dependency>
  2. 2             <groupId>cglib</groupId>
  3. 3             <artifactId>cglib</artifactId>
  4. 4             <version>3.1</version>
  5. 5         </dependency>
复制代码
明星类
  1. 1 package com.example.demo.learncglib;
  2. 2
  3. 3 import lombok.Data;
  4. 4 import lombok.NoArgsConstructor;
  5. 5
  6. 6 /**
  7. 7  * @discription
  8. 8  */
  9. 9
  10. 10 @Data
  11. 11 @NoArgsConstructor
  12. 12 public class SuperStar implements ISuperStar {
  13. 13     String starName;
  14. 14
  15. 15     public SuperStar(String starName) {
  16. 16         this.starName = starName;
  17. 17     }
  18. 18
  19. 19     @Override
  20. 20     public void signContract() {
  21. 21         System.out.println(starName + " 签名");
  22. 22         // to do sth
  23. 23         return;
  24. 24     }
  25. 25
  26. 26     @Override
  27. 27     public void negotiate() {
  28. 28         System.out.println(starName + " 谈判");
  29. 29         // to do sth
  30. 30         return;
  31. 31     }
  32. 32
  33. 33     @Override
  34. 34     public String getStarImage() {
  35. 35         System.out.println(starName + " start image");
  36. 36         // to do sth
  37. 37         return "One " + starName + " Image";
  38. 38     }
  39. 39 }
复制代码
明星类接口
  1. 1 package com.example.demo.learncglib;
  2. 2
  3. 3 public interface ISuperStar
  4. 4 {
  5. 5     /**
  6. 6      * 签约
  7. 7      */
  8. 8     void signContract();
  9. 9
  10. 10     void negotiate();
  11. 11
  12. 12     String getStarImage();
  13. 13 }
复制代码
代理工厂
  1. 1 package com.example.demo.learncglib;
  2. 2
  3. 3
  4. 4 import net.sf.cglib.core.DebuggingClassWriter;
  5. 5 import net.sf.cglib.proxy.Enhancer;
  6. 6 import net.sf.cglib.proxy.MethodInterceptor;
  7. 7 import net.sf.cglib.proxy.MethodProxy;
  8. 8
  9. 9 import java.lang.reflect.Method;
  10. 10
  11. 11 /**
  12. 12  * @discription
  13. 13  */
  14. 14 public class ProxyFactory implements MethodInterceptor {
  15. 15
  16. 16     private String starName;
  17. 17
  18. 18     public SuperStar create(String starName) {
  19. 19         System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\code\\common\\learn-design" +
  20. 20                 "-pattern\\target\\cglib");
  21. 21
  22. 22         this.starName = starName;
  23. 23         Enhancer enhancer = new Enhancer();
  24. 24         enhancer.setSuperclass(SuperStar.class);
  25. 25         enhancer.setCallback(this);
  26. 26         SuperStar proxy = (SuperStar) enhancer.create();
  27. 27         proxy.starName = starName;
  28. 28         return proxy;
  29. 29     }
  30. 30
  31. 31
  32. 32     @Override
  33. 33     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  34. 34         System.out.println(starName + "的代理人开始组织活动");
  35. 35         Object obj = methodProxy.invokeSuper(o, objects);
  36. 36         System.out.println(starName + "的代理人结束组织活动");
  37. 37         return obj;
  38. 38     }
  39. 39 }
复制代码
主类
  1. 1 package com.example.demo.learncglib;
  2. 2
  3. 3 /**
  4. 4  * @discription
  5. 5  */
  6. 6 public class CglibMain {
  7. 7     public static void main(String[] args) {
  8. 8         ProxyFactory factory = new ProxyFactory();
  9. 9         SuperStar superStar = factory.create("messi");
  10. 10         superStar.signContract();
  11. 11         superStar.negotiate();
  12. 12         String image=superStar.getStarImage();
  13. 13         System.out.println("we get a image: "+image);
  14. 14     }
  15. 15
  16. 16
  17. 17 }
复制代码
运行效果
  1. messi的代理人开始组织活动
  2. messi 签名
  3. messi的代理人结束组织活动
  4. messi的代理人开始组织活动
  5. messi 谈判
  6. messi的代理人结束组织活动
  7. messi的代理人开始组织活动
  8. messi start image
  9. messi的代理人结束组织活动
  10. we get a image: One messi Image
  11. Disconnected from the target VM, address: '127.0.0.1:64165', transport: 'socket'
复制代码
生成代理类的焦点逻辑在com.example.demo.learncglib.ProxyFactory#create方法中:
我们首先声明一个增强器:Enhancer enhancer
接着设置代理类父类:SuperStar.class
接着设置回调类(包含增强方法的类):? implements MethodInterceptor
最后调用增强类的创建方法就生成好了:enhancer.create()
整体的流程和jdk动态代理很像,
不同点是jdk动态代理是根据接口,动态的生成实现类,代理类和被代理类均为接口实现类,是“兄弟关系”,被代理的方法就是接口中公开的方法。
而cglib动态代理是将被代理类作为父类,派生出子类,代理类和被代理类均为继承关系,是“父子关系”,被代理的方法就是父类中公开的方法。
如下图:

实在细细想想也很正常,我们想要间接的动态的获取到某个类中公开的方法,有两种途径,第一种是继承自它,那么它所有的公开方法我们都能继续持有(cglib的思路)。第二种就是和他实现雷同的约定(接口),那么它多有开发的协议,我们也就能动态的获取到了(jdk动态代理的思路)。
说了这么多来讲讲cglib方式的范围性,主要还是和继承有关系:
1、无法动态代理final方法,因为子类无法复写。

2、无法动态代理static,因为子类无法复写。jdk动态代理和cglib可以说是各有优劣,很多人说颠末jdk动态代理的速度优化,spring 目前已经默认采用jdk动态代理了,所以jdk动态代理更好。
这里我要说两点,
1、设计和实现是两回事,未来cglib的实现思路颠末优化,又胜出了,也并不能说明cglib的设计方案更好;
2、目前的Springboot最新版本又采用了cglib作为默认的aop实现方式,这也并不能说明cglib就比jdk动态代理方式要强了。

ps:假如想要将运行时动态生成的class文件生存到磁盘中,可以在实行的代码出添加,如上文代码示例的红色字体处:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\code\\common\\learn-design-pattern\\target\\cglib");

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

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

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

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

本版积分规则

东湖之滨

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表