Spring -- 06 -- JDK动态代理和CGLIB动态代理的区别

一、相关概念

1、JDK 动态代理原理
  • 使用拦截器 (需要实现 InvocationHandler 接口) 加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 invoke() 方法来进行处理
2、CGLIB 动态代理原理
  • 使用 ASM 字节码框架 (需要实现 MethodInterceptor 接口),加载代理对象类的 Class 文件,通过修改其字节码生成子类来进行处理
3、什么时候使用 JDK 动态代理、CGLIB 动态代理?
  • 如果目标对象实现了接口,默认情况下会使用 JDK 动态代理来实现 AOP,可以强制使用 CGLIB 来实现 AOP

  • 如果目标对象没有实现接口,则必须使用 CGLIB 动态代理,Spring 会在 JDK 动态代理和 CGLIB 动态代理之间自动切换

4、如何强制使用 CGLIB 动态代理实现 AOP?
  • XML 文件

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
  • application.yml 文件

    spring:
      aop:
        proxy-target-class: true
    
5、JDK 动态代理和 CGLIB 动态代理的区别
  • JDK 动态代理只能针对实现了接口的类生成代理,而不能针对普通类

  • CGLIB 动态代理针对类 (不能用 final 进行修饰) 生成代理,通过生成目标类的子类,并覆盖目标类的方法来实现增强

6、JDK 动态代理和 CGLIB 动态代理谁更快?
  • 在 JDK6 和 JDK7 版本时,JDK 动态代理的速度要比 CGLIB 动态代理慢

  • 从 JDK8 开始,JDK 动态代理的速度要比 CGLIB 动态代理快


二、代码示例

  • UserService 接口,供 JDK 动态代理使用

    public interface UserService {
    
        void addUser(String username, String password);
    }
    
  • UserServiceImpl 实现类,实现 UserService 接口,供 CGLIB 动态代理使用

    public class UserServiceImpl implements UserService {
    
        @Override
        public void addUser(String username, String password) {
            System.out.println("调用了 UserServiceImpl 类的 addUser() 方法");
        }
    }
    
  • CGLIB 动态代理

    public class CGLIBProxy implements MethodInterceptor {
    
        /**
         * 需要代理的目标对象
         */
        private Object targetObj;
    
        /**
         * 获取代理对象
         */
        public Object newProxy(Object targetObj) {
            this.targetObj = targetObj;
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(targetObj.getClass());
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
    
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            // 过滤方法
            if ("addUser".equals(method.getName())) {
                checkPermissions();
            }
            return method.invoke(targetObj, args);
        }
    
        private void checkPermissions() {
            System.out.println("检查用户权限 checkPermissions");
        }
    }
    
  • JDK 动态代理

    public class JDKProxy implements InvocationHandler {
    
        /**
         * 需要代理的目标对象
         */
        private Object targetObj;
    
        /**
         * 获取代理对象
         */
        public Object newProxy(Object targetObj) {
            this.targetObj = targetObj;
            Class<?> clazz = targetObj.getClass();
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 检查权限
            checkPermissions();
            return method.invoke(targetObj, args);
        }
    
        private void checkPermissions() {
            System.out.println("检查用户权限 checkPermissions");
        }
    }
    
  • 进行测试

    public class ProxyTest {
    
        public static void main(String[] args) {
            System.out.println("================ CGLIB动态代理 ================");
            CGLIBProxy cglibProxy = new CGLIBProxy();
            UserServiceImpl cglib = (UserServiceImpl) cglibProxy.newProxy(new UserServiceImpl());
            cglib.addUser("tom", "root");
            System.out.println("================ JDK动态代理 ================");
            JDKProxy jdkProxy = new JDKProxy();
            UserService jdk = (UserService) jdkProxy.newProxy(new UserServiceImpl());
            jdk.addUser("tom", "root");
        }
    }
    
  • 测试结果
    在这里插入图片描述

  • 去除 UserServiceImpl 类实现 UserService 接口 (即此时 UserServiceImpl 是一个普通类),再进行测试

    public class UserServiceImpl {
    
        public void addUser(String username, String password) {
            System.out.println("调用了 UserServiceImpl 类的 addUser() 方法");
        }
    }
    
  • 测试结果
    在这里插入图片描述


三、参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值