大家都知道Spring中AOP是通过Java动态代理实现的,今天就来简单学习下demo。
Java动态代理主要有两个核心类,InvocationHandler和Proxy。
1/** 2 * {@code InvocationHandler} is the interface implemented by 3 * the <i>invocation handler</i> of a proxy instance. 4 * 5 * <p>Each proxy instance has an associated invocation handler. 6 * When a method is invoked on a proxy instance, the method 7 * invocation is encoded and dispatched to the {@code invoke} 8 * method of its invocation handler. 9 * 10 * @author Peter Jones 11 * @see Proxy 12 * @since 1.3 13 */ 14public interface InvocationHandler
所有的Handler类要实现InvocationHandler接口,并关联到Proxy实例上,最后会分发到InvocationHandler的invoke方法上。
1/** 2 * {@code Proxy} provides static methods for creating dynamic proxy 3 * classes and instances, and it is also the superclass of all 4 * dynamic proxy classes created by those methods. 5 * 6 * <p>To create a proxy for some interface {@code Foo}: 7 * <pre> 8 * InvocationHandler handler = new MyInvocationHandler(...); 9 * Class proxyClass = Proxy.getProxyClass( 10 * Foo.class.getClassLoader(), new Class[] { Foo.class }); 11 * Foo f = (Foo) proxyClass. 12 * getConstructor(new Class[] { InvocationHandler.class }). 13 * newInstance(new Object[] { handler }); 14 * </pre> 15 * or more simply: 16 * <pre> 17 * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), 18 * new Class[] { Foo.class }, 19 * handler); 20 * </pre> 21 * 22 **************************** 23 */ 24public class Proxy implements java.io.Serializable
通过该类的静态方法创建要动态代理的类。
下面看下demo
1. 先创建一个接口
1public interface TargetInterface { 2 int targetMethod(int num); 3}
2. 实例化该接口
1public class TargetClass implements TargetInterface { 2 @Override 3 public int targetMethod(int number) { 4 System.out.println("调用目标类的方法targetMethod..."); 5 return number; 6 } 7}
3. 创建代理处理类,InvocationHandler子类
1public class ProxyHandler implements InvocationHandler { 2 Object concreteClass; 3 public ProxyHandler(Object concreteClass) { 4 this.concreteClass = concreteClass; 5 } 6 @Override 7 public Object invoke(Object proxy, Method method, Object[] args) 8 throws Throwable { 9 System.out.println("proxy:"+proxy.getClass().getName()); 10 System.out.println("method:"+method.getName()); 11 System.out.println("args:"+args[0].getClass().getName()); 12 13 System.out.println("Before invoke method..."); 14 Object object = method.invoke(concreteClass, args); 15 System.out.println("After invoke method..."); 16 return object; 17 } 18}
proxy: 指代我们所代理的那个真实对象 method: 指代的是我们所要调用真实对象的某个方法的Method对象 args: 指代的是调用真实对象某个方法时接受的参数
1public class Example { 2 public static void main(String[] args) { 3 TargetClass cc = new TargetClass(); 4 InvocationHandler ih = new ProxyHandler(cc); 5 TargetInterface tf = (TargetInterface) Proxy.newProxyInstance(cc.getClass().getClassLoader(), cc.getClass().getInterfaces(), ih); 6 7 int i = tf.targetMethod(5); 8 } 9} 10 11public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 12 13loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载 14interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了 15h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
注意:通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
动态代理有个缺陷,就是创建时需要参数interfaces,即被代理的类,需要实现该接口。