整理两种代理的简单实现,各自优缺点,以及 Spring 对两种 aop 代理的选择。
JDK Proxy (基于接口的代理)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 interface Hello { void sayHello () ; } class HelloImpl implements Hello { @Override public void sayHello () { System.out.println("Hello World" ); } } class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler (Object target) { this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before invoke ..." ); Object result = method.invoke(target, args); System.out.println("After invoke ..." ); return result; } } public static void main (String[] args) { Hello Hello = new HelloImpl(); MyInvocationHandler handler = new MyInvocationHandler(Hello); Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler); proxyHello.sayHello(); } ------- Before invoke ... Hello World After invoke ...
JDK 动态代理的大致过程
Proxy.newProxyInstance
getProxyClass0 ProxyClassFactory ProxyGenerator 生成代理类的字节码,可在 main 方法执行时,添加 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
生成代理类字节码文件。
newInstance
Cglib (不依赖接口) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class HelloImpl { public void sayHello () { System.out.println("Hello World" ); } } public class MyCglibInterceptor implements MethodInterceptor { @Override public Object intercept (Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before cglib invoke ..." ); Object result = methodProxy.invokeSuper(obj, args); System.out.println("after cglib invoke ..." ); return result; } } public class CglibProxy { public static void main (String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloImpl.class); enhancer.setCallback(new MyCglibInterceptor()); HelloImpl hello = (HelloImpl) enhancer.create(); hello.sayHello(); } } ------ before cglib invoke ... Hello World after cglib invoke ...
Cglib 基于继承来实现代理,无法对 static 、final 类进行代理,也无法对 private 、static 方法进行代理。
Spring 对两种代理的选择 JDK 动态代理是实现了被代理类对象的接口,cglib 是继承了被代理的对象。
JDK 和 cglib 代理都是在运行期生成字节码,JDK 是直接写 Class 字节码,cglib 使用 asm 框架写字节码,生成代理类的效率比 jdk 低。
JDK 调用代理方法,是通过反射机制调用,cglib 是通过 FastClass 机制直接调用刚发,cglib 执行效率更高。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public AopProxy createAopProxy (AdvisedSupport config) throws AopConfigException { if (!config.isOptimize() && !config.isProxyTargetClass() && !this .hasNoUserSuppliedProxyInterfaces(config)) { return new JdkDynamicAopProxy(config); } else { Class<?> targetClass = config.getTargetClass(); if (targetClass == null ) { throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation." ); } else { return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config)); } } }
如果目标对象实现了接口,则默认采用 JDK 动态代理
如果目标对象没有实现接口,则采用 cglib 动态代理
如果目标对象实现了接口,且强制 cglib 代理,则使用 cglib 代理 。强制开启 cglib 代理方法,加上 @EnableAspectJAutoProxy(proxyTargetClass = true)
Title: Spring AOP
Author: mjd507
Date: 2018-09-12
Last Update: 2024-01-27
Blog Link: https://mjd507.github.io/2018/09/12/Spring-AOP/
Copyright Declaration: This station is mainly used to sort out incomprehensible knowledge. I have not fully mastered most of the content. Please refer carefully.