1. JDK代理和CGLIB代理
1)JDK动态代理是基于拦截器和反射实现的,不需要第三方库支持,只需要JDK环境即可。
条件/实现步骤:
必须实现InvocationHandler接口;
使用Proxy.newProxyInstance产生代理对象;
被代理的对象必须要实现接口;
内部采用asm技术动态生成字节码。
演示示例
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JdkProxyPattern { interface Foo { void foo(); } static class Target implements Foo { @Override public void foo() { System.out.println("target foo exec method"); } } /** * jdk代理只能针对接口进行代理 * 内部采用asm技术动态生成字节码 * @param args 命令参数 */ public static void main(String[] args) { Target target = new Target(); ClassLoader classLoader = JdkProxyPattern.class.getClassLoader(); Foo proxy = (Foo)Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before target proxy foo"); Object result = method.invoke(target, args); System.out.println("after target proxy foo"); return result; } }); proxy.foo(); } }
jdk动态代理的局限性在于只能对接口进行代理,不能对类进行代理。另外未被接口话的方法在代理类中将不可被代理。
2)CGLIB(Code Generation Library)动态代理. cglib是一个强大的高性能高质量的code生成类库,可以在运行期扩展Java类与实现Java接口。
条件/实现步骤:比如类A为被代理类
由于是采用的继承的方式,首先A不可以是final类;
查找A上的所有非final的public类型的方法定义,将这些方法的定义转换成字节码;
将组成的字节码转换成相应的代理的class对象;
实现MethodInterceptor接口,用来处理代理类上所有方法的请求。
演示示例 (这里使用了spring框架内中的cglib)
import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author cy.K * @since */ public class CglibProxyPattern { public static void main(String[] args) { Business business = new Business(); CgProxy cgProxy = new CgProxy(); // cglib中加强器,用来创建动态代理 Enhancer enhancer = new Enhancer(); // 设置代理类 enhancer.setSuperclass(business.getClass()); // 设置回调 enhancer.setCallback(cgProxy); Business proxy = (Business)enhancer.create(); proxy.code(); } } class Business { public void code(){ System.out.println("business does"); } } class CgProxy implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before proxy business"); methodProxy.invokeSuper(o, args); System.out.println("after proxy business"); return null; } }
springAOP便是使用的CGLIB动态代理来实现的。
优点:对比JDK代理,CGLIB可以对类进行代理;另一个是cglib的fastclass机制使得它比使用java反射实现代理来得要快。
缺点:无法对final类、final方法进行代理;cglib代理对象性能高于jdk代理,但是创建代理的耗时比jdk代理多,故更适合单例对象。非单例对象,jdk代理创建对象更快。
SpringAOP同时使用JDK代理和CGLIB动态代理,如果不强制,springAOP默认使用JDK动态代理。
当我们需要强制使用CGLIB来实现AOP的时候,需要xml中配置spring.aop.proxy-target-class=true或启动类中加上@EnableAspectJAutoProxy(proxyTargetClass = true)
浙公网安备 33010602011771号