jdk动态代理和cglib动态代理
jdk动态代理
个人的理解,运行期间由JVM根据反射等机制动态的生成代理类
核心API
java.lang.reflect.Proxy
所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
java.lang.reflect.InvocationHandler
这是调用处理器接口,它自定义了一个 invoke 方法,通常在该方法中实现对委托类的访问
java.lang.ClassLoader
这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用
实现一个动态代理
代码实现:点击下载
一个典型的动态代理创建对象过程可分为以下四个步骤:
1. 通过实现InvocationHandler接口创建自己的调用处理器
IvocationHandler handler = new InvocationHandlerImpl(…);
2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
核心问题
1.代理对象是怎么生成的
由Proxy完成, 在内部方法中调用ProxyGenerator类的静态方法generateProxyClass,这里是真正生成代理类class字节码的地方。
2.InvocationHandler的invoke方法是由谁来调用的
生成的代理类ProxySubject继承Proxy类实现Subject接口,实现了Subject的方法,在实现方法中,调用处理器的invoke方法
3.真实实例的方法如何被调用的
InvocationHander的实现类只是通过代理类的构造函数注入后, 实现了对代理类中方法调用的拦截
而invoke方法利用反射调用的是真实对象的的方法(Object result=method.invoke(proxied,args))
总结
jdk动态代理只能代理接口,是因为生成的代理类本身 extends Proxy implement xxxInterface
cglib动态代理
CGLib采用了asm框架的字节码技术,其原理是:
通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑
核心API
net.sf.cglib.proxy.Enhancer – 主要的增强类
net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
net.sf.cglib.proxy.MethodProxy -可以方便的实现对源对象方法的调用
实现一个动态代理
代码实现: 点击下载
核心问题
1.代理对象的生成过程由Enhancer类实现
1、生成代理类Class的二进制字节码;
2、通过Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。
2.如何调用真实实例的方法
通过FastClassInfo维护了委托类和代理类的FastClass,提出下标概念index,通过索引保存方法的引用信息,将原先的反射调用,转化为方法的直接调用
所以当调用methodProxy.invokeSuper
方法时,实际上是调用代理类的CGLIB$add$0
方法,CGLIB$add$0
直接调用了委托类的add方法。
总结
cglib动态代理类,继承了委托类, 采用保存索引的方式调用委托类的方法
Jdk动态代理和cglib动态代理的区别
1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;
祝:
大家生活愉快,工作顺利