静态代理
实现方法:代理对象和目标对象实现同一个接口,在代理对象的构造函数中获取到目标对象实例,在实现接口的方法中在调用目标方法前后,写上增强代码
JDK动态代理
使用JDK API,动态代理利用了JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理
与静态代理的区别:静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件。动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
通过Proxy类创建代理对象,调用方法newInstance(),具体:static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h ),三个参数分别为:<br>
ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的,通过Class.getClassLoader()获取
Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型,通过object.getClass().getInterfaces()或者new Class[]{Object.class}获取
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入,InvocationHandler实例通过实现InvocationHandler接口创建。在方法Object invoke(Object proxy, Method method, Object[] args)中实现代码增强<br>
CGLib代理
CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法啊,这样也可以保证代理类拥有目标类的同名方法
与动态代理的区别
JDK动态代理强制要求实现类必须最少实现一个接口,但是CGLIB则可以要求实现类不用实现任何接口
实现方法
创建拦截器实现MethodInterceptor接口
在拦截器方法方法Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)中实现方法增强,调用 methodProxy.invokeSuper(o, objects);方法调用目标对象的方法<br>
创建Enhancer对象,类似于JDK动态代理的Proxy类,为Enhancer对象设置目标类的字节码文件(目标对象Class),设置回调函数(回调函数就是实现了MethodInterceptor的类实例)
调用Enhancer对象实例的create()方法创建代理对象
JDK动态代理和CGLib动态代理的区别
JDK不需要第三方库支持,CGLib必须依赖于CGLib的类库
JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理;CGLib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
在老版本CGLIB的速度是JDK速度的10倍左右,但是CGLIB启动类比JDK慢8倍左右,但是实际上JDK的速度在版本升级的时候每次都提高很多性能,而CGLIB仍止步不前.
JDK动态代理基于接口;CGLib动态代理基于继承
Spring的AOP如何选择动态代理?
如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,也可以强制使用CGLIB实现AOP
如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换