- 逻辑流程
- Proxy.newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler invocationHandler)
调用该方法之后,会产生一个$Proxy0类,该类继承Proxy,实现interfaces中的接口,由classLoader加载到JVM中。在调用interfaces中的方法时,$Proxy0的实例会交给invocationHandler处理。
- InvocationHandler接口
interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;}就一个方法,proxy是调用该方法的代理实例,method是proxy调用的接口中的方法,args是传递的参数。
- 例子
public interface Animal { public void eat(); } class Cat implements Animal { @Override public void eat() { System.out.println("猫在吃"); } }
Animal接口以及一个实现了Animal接口的类Cat。
public class CatInvocationHandler implements InvocationHandler { private Animal animal; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(proxy.getClass().getName()); if (method.getName().equals("eat")) { if (animal == null) { System.out.println("代理在吃"); } else { method.invoke(animal, args); } } return null; } public void setAnimal(Animal animal) { this.animal = animal; } }
CatInvocationHandler实现了InvocationHandler接口。
public class Test { public static void main(String[] args) { Class[] interfaces = {Animal.class}; CatInvocationHandler catInvocationHandler = new CatInvocationHandler(); Animal proxy = (Animal) Proxy.newProxyInstance(Test.class.getClassLoader(), interfaces, catInvocationHandler); proxy.eat(); Animal cat = new Cat(); catInvocationHandler.setAnimal(cat); proxy.eat(); } }
主函数。
proxy实例由Test的类加载器加载,实现了Animal接口,绑定CatInvocationHandler的一个实例。第一次调用proxy.eat()时,由于catInvocationHandler中animal对象为null,因此输出“代理在吃”。@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(proxy.getClass().getName()); if (method.getName().equals("eat")) { if (animal == null) { System.out.println("代理在吃"); } else { method.invoke(animal, args); } } return null; }
之后会catInvocationHandler设置了一个实现了Animal接口的Cat实例,所以第二次调用proxy.eat()时,会调用该实例的eat()方法。
最终输出:com.sun.proxy.$Proxy0 代理在吃 com.sun.proxy.$Proxy0 猫在吃
- 代理类生成
- interfaces处理
Proxy.newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler invocationHandler)会先处理interfaces。
具体流程:1.将interfaces存入一个HashSet中去除重复的接口;2.判断cache是否存在实现了这些interfaces的Proxy子类,存在就不用生成一个新的Proxy子类,不存在就生成。
- 代理类生成
调用ProxyGenerator.generateProxyClass()方法生成一个指定名字和接口的类。
ProxyGenerator.generateProxyClass()方法首先调用generateClassFile()把字段和方法写好,然后再一并写入磁盘文件中。
- 总结
Java的动态代理在生成代理类($Proxy0)时,需要提供接口的集合,新生成的代理类会声明为实现了这些接口。
在对代理实例调用接口中的方法时,它会调用绑定的InvocationHandler中的invoke方法,此时我们可以进行一些自己想要做的操作:例如,权限管理,增加方法等。