动态代理(如下称代理),利用Java的反射技术(Java Reflection),在运行时建立一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象)html
(Using Java Reflection to create dynamic implementations of interfaces at runtime)。java
代理的是对象是接口(Interfaces),不是类(Class),更不是抽象类。git
解决特定问题:一个接口的实如今编译时没法知道,须要在运行时才能实现github
实现某些设计模式:适配器(Adapter)或修饰器(Decorator)编程
面向切面编程:如AOP in Spring.设计模式
利用Java的Proxy类,调用Proxy.newProxyInstance(),api
而Proxy.newProxyInstance()方法有三个参数:数组
1. 类加载器(Class Loader);缓存
2. 须要实现的接口数组;oracle
3. InvocationHandler接口,全部动态代理类的方法调用,都会交由InvocationHandler接口实现类里的invoke()方法去处理。这是动态代理的要义所在。
下面是官方文档解释:
ublic static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler. This method is equivalent to:
Proxy.getProxyClass(loader, interfaces). getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });
Proxy.newProxyInstance
throws IllegalArgumentException
for the same reasons that Proxy.getProxyClass
does.
Parameters:
loader
- the class loader to define the proxy class
interfaces
- the list of interfaces for the proxy class to implement
h
- the invocation handler to dispatch method invocations to
Returns:
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
Throws:
IllegalArgumentException
- if any of the restrictions on the parameters that may be passed to getProxyClass
are violated
NullPointerException
- if the interfaces
array argument or any of its elements are null
, or if the invocation handler, h
, is null
接口里有一个invoke()方法。基本的作法是,建立一个类,实现这个方法,利用反射在invoke()方法里实现需求:
public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //do something "dynamic" } }
invoke()方法也一样有三个参数:
1. 动态代理类的引用,一般状况下不须要它。但可使用getClass()方法,获得proxy的Class类从而取得实例的类信息,如方法列表,annotation等。
2. 方法对象的引用,表明被动态代理类调用的方法。从中可获得方法名,参数类型,返回类型等等。
3. args对象数组,表明被调用方法的参数。注意基本类型(int,long)会被装箱成对象类型(Interger, Long)。
//interface public interface DynamicQuiz { void run(); } //do something public class DynamicProxyTest implements DynamicQuiz { @Override public void run() { System.out.println("this is a dynmic quiz"); } } //proxy process class DynamicProxy implements InvocationHandler { DynamicQuiz dynamicQuiz; DynamicProxy() { } DynamicQuiz bind(DynamicQuiz dynamicQuiz) { this.dynamicQuiz = dynamicQuiz; return (DynamicQuiz) Proxy.newProxyInstance(dynamicQuiz.getClass().getClassLoader(), dynamicQuiz.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("welcome"); Object result = method.invoke(dynamicQuiz, args); System.out.println("see you agin"); return result; } } //main public class Main { public static void main(String[] args) { DynamicQuiz dynamicQuiz = new DynamicProxyTest(); DynamicQuiz quizeResult = new DynamicProxy().bind(dynamicQuiz); quizeResult.run(); } }
从上面的代码能够看出,对DynamicQuiz接口的调用,会交由Proxy的invoke方法处理,并在不改变run()的源代码下,新增了动态的逻辑(before running/after running),这正式AOP所作的。
深刻讲,Proxy.newInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)作了如下几件事.
(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)建立代理类$Proxy.
$Proxy0类实现了interfaces的接口,并继承了Proxy类.
(2)实例化$Proxy0并在构造方法中把BusinessHandler传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值.
1.接口的run()会触发invoke(), 因此在proxy里面切不可将invoke()替换成(DynamicQuiz)poxy.run(),不然就形成死循环,形成栈溢出。
2.跟踪源码能够看到,程序进行了验证、优化、缓存、同步、生成字节码、显示类加载等操做,前面的步骤并非咱们关注的重点,而最后它调用了sun.misc.ProxyGenerator.generateProxyClass()方法完成生成字节码的动做,这个方法能够在运行时产生一个描述代理类的字节码byte[]数组。若是想看这个运行时产生的代理类中的内容,能够在main方法加以下这句代码:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
运行会生成一个名为"$Proxy).class"的代理class文件,反编译以后就能看见内容。
代码地址:https://github.com/wangtao1/dynamic
参考:
深刻理解java虚拟机第9章节
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
http://www.cnblogs.com/techyc/p/3455950.html