动态代理

使用反射可以在运行时创建接口的动态实现(是说运行时实现接口?),java.lang.reflect.Proxy类提供了创建动态实现的功能。我们把运行时创建接口的动态实现称为动态代理。应用有例如数据库连接和事务管理、用于单元测试的动态模拟对象以及其他类似aop的方法拦截等。

创建动态代理
调用java.lang.reflect.Proxy类的newProxyInstance()方法就可以创见动态代理,newProxyInstance()方法有三个参数: 1、用于“加载”动态代理类的类加载器。2、要实现的接口数组。 3、将代理上的所有方法调用转发到InvocationHandler的对象。

InvocationHandler handler = new MyInvocationHandler();
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                            MyInterface.class.getClassLoader(),
                            new Class[] { MyInterface.class },
                            handler);

运行上面代码后,proxy变量包含了MyInterface接口的动态实现。对代理的所有调用都将由到实现了InvocationHandler接口的handler 对象来处理。 InvocationHandler代码:

public interface InvocationHandler{
  Object invoke(Object proxy, Method method, Object[] args)	//invoke方法是对函数的调用
         throws Throwable;
}

实现InvocationHandler接口的类:
Object proxy参数,实现接口的动态代理对象。通常不需要这个对象(是因为本来就是通过proxy来调用newProxyInstance,从而调用了handler,从而调用了invoke,所以这种情况下这个proxy已经确定了)。
Method method参数,表示在动态代理实现的接口上调用的方法。通过Method对象,可以获取到方法名,参数类型,返回类型等信息。
Object[] args参数,包含调用接口中实现的方法时传递给代理的参数值(是值还是类型?比如说是传入Integer.class还是一个数字1?是数字1)。注意:如果接口中的参数是int、long等基本数据时,这里的args必须使用Integer, Long等包装类型(传入的是类型?不是类型,invoke是直接调用具体函数了,传入的是参数值而非参数类型)。

public class MyInvocationHandler implements InvocationHandler{

  public Object invoke(Object proxy, Method method, Object[] args)
  throws Throwable {
    //do something "dynamic"
  }
}

上面代码中会生成一个MyInterface接口的对象proxy(什么叫接口的对象?是实现了接口的类还是一个接口?似乎是实现了接口的类,因为proxy可以直接调用方法了,由handler处理嘛,或者这就叫做代理对象?),通过proxy对象调用的方法都会由MyInvocationHandler类的invoke方法处理。