动态代理设计模式
通过JDK实现动态代理
如果要实现动态代理,那么你要编写的那个代理类就需要实现一个InvocationHandle接口
java.lang.reflect.InvocationHandler.看到reflect我们就能知道,动态代理肯定是通过反射来实现的了,这个接口中有一个方法:
Object invoke(Object proxy, Method method, Object[] args) :在代理实例上处理方法调用并返回结果。
invoke方法其实是反射里边的一个方法,在这个方法中有三个参数:
Ojbect proxy:表示需要代理的对象
Method method:表示要操作的方法
Object[] args:method方法所需要传入的参数(可能没有为,null.也可能有多个)
如果要想让代理设计真正可用,我们还必须有一个代理类对象产生,这有用到了另一个类:java.lang.reflect.Proxy.我的中文jdk文档对他的描述是:
Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
在这个类下面,我们找到了这样一个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
该方法返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序.方法中有三个参数:
参数:
loader
- 定义代理类的类加载器
interfaces
- 代理类要实现的接口列表
h
- 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
动态代理实现代码:
测试类:
动态代理和静态代理相比较,最大的好处就是接口中声明的所有的方法都被转移到一个集中的方法中去处理,就是invocke()方法.这样在接口中声明的方法比较多的情况下我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
动态代理只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法的返回值是被代理接口的一个实现类。
那么有没有可能我们可以不依赖接口呢?这时候就需要CGLIB实现动态代理了
现在我们把UserService改为不实现任何接口,看看运行结果
运行结果报错:
原因:/**
* 当目标对象为一个类的时候,这个类没有实现任何接口,这时候会报错;
* 因此JDK动态代理类只能对实现了接口的类生成代理,而不能针对类
*/
要解决动态代理目标对象不实现任何接口时候,需要cglib来实现
通过CGLIB实现动态代理
什么是CGLIB动态代理 使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码。
CGLIB动态代理相关代码
CGLIB动态代理与JDK动态区别
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
Spring在选择用JDK还是CGLiB的依据:
(1)当Bean实现接口时,Spring就会用JDK的动态代理
(2)当Bean没有实现接口时,Spring使用CGlib是实现
(3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
本文转载:https://www.cnblogs.com/fingerboy/p/5335328.html