代理机制的实现已经有现成的设计模式支持,叫代理模式(Proxy Pattern)。在代理模式中,通常涉及4种角色。
1.接口:该接口是对被访问者或被访问资源的抽象。在严格的设计模式中,这样的抽象接口是必须的,但某些场景下不使 用类似的统一抽象接口也是可以的。
2.具体实现类:就是具体实现类嘛。
3.代理实现类:该类持有一个接口类的具体实例。
4.客户端:代表访问者的抽象角色,他将会访问接口类的对象或资源。
对于动态代理的实现主要由一个类和一个接口组成,即java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。具体实现方法这里就不过多赘述了。不太明白的话参考一下Javadoc。Java Reflection In Action(Manning, 2005)一书对Java的Reflection机制进行了详尽的阐述,其中有一章专门讲解了动态代理机制,不妨一读。
对于Spring AOP来说,如果发现代理目标对象实现了相应的接口,则采用动态代理机制为其生成代理对象实例。而如果代理目标对象没有实现任何接口,Spring AOP会尝试使用一个称为CGLIB(Code Generation Library)的开源的动态字节码生成类库,为目标生成动态的代理对象实例。其原理是,我们可以对目标对象进行继承扩展,为其生成相应的子类,而子类可以通过覆写来扩展父类的行为,只要将横切逻辑的实现放到子类中,然后让系统使用扩展后的目标对象的子类,就可以达到与代理模式相同的效果了。但是,使用继承的方式来扩展对象定义,也不能像静态代理模式那样,为每个不同的类型的目标对象都单独创建相应的子类。所以,我们要使用CGLIB在系统运行期间动态的为目标对象生成相应的扩展子类。
为了演示CGLIB的使用,我们定义的目标类如下所示:
public class Requestable{
public void request(){
System.out.println("rq in Requestable without implement any interface");
}
}
要对上面的类进行扩展,首先需要实现一个net.sf.cglib.proxy.Callback。不过更多的时候,我们会直接使用net.sf.cglib.proxy.MethodInterceptor接口,因为它扩展了Callback接口。下面我们实现Callback。
public class RequestCtrlCallback implements MethodInterceptor {
private static final Log logger = LogFactory.getLog(RequestCtrlCallback.class);
public Object interceptor(Object obj, Method method, Object[] args, MethodProxy proxy) throw throwable {
System.out.println("this is before " + method);
proxy.invokeSuper(obj, args);
System.out.println("this is before " + method);
return null;
}
}
这样我们就实现了对request()方法请求进行访问控制的逻辑。现在我们要通过CGLIB的Enhancer为目标对象生成一个子类,并将RequestCtrlCallback中的横切逻辑附加到该子类中,代码如下:
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Requestable.class);
enhancer.setCallback(new RequestCtrlCallback());
Requestable proxy = (Requestable) enhancer.create();
proxy.request();
通过为Enhancer指定需要生成的子类对应的父类,以及实现Callback,Enhancer最终为我们生成了需要的代理对象实例。
另外,使用CGLIB对象进行扩展的唯一限制就是无法对final方法进行覆写。