java.lang.reflect包下提供了一个Proxy类和InvocationHandler接口,用于生成动态代理类和动态代理对象。
一、使用Proxy、InvocationHandler创建动态代理
这里要注意,在java.net包下也有一个Proxy类,不过这个类是用于设置代理服务器的,莫混淆。。
Proxy提供了如下两个方法创建动态代理类和动态代理实例:
实际上即使采用第一种方法创建动态代理类,如果程序需要通过该代理类来创建对象,依然需要传入一个InvocationHandler对象,也就是说,系统生成的每个代理对象都有一个与之关联的InvocationHandler对象。
public class ProxyTest { public static void main(String[] args){ MyInvocationHandler invocationHandler = new MyInvocationHandler(); invocationHandler.setTarget(new Hero()); Person hero= (Person) Proxy.newProxyInstance(Hero.class.getClassLoader(),Hero.class.getInterfaces(),invocationHandler); // hero.fight(); // hero.laugh(); hero.sayHello("Tom"); hero.work(); } } interface Person{ void work(); void sayHello(String name); } interface FightAble{ void fight(); } class Hero implements Person,FightAble{ @Override public void fight() { System.out.println("hero fight"); } @Override public void work() { System.out.println("hero work"); } @Override public void sayHello(String name) { System.out.println("hello "+name); } public void laugh(){ System.out.println("hero laugh"); } } class MyInvocationHandler implements InvocationHandler{ private Object target; public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-------正在执行的方法:"+method); if(args != null){ System.out.println("下面是执行该方法传入的实参:"); for (Object val : args){ System.out.println(val); } } else { System.out.println("调用的方法没有实参"); method.invoke(target); } return null; } }
注意,java动态代理产生的对象一定要用接口引用指向之,这是由于java的动态代理实际上时使用传入的接口类型创建了新的类,所以在上面代码中不可以用Hero类型指向创建的对象,只能由Person或FightAble类型指向之。看源码就可以发现这一点。
二、AOP代理
AOP(面向切面编程),的一种实现方式就是使用java动态代理。
在上面的代码中实际上已经实现了AOP,对所有代理对象的无实参方法,在执行方法body之前都先执行System.out.println("调用的方法没有实参");只不过这些代码写在了InvocationHandler中,而像Spring之类的框架会把这一部分代码用设计模式解耦出来,但本质上还是这样子的原理。