• JDK动态代理和CGLib动态代理的对比


    JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
    CGLib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    1. JDK动态代理

    1.1 角色

    1. Interface:对于JDK Proxy,业务类是需要一个Interface的。
    2. Proxy:Proxy类是动态产生的,这个类在调用Proxy.newProxyInstance()方法之后,产生一个Proxy类的实力。实际上,这个Proxy类也是存在的,不仅仅是类的实例,这个Proxy类可以保存在硬盘上。
    3. Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来。
    4. InvocationHandler:这个类在业务委托类执行时,会先调用invoke方法。invoke方法在执行想要的代理操作,可以实现对业务方法的再包装。

    1.2 总结

    • JDK动态代理类实现了InvocationHandler接口,重写的invoke方法。
    • JDK动态代理的基础是反射机制(method.invoke(对象,参数))Proxy.newProxyInstance()。

    1.3 动态代理步骤

    1. 创建被代理类及接口(JDK代理是接口代理)
    2. 创建Handle类实现 InvocationHandler接口 ,重写invoke方法
    3. 通过Proxy的newProxyInstance()方法获取代理类对象
    4. 通过代理类对象调用被代理类的方法

    1.4 代码实现

    //接口类
    public interface FoodService {
        public void makeNoodle();
        public void makeChicken();
    }
    
    //代理类,实现定义的接口
    public class FoodServiceImpl implements FoodService {
        @Override
        public void makeNoodle() {
            System.out.println("make noodle");
        }
    
        @Override
        public void makeChicken() {
            System.out.println("make Chicken");
        }
    }
    public class JDKProxyFactory implements InvocationHandler {
        private Object target;
    
        public JDKProxyFactory(Object target) {
            super();
            this.target = target;
        }
    
        // 创建代理对象
        public Object createProxy() {
            // 1.得到目标对象的类加载器
            ClassLoader classLoader = target.getClass().getClassLoader();
            // 2.得到目标对象的实现接口
            Class<?>[] interfaces = target.getClass().getInterfaces();
            // 3.第三个参数需要一个实现invocationHandler接口的对象
            Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
            return newProxyInstance;
        }
    
    
        // 第一个参数:代理对象.一般不使用;第二个参数:需要增强的方法;第三个参数:方法中的参数
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("这是增强方法前......");
            Object invoke = method.invoke(target, args);
            System.out.println("这是增强方法后......");
            return invoke;
        }
    
        public static void main(String[] args) {
            // 1.创建对象
            FoodServiceImpl foodService = new FoodServiceImpl();
            // 2.创建代理对象
            JDKProxyFactory proxy = new JDKProxyFactory(foodService);
            // 3.调用代理对象的增强方法,得到增强后的对象
            FoodService createProxy = (FoodService) proxy.createProxy();
            createProxy.makeChicken();
        }
    
    }

    2. CGLib动态代理

    强制使用CGLib

    <!-- proxy-target-class="false"默认使用JDK动态代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
    <aop-config proxy-target-class="true">
    <!-- 切面详细配置 -->
    </aop-config>
    public class CglibProxyFactory implements MethodInterceptor {
        //得到目标对象
        private Object target;
    
        //使用构造方法传递目标对象
        public CglibProxyFactory(Object target) {
            super();
            this.target = target;
        }
    
        //创建代理对象
        public Object createProxy(){
            //1.创建Enhancer
            Enhancer enhancer = new Enhancer();
            //2.传递目标对象的class
            enhancer.setSuperclass(target.getClass());
            //3.设置回调操作
            enhancer.setCallback(this);
    
            return enhancer.create();
        }
    
    
        //参数一:代理对象;参数二:需要增强的方法;参数三:需要增强方法的参数;参数四:需要增强的方法的代理
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("这是增强方法前......");
            Object invoke = methodProxy.invoke(target, args);
            System.out.println("这是增强方法后......");
            return invoke;
        }
    
        public static void main(String[] args) {
            // 1.创建对象
            FoodServiceImpl foodService = new FoodServiceImpl();
            // 2.创建代理对象
            CglibProxyFactory proxy = new CglibProxyFactory(foodService);
            // 3.调用代理对象的增强方法,得到增强后的对象
            FoodService createProxy = (FoodService) proxy.createProxy();
            createProxy.makeChicken();
        }
    }

    3. 两者区别

    • JDK代理只能对实现接口的类生成代理;CGLib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
    • JDK代理使用的是反射机制实现aop的动态代理,CGLib代理使用字节码处理框架ASM,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,CGLib创建效率较低,执行效率高。
    • JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLib则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
  • 相关阅读:
    二维数组输出10行杨辉三角
    二维数组的练习----求和
    数组的异常及处理
    二维数组在内存中的结构
    Ubuntu系统中安装Mercurial 以支持hg
    什么是插补、直线插补、联动与插补
    压力表(负压表...)
    常用接近开关的原理和分类
    VMware Ubuntu安装详细过程
    Redis+Spring缓存实例(windows环境,附实例源码及详解)
  • 原文地址:https://www.cnblogs.com/zjfjava/p/13919437.html
Copyright © 2020-2023  润新知