有两种动态代理来:jdk动态代理和cglib动态代理。
两种方法同时存在,各有优劣。
- jdk动态代理是由Java内部的反射机制来实现的
- cglib动态代理底层则是借助asm来实现的。(asm:是一个JAVA字节码分析、创建和修改的开源应用框架)
- ASM(1)是一个JAVA字节码分析、创建和修改的开源应用框架。它可以动态生成二进制格式的stub类或其他代理类,或者在类被JAVA虚拟机装入内存之前,动态修改类。
在ASM中提供了诸多的API用于对类的内容进行字节码操作的方法。与传统的BCEL和SERL不同,在ASM中提供了更为优雅和灵活的操作字节码的方式。
ASM相当小巧,并且它有更高的执行效率,是BCEL的7倍,SERP的11倍以上(摘自网络,具体没有测试)。目前ASM已被广泛的开源应用架构所使用,
例如:Spring、Hibernate等
总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。。
方法一JDK:
接口:
public interface Subject { public void rent(); public void hello(String str); }
实现类:
public class RealSubject implements Subject { public void rent() { System.out.println("RealSubject rent......"); } public void hello(String str) { System.out.println("hello : "+str); } }
代理类:
public class DynamicProxy implements InvocationHandler { private Object subject; public DynamicProxy(Object subject){ this.subject=subject; } public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { //在代理真实对象之前,我们可以设置自己的操作 System.out.println("在代理真实对象之前......."); System.out.println("method: "+method); //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); //在代理真实对象后我们也可以添加一些自己的操作 System.out.println("在代理真实对象之后......."); return null; } }
测试方法:
public static void main(String[] args) { RealSubject realSubject=new RealSubject(); InvocationHandler handler=new DynamicProxy(realSubject); Subject subject=(Subject) Proxy.newProxyInstance( realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(),
handler); System.out.println(subject.getClass().getName()); subject.rent(); // subject.hello("你好"); }
方法二CGLIB: