Java代理(Proxy)

北城以北 提交于 2019-12-04 06:43:46

利用代理可以在运行时创建一个实现了一组给定接口的新的实现类。

假设有一个表示接口的Class对象,它的确切类型在编译时无法知道,要想在运行时构造一个实现了该接口的类,就需要使用newInstance方法或者反射找到构造器,很复杂,很麻烦。那么代理可以解决这个问题!

代理需要提供一个实现了InvocationHandler接口的调用处理器,在这个接口中只定义了一个方法:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
  • 这样无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的参数,调用处理器必须在invoke方法中给出处理调用的方式。

创建代理对象

创建一个代理对象,需要使用Proxy类的newProxyInstance方法:

public class Proxy implements java.io.Serializable {
  	// more code ...
	public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
			throws IllegalArgumentException
	// more code ...
}
  • 这个方法中包含了三个参数:
    1. ClassLoader:指定一个类加载器,null表示使用默认的加载器;
    2. Class<?>[]:表示需要实现的接口数组;
    3. InvocationHandler:一个调用处理器。

一个例子🌰

这里举一个程序员写代码,然后公司作为代理的例子:

  1. 首先创建一个Programmer接口:
public interface Programmer {
    void writeCode(String code);
    void postProduct();
}
  1. 写一个Programmer实现类
public class ProgrammerImpl implements Programmer {
    @Override
    public void writeCode(String code) {
        System.out.println("写代码。。。。。。。" + code);
    }
	
    @Override
    public void postProduct() {
        System.out.println("提交产品。。。。。。。");
    }
}
  1. 写一个调用处理器
public class Handler implements InvocationHandler {

    private Object target;

    public Handler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我代表:" + target.getClass().getName());
        System.out.println("要执行的行为是:" + method.getName());
        System.out.println("传递的参数包括:");
        if (args != null && args.length > 0) {
            for (Object obj : args
            ) {
                System.out.println(obj);
            }
        }
        System.out.println("开始执行方法:");
        method.invoke(target, args);
        System.out.println("方法执行完毕");
        return null;
    }
}
  1. 代理主类测试
public class ProxyMain {

    public static void main(String[] args) {

        Programmer programmer = new ProgrammerImpl();

        Handler handler = new Handler(programmer);

        Programmer programmerProxy = (Programmer) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Programmer.class}, handler);

        programmerProxy.writeCode("java");

        programmerProxy.postProduct();

    }
}
  1. 运行结果
我代表:com.ytuan.ProgrammerImpl
要执行的行为是:writeCode
传递的参数包括:
java
开始执行方法:
写代码。。。。。。。java
方法执行完毕
我代表:com.ytuan.ProgrammerImpl
要执行的行为是:postProduct
传递的参数包括:
开始执行方法:
提交产品。。。。。。。
方法执行完毕

代理类的特性

  • 代理类都是在运行过程中创建的,一旦创建后,和常规类一样
  • 所有的代理类都扩展于Proxy类
  • 一个代理类只有一个实例域——InvocationHandler的实现类,InvocationHandler的invoke方法包含了处理逻辑的代码。
  • 对于特定的类加载器和一组接口来说,只有一个代理类;即如果多次使用相同的类加载器和同一组接口调用newInstance方法,那么生成的代理类是一致的。
  • 代理类一定public和final修饰的
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!