zoukankan      html  css  js  c++  java
  • JDK和CGLIB动态代理原理区别

    JDK和CGLIB动态代理原理区别

    https://blog.csdn.net/yhl_jxy/article/details/80635012

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yhl_jxy/article/details/80635012

    一 JDK和CGLIB动态代理原理

    JDK动态代理:

    利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,

    在调用具体方法前调用InvokeHandler来处理。

    CGLiB动态代理:

    利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    何时使用JDK还是CGLiB?

    1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。

    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP。

    3、如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。


    如何强制使用CGLIB实现AOP?

    1、添加CGLIB库(aspectjrt-xxx.jar、aspectjweaver-xxx.jar、cglib-nodep-xxx.jar)

    2、在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>


    JDK动态代理和CGLIB字节码生成的区别?

    1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类。

    2、CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,

         并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,

         对于final类或方法,是无法继承的。


    CGlib比JDK快?

    1、使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,

    在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,

    因为CGLib原理是动态生成被代理类的子类。

    2、在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,

    只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,

    总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理消息确有点跟不上步伐。


    Spring如何选择用JDK还是CGLiB?

    1、当Bean实现接口时,Spring就会用JDK的动态代理。

    2、当Bean没有实现接口时,Spring使用CGlib是实现。

    3、可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

     
    二 代码实例

    接口:

    1. package com.lanhuigu.spring.proxy.compare;
    2.  
    3. /**
    4. * 用户管理接口(真实主题和代理主题的共同接口,这样在任何可以使用真实主题的地方都可以使用代理主题代理。)
    5. * --被代理接口定义
    6. */
    7. public interface IUserManager {
    8. void addUser(String id, String password);
    9. }

    实现类:

    1. package com.lanhuigu.spring.proxy.compare;
    2.  
    3. /**
    4. * 用户管理接口实现(被代理的实现类)
    5. */
    6. public class UserManagerImpl implements IUserManager {
    7.  
    8. @Override
    9. public void addUser(String id, String password) {
    10. System.out.println("======调用了UserManagerImpl.addUser()方法======");
    11. }
    12. }

    JDK代理实现:

    1. package com.lanhuigu.spring.proxy.compare;
    2.  
    3. import java.lang.reflect.InvocationHandler;
    4. import java.lang.reflect.Method;
    5. import java.lang.reflect.Proxy;
    6.  
    7. /**
    8. * JDK动态代理类
    9. */
    10. public class JDKProxy implements InvocationHandler {
    11. /** 需要代理的目标对象 */
    12. private Object targetObject;
    13.  
    14. /**
    15. * 将目标对象传入进行代理
    16. */
    17. public Object newProxy(Object targetObject) {
    18. this.targetObject = targetObject;
    19. //返回代理对象
    20. return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
    21. targetObject.getClass().getInterfaces(), this);
    22. }
    23.  
    24. /**
    25. * invoke方法
    26. */
    27. @Override
    28. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    29. // 一般我们进行逻辑处理的函数比如这个地方是模拟检查权限
    30. checkPopedom();
    31. // 设置方法的返回值
    32. Object ret = null;
    33. // 调用invoke方法,ret存储该方法的返回值
    34. ret = method.invoke(targetObject, args);
    35. return ret;
    36. }
    37.  
    38. /**
    39. * 模拟检查权限的例子
    40. */
    41. private void checkPopedom() {
    42. System.out.println("======检查权限checkPopedom()======");
    43. }
    44. }

    CGLIB代理实现:

    1. package com.lanhuigu.spring.proxy.compare;
    2.  
    3. import net.sf.cglib.proxy.Enhancer;
    4. import net.sf.cglib.proxy.MethodInterceptor;
    5. import net.sf.cglib.proxy.MethodProxy;
    6.  
    7. import java.lang.reflect.Method;
    8.  
    9. /**
    10. * CGLibProxy动态代理类
    11. */
    12. public class CGLibProxy implements MethodInterceptor {
    13. /** CGLib需要代理的目标对象 */
    14. private Object targetObject;
    15.  
    16. public Object createProxyObject(Object obj) {
    17. this.targetObject = obj;
    18. Enhancer enhancer = new Enhancer();
    19. enhancer.setSuperclass(obj.getClass());
    20. enhancer.setCallback(this);
    21. Object proxyObj = enhancer.create();
    22. // 返回代理对象
    23. return proxyObj;
    24. }
    25.  
    26. @Override
    27. public Object intercept(Object proxy, Method method, Object[] args,
    28. MethodProxy methodProxy) throws Throwable {
    29. Object obj = null;
    30. // 过滤方法
    31. if ("addUser".equals(method.getName())) {
    32. // 检查权限
    33. checkPopedom();
    34. }
    35. obj = method.invoke(targetObject, args);
    36. return obj;
    37. }
    38.  
    39. private void checkPopedom() {
    40. System.out.println("======检查权限checkPopedom()======");
    41. }
    42. }

    客户端测试类:

    1. package com.lanhuigu.spring.proxy.compare;
    2.  
    3. /**
    4. * 代理模式[[ 客户端--》代理对象--》目标对象 ]]
    5. */
    6. public class Client {
    7. public static void main(String[] args) {
    8. System.out.println("**********************CGLibProxy**********************");
    9. CGLibProxy cgLibProxy = new CGLibProxy();
    10. IUserManager userManager = (IUserManager) cgLibProxy.createProxyObject(new UserManagerImpl());
    11. userManager.addUser("lanhuigu", "123456");
    12.  
    13. System.out.println("**********************JDKProxy**********************");
    14. JDKProxy jdkPrpxy = new JDKProxy();
    15. IUserManager userManagerJDK = (IUserManager) jdkPrpxy.newProxy(new UserManagerImpl());
    16. userManagerJDK.addUser("lanhuigu", "123456");
    17. }
    18. }

    程序运行结果:

    三 JDK和CGLIB动态代理总结

    JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:

    1、实现InvocationHandler 

    2、使用Proxy.newProxyInstance产生代理对象

    3、被代理的对象必须要实现接口

    CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,

    覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理;

  • 相关阅读:
    CDH 2、Cloudera Manager的安装
    204 01 Android 零基础入门 03 Java常用工具类 04 Java集合 04 Map集合 01 Map概述
    203 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 07 删除宠物猫信息数据(引入泛型知识点)
    202 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 06 查找宠物猫信息数据
    201 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 05 添加重复的宠物猫信息数据
    200 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 04 添加和显式宠物猫信息
    199 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 03 宠物猫信息管理概述
    198 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 02 案例:在集合中插入字符串
    197 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 01 Set概述
    196 01 Android 零基础入门 03 Java常用工具类 04 Java集合 02 List集合 05 案例:公告的删除和修改
  • 原文地址:https://www.cnblogs.com/yibutian/p/9634621.html
Copyright © 2011-2022 走看看