代理模式中,Proxy角色在执行代理业务的时候,无非是在调用真正业务前后做一些额外的业务。
由上图可以看出,代理类处理的逻辑很简单:在调用某个方法前后做一些额外的业务。换一个思路就是:在Proxy代理对象调用/触发(invoke)真实类的方法前后做一些额外的业务。那么,为了构造出具有通用性和简单性、侵入性低的代理类,可以将所有的触发真实角色方法的动作交给一个触发的管理器统一管理真实类所有的动作/方法的触发。这个管理器就是InvocationHandler。
InvocationHandler作用:
- 在静态代理中,代理Proxy中的方法,都指定了调用特定的realSubject(真实类)中的对应的方法。(代理类与真实类方法一一对应)。在静态代理模式下,Proxy所做的事情,无非是调用不同的方法的时候,触发调用realSubject对应的方法;更抽象点看,Proxy所做的事情,在Java中方法(Method)也是作为一个对象来看待的。
- 动态代理的基本模式就是将自己的方法的实现交给InvocationHandler角色,外界对Proxy角色的每一个方法调用,Proxy角色都会交给InvocationHandler来处理,而InvocationHandler则调用具体对象角色(真实类)的方法。
在这种模式下,代理Proxy和RealSubject应该实现相同的功能(方法,public方法)
而在面向对象的编程之中,想要约定两个类可以实现相同的功能,有两种方式:
- 定义几个功能接口,然后让Proxy和RealSubject来实现这个接口。
- 继承。因为如果Proxy 继承自RealSubject,这样Proxy则拥有了RealSubject的功能,Proxy还可以通过重写RealSubject中的方法,来实现多态。
其中JDK中提供的创建动态代理的机制,是以a这种思路设计的,而cglib则是以b思路设计的。
JDK的动态代理创建机制,通过接口(生成代理对象字节码的依据是接口内方法、通过反射实现)
比如现在想为RealSubject这个类创建一个动态代理对象,JDK主要会做以下工作:
- 获取 RealSubject上的所有接口列表;
- 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX ;
- 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
- 将对应的字节码转换为对应的class对象;
- 创建InvocationHandler实例handler,用来处理Proxy所有方法调用;
- Proxy的class对象以创建的handler对象为参数,实例化一个proxy对象
JDK通过 java.lang.reflect.Proxy包来支持动态代理,一般情况下,我们使用下面的newProxyInstance方法
//返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);
而对于InvocationHandler,我们需要实现下列的invoke方法:
在调用代理对象中的每一个方法时,在代码内部,都是直接调用了InvocationHandler(h)的invoke方法,而invoke方法根据代理类传递给自己的method参数来区分是什么方法。
//在代理实例上处理方法调用并返回结果。
invoke(Object proxy,Method method,Object[] args);
cglib生成动态代理类的机制,通过类继承(生成代理对象字节码的依据是继承、通过ASM实现)
JDK中提供的生成动态代理类的机制有个鲜明的特点是: 某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法。极端的情况是:如果某个类没有实现接口,那么这个类就不能同JDK产生动态代理了!幸好我们有cglib。“CGLIB(Code Generation Library),是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
cglib 创建某个类A的动态代理类的模式是:
- 查找类上的所有非final 的public类型的方法定义;
- 将这些方法的定义转换成字节码;
- 将组成的字节码转换成相应的代理的class对象;
-
实现 MethodInterceptor接口,用来处理对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)
package samples;
/**
* 程序猿类
*/
public class Programmer {
public void code()
{
System.out.println("I'm a Programmer,Just Coding.....");
}
}
package samples;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/*
* 实现了方法拦截器接口
*/
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("**** I am a hacker,Let's see what the poor programmer is doing Now...");
proxy.invokeSuper(obj, args);
System.out.println("**** Oh,what a poor programmer.....");
return null;
}
}
package samples;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
Programmer progammer = new Programmer();
MyMethodInterceptor myMethodInterceptor= new MyMethodInterceptor ();
//cglib 中加强器,用来创建动态代理
Enhancer enhancer = new Enhancer();
//设置要创建动态代理的类
enhancer.setSuperclass(progammer.getClass());
// 设置回调,这里相当于是对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实行intercept()方法进行拦截
enhancer.setCallback(myMethodInterceptor);
Programmer proxy =(Programmer)enhancer.create();
proxy.code();
}
}
程序执行结果: