Java动态代理简易说明

先看一下java.lang.reflect.Proxy的实例化方法声明

/**
     ...
     * @param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
  ...
*/
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)

显然,实例化一个Proxy对象需要传三个参数:

  • ClassLoader 类加载器
  • Class[] 类型数组,这里只能传接口数组,决定了生成的代理对象可以转换成的类型
  • InvocationHandler 实际代理处理类

然后我们再看InvocationHandler的接口方法

/**
     ...
     * @param   proxy the proxy instance that the method was invoked on
     *
     * @param   method the {@code Method} instance corresponding to
     * the interface method invoked on the proxy instance.  The declaring
     * class of the {@code Method} object will be the interface that
     * the method was declared in, which may be a superinterface of the
     * proxy interface that the proxy class inherits the method through.
     ...
     */
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

显然,invoke方法有三个参数:

  • Object proxy 代理实例,这里实际上是代理实例把自己作为参数传递了,只能用作类型判断,否则会产生循环嵌套调用,导致栈溢出
  • Method method 方法实例,这里需要了解反射的知识,其是proxy调用的任何方法的方法实例
  • Object[] args 这个是proxy调用方法时传递的实例

由此看出,仅仅实现了InvocationHandler的类没有任何用处,因为Method的调用需要一个实现该方法的类实例

/**
     ...
     * @param obj  the object the underlying method is invoked from
     * @param args the arguments used for the method call
     * @return the result of dispatching the method represented by
     * this object on {@code obj} with parameters
     ...
     */
    @CallerSensitive
    public Object invoke(Object obj, Object... args)

好了,方法基本说完了,下面是重点中的重点:

代理实例方法(任何方法)的调用,都是通过InvocationinHandlerInvoke()调用的,InvocationinHandler处理的粒度是方法。

下面是例子

首先是要被代理的接口和接口的实现

public interface IMethodInvoke {
	public void psvm();
}
public class MethodInvoke implements IMethodInvoke{
	public MethodInvoke() {
	}
	public void psvm() {
		System.out.println("psvm方法调用!");
	}
	
}

然后是InvocationinHandler

public class MessageHandler implements InvocationHandler{
	private Object cli;
	public MessageHandler(Object cli) {
		this.cli=cli;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("发送信息");
		return  method.invoke(cli, args);
	}

}

最后是Main

public static void main(String[] args) {
	IMethodInvoke imi = new MethodInvoke();
	InvocationHandler ivh = new MessageHandler(imi);
	IMethodInvoke proxy = (IMethodInvoke)Proxy.newProxyInstance(imi.getClass().getClassLoader(), imi.getClass().getInterfaces(), ivh);
	User user = new User();
	Class[] users = {User.class}; 
	User userProxy = (User)Proxy.newProxyInstance(imi.getClass().getClassLoader(), users, ivh);
	proxy.psvm();//作为ivh的Invoke方法的参数中的Method,和Object[],Proxy则是代理实例本身
    System.out.println("Out"+proxy.toString());
}

Enjoy.

你可能感兴趣的:(Java)