Java设计模式
动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的.java源文件。
动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
动态代理的实现方式常用的有两种:使用JDK代理代理,与通过CGLIB动态代理。
jdk动态代理是基于Java的反射机制实现的。使用jdk中接口和类实现代理对象的动态创建。
Jdk的动态要求目标对象必须实现接口,这是java设计上的要求。
从jdk1.3以来,java语言通过java.lang.reflect包提供三个类支持代理模式Proxy, Method和InovcationHandler。
⒈ InvocationHandler接口
InvocationHandler接口叫做调用处理器,负责完调用目标方法,并增强功能。
通过代理对象执行目标接口中的方法,会把方法的调用分派给调用处理器(InvocationHandler)的实现类,执行实现类中的invoke()方法,我们需要把功能代理写在invoke()方法中 。
接口中只有一个方法:
在invoke方法中可以截取对目标方法的调用。在这里进行功能增强。Java的动态代理是建立在反射机制之上的。
实现了InvocationHandler接口的类用于加强目标类的主业务逻辑。这个接口中有一个方法invoke(),具体加强的代码逻辑就是定义在该方法中的。通过代理对象执行接口中的方法时,会自动调用invoke()方法。
invoke()方法的介绍如下:
public Object invoke ( Object proxy, Method method, Object[] args)
proxy:代表生成的代理对象
method:代表目标方法
args:代表目标方法的参数
第一个参数proxy是jdk在运行时赋值的,在方法中直接使用,第二个参数后面介绍,第三个参数是方法执行的参数, 这三个参数都是jdk运行时赋值的,无需程序员给出。
⒉Method 类
invoke()方法的第二个参数为Method类对象,该类有一个方法也叫invoke(),可以调用目标方法。这两个invoke()方法,虽然同名,但无关。
public Object invoke ( Object obj, Object... args)
obj:表示目标对象
args:表示目标方法参数,就是其上一层invoke方法的第三个参数
该方法的作用是:调用执行obj对象所属类的方法,这个方法由其调用者Method对象确定。
在代码中,一般的写法为method.invoke(target, args);其中,method为上一层invoke方法的第二个参数。这样,即可调用了目标类的目标方法。
⒊Proxy类
通过JDK的java.lang.reflect.Proxy类实现动态代理,会使用其静态方法newProxyInstance(),依据目标对象、业务接口及调用处理器三者,自动生成一个动态代理对象。
public static newProxyInstance ( ClassLoader loader, Class<?>[] interfaces,
InvocationHandler handler)
loader:目标类的类加载器,通过目标对象的反射可获取
interfaces:目标类实现的接口数组,通过目标对象的反射可获取
handler:调用处理器。
jdk动态代理实现
jdk动态代理是代理模式的一种实现方式,其只能代理接口。
实现步骤:
① 新建一个接口,作为目标接口
② 为接口创建一个实现类,是目标类
③ 创建类实现java.lang.reflect.InvocationHandler接口,调用目标方法并增加其他功能代码
④ 创建动态代理对象,使用Proxy.newProxyInstance()方法,并把返回值强制转为接口类型。
idea创建java project
工程名称:ch02-dynamicproxy
⒈定义目标接口
⒉定义目标接口实现类
⒊定义调用处理程序
调用处理程序是实现了InvocationHandler的类,在invoke方法中增加业务功能。还需要创建有参构造,参数是目标对象。为的是完成对目标对象的方法调用。
⒋创建动态代理对象
执行流程:
类图:
CGLIB(Code Generation Library)是一个开源项目。是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP。
使用JDK的Proxy实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。
但对于无接口的类,要为其创建动态代理,就要使用CGLIB来实现。CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以,使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final的类。
cglib经常被应用在框架中,例如Spring ,Hibernate等。Cglib的代理效率高于Jdk。对于cglib一般的开发中并不使用。做了一个了解就可以。