jdk动态代理和cglib动态代理源码解析

JDK动态代理

        测试代码

public class JdkAgent {

    public static void main(String[] args) throws Exception {
        // =========================第一种==========================
        // 1、生成$Proxy0的class文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 2、获取动态代理类
        Class proxyClazz = Proxy.getProxyClass(Hello.class.getClassLoader(), Hello.class);
        // 3、获得代理类的构造函数,并传入参数类型InvocationHandler.class
        Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
        // 4、通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
        Hello iHello1 = (Hello) constructor.newInstance(new MyInvocationHandler(new HelloImpl()));
        // 5、通过代理对象调用目标方法
        iHello1.sayHello();

        // ==========================第二种=============================
        /**
         * Proxy类中还有个将2~4步骤封装好的简便方法来创建动态代理对象,
         *其方法签名为:newProxyInstance(ClassLoader loader,Class[] instance, InvocationHandler h)
         */
//        Hello iHello2 = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), // 加载接口的类加载器
//            new Class[]{Hello.class}, // 一组接口
//            new MyInvocationHandler(new HelloImpl())); // 自定义的InvocationHandler
//        iHello2.sayHello();
    }

}

interface Hello {

    void sayHello();
}

class HelloImpl implements Hello {

    @Override
    public void sayHello() {
        System.out.println("hello");
    }
}

/**
 * 拦截器
 */
class MyInvocationHandler implements InvocationHandler {

    /**
     * 目标对象
     */
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("------插入前置通知代码-------------");
        // 执行相应的目标方法
        Object rs = method.invoke(target, args);
        System.out.println("------插入后置处理代码-------------");
        return rs;
    }
}

        要求代理类必须实现一个接口。通过反射机制生成一个代理类,该类继承Proxy类实现需要被代理的接口,

        通过调用invokcationHandler中的invoke方法实现对方法的增强。

        下图所示是源码调用流程图,可以参考源码对比流程图。

jdk动态代理和cglib动态代理源码解析_第1张图片

        分析生成的class文件,通过反编译(小妙招:直接将生成的class文件拖进idea中查看)可以发现,生成的代理类继承了Proxy并且实现了待代理的接口,通过调用invoke方法实现代理。

jdk动态代理和cglib动态代理源码解析_第2张图片

jdk动态代理和cglib动态代理源码解析_第3张图片

CGLIB代理

        测试代码

public class CglibProxyMainTest {

    public static void main(String[] args) {
        //该设置用于输出cglib动态代理产生的类
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\cglibProxyClass");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Car.class);
        enhancer.setCallback((MethodInterceptor) (obj, method, args1, methodProxy) -> {
            if("sayHello".equals(method.getName())){
                System.out.println("before");
                Object res = methodProxy.invokeSuper(obj, args1);
                System.out.println("after");
                return res;
            } else {
                Object res = methodProxy.invokeSuper(obj, args1);
                return res;
            }
        });
        Car car = (Car) enhancer.create();

//        car.print();
        car.sayHello();
    }

    static class Car {

//        void print() {
//            System.out.println("I am a car");
//        }

        void sayHello() {
            System.out.println("hello");
        }
    }

}

        利用了ASM操作字节码的框架,修改原本类的字节码,生成新的子类。该类继承原来的类。

        调用方法时,如果代理类的某个方法进行了增强。通过MethodInterceptor拦截器对方法进行增强。通过分析该代理类的class文件,可以发现,会先调用MethodInterceptor中增强的方法,然后再通过super.method()调用父类的原始方法,达到增强方法,代理的目的。

jdk动态代理和cglib动态代理源码解析_第4张图片

jdk动态代理和cglib动态代理的区别

1.jdk动态代理只能代理实现了接口的类,cglib则没有这个限制

2.jdk动态代理使用反射+实现invocationHandler拦截器的invoke方法,生成新的代理类实现

3.cglib利用asm框架生成一个新的代理类,该类继承自原来的类,调用方法实际是调用父类的方法。cglib代理逻辑通过实现MethodInterceptor接口,重写intercept方法实现

4.jdk1.6之前生成字节码的方式要优于反射,但是后面jdk优化之后区别就不大了

你可能感兴趣的:(jdk动态代理,cglib动态代理)