Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发。我们知道一个静态代理是通过代理主题角色(Proxy)和具体主题角色(Real Subject)共同实现抽象主题角色(Subject)的逻辑的,只是代理主题角色把相关的执行逻辑委托给了具体主题角色而已,一个简单的静态代理如下所示:
//抽象主题角色
interface Subject{
//定义一个方法
public void request();
}
//具体主题角色
class RealSubject implements Subject{
//实现方法
public void request(){
//业务逻辑处理
}
}
//代理主题角色
class Proxy implements Subject{
//要代理哪个实现类
private Subject subject=null;
//默认被代理者
public Proxy(){
subject=new RealSubject();
}
//通过构造函数传递被代理者
public Proxy(Subject_subject){
subject=_subject;
}
//实现接口中定义的方法
public void request(){
before();
subject.request();
after();
}
//预处理
private void before(){
//do something
}
//善后处理
private void after(){
//do something
}
}
这是一个简单的静态代理。Java还提供了java.lang.reflect.Proxy用于实现动态代理:只要提供一个抽象主题角色和具体主题角色,就可以动态实现其逻辑的,其示例代码如下:
//抽象主题角色
interface Subject{
//定义一个方法
public void request();
}
//具体主题角色
class RealSubject implements Subject{
//实现方法
public void request(){
//业务逻辑处理
}
}
class SubjectHandler implements InvocationHandler{
//被代理的对象
private Subject subject;
public SubjectHandler(Subject_subject){
subject=_subject;
}
//委托处理方法
public Object invoke(Object proxy, Method method, Objectargs)
throws Throwable{
//预处理
System.out.println("预处理");
//直接调用被代理类的方法
Object obj=method.invoke(subject, args);
//后处理
System.out.println("后处理");
return obj;
}
}
注意看,这里没有了代理主题角色,取而代之的是SubjectHandler作为主要的逻辑委托处理,其中invoke方法是接口InvocationHandler定义必须实现的,它完成了对真实方法的调用。
我们来详细了解一下InvocationHanlder接口,动态代理是根据被代理的接口生成所有方法的,也就是说给定一个(或多个)接口,动态代理会宣称“我已经实现该接口下的所有方法了”,那各位读者想想看,动态代理怎么才能实现代理接口中的方法呢?在默认情况下所有方法的返回值都是空的,是的,虽然代理已经实现了它,但是没有任何的逻辑含义,那怎么办?好办,通过InvocationHandler接口的实现类来实现,所有方法都是由该Handler进行处理的,即所有被代理的方法都由InvocationHandler接管实际的处理任务。
我们接着来看动态代理的场景类,代码如下:
public static void main(Stringargs){
//具体主题角色,也就是被代理类
Subject subject=new RealSubject();
//代理实例的处理Handler
InvocationHandler handler=new SubjectHandler(subject);
//当前加载器
ClassLoader cl=subject.getClass().getClassLoader();
//动态代理
Subject proxy=(Subject)Proxy.newProxyInstance(cl, subject.getClass().
getInterfaces(),handler);
//执行具体主题角色方法
proxy.request();
}
此时就实现了不用显式创建代理类即实现代理的功能,例如可以在被代理角色执行前进行权限判断,或者执行后进行数据校验。
动态代理很容易实现通用的代理类,只要在InvocationHandler的invoke方法中读取持久化数据即可实现,而且还能实现动态切入的效果,这也是AOP(Aspect Oriented Programming)编程理念。