很多框架或工具都是利用代理技术实现的。典型的如spring 的AOP、easymock、单元覆盖率检测工具等。静态代理比较好理解,就是自己写代理类来完成附加的功能,设计模式中专门有个代理模式讲这个。动态代理是指代理实现对象并不是在编译期间生成好的,而是在运行过程中产生的。这样的好处是当被代理的接口方法(注:jdk动态代理只能对接口进行代理)发生变化时,不需要改动代理实现类的代码。以下为示例代码:


假设有个接口:

public interface IDoSomething {
    public void doA();
    //public void doB();
}


一个常规的实现类:

public class DoSomethingImpl implements IDoSomething{
    @Override
    public void doA() {
        System.out.println("I'm working...");
    }
}


如果是静态代理,大概就写成这个样子:(静态代理通常实现和被代理类相同的接口)

public class StaticProxyDoSomething implements IDoSomething{
    private IDoSomething target;
                           
    public StaticProxyDoSomething(IDoSomething target){
        this.target=target;
    }
                           
    public void doA(){
        System.out.println("代理准备");
        target.doA();
        System.out.println("代理完成");
    }
                           
//  public void doB(){
//     
//  }
}

可以看出,当接口方法发生变化,代理类里的方法也要跟着修改


动态代理类写成这样就可以了:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyDoSomething implements InvocationHandler{
    private Object target;
                  
    public ProxyDoSomething(Object target){
        this.target=target;
    }
                  
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
        Object result;
        System.out.println("准备工作...");
        result=method.invoke(target,args);
        System.out.println("代理完成...");
        return result;
    }  
}

   动态代理类需要实现InvocationHandler接口,覆写invoke方法。注意invoke方法中的第一个参数“proxy”容易引起混淆,它是一个隐含实现,对编码来说并没有用到。而执行method.invoke时需要给的是被代理对象。可以看出动态代理类就这么一些内容。未来不论接口再增加、修改了什么,代理类都不需要改写了。而且是执行被代理对象的每种接口方法都会调用这里的invoke,这就为我们提供一个方便的途径来进行“全局控制”,比如记录日志、权限检查什么的。


最后是一个简单的测试类:

import java.lang.reflect.Proxy;
public class TestProxy {
    public static void main(String[] args){
        DoSomethingImpl dsi=new DoSomethingImpl();
            
        IDoSomething proxy=(IDoSomething)Proxy.newProxyInstance(dsi.getClass().getClassLoader(),
                dsi.getClass().getInterfaces(),new ProxyDoSomething(dsi));
            
        proxy.doA();
    }
}