Spring Aop 代理创建方式:https://www.cnblogs.com/jhxxb/p/14097866.html
最后都会走到 ProxyCreatorSupport#createAopProxy 中,拿到 AopProxy,然后调用 getProxy 方法获取代理对象
public class ProxyCreatorSupport extends AdvisedSupport { protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); }
DefaultAopProxyFactory
createAopProxy 方法,它的唯一实现为 DefaultAopProxyFactory
/** * 默认情况下,实现了接口,就使用 JDK 动态代理,没有就使用 CGLIB */ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { 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."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } /** * Determine whether the supplied {@link AdvisedSupport} has only the {@link org.springframework.aop.SpringProxy} interface specified (or no proxy interfaces specified at all). */ private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }
AopProxy 有两个实现类,通过 getProxy 方法创建代理对象
JdkDynamicAopProxy
/** * 实现了 InvocationHandler,所以处理器就是自己。会实现 invoke 方法 * 是 final 类,默认是 package 的访问权限 */ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { /** * 保存这个 AOP 代理所有的配置信息,包括所有的增强器等等 */ private final AdvisedSupport advised; // 标记 equals 和 hashCode 方法是否定义在了接口上 private boolean equalsDefined; private boolean hashCodeDefined; public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); // 内部再校验一次:必须有至少一个增强器和目标实例才行 if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException("No advisors and no TargetSource specified"); } this.advised = config; } @Override public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } /** * 真正创建 JDK 动态代理实例的地方 */ @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } // 这部很重要,就是去找接口,我们看到最终代理的接口就是这里返回的所有接口们(除了我们自己的接口,还有 Spring 默认的一些接口)大致过程如下: // 1、获取目标对象自己实现的接口们(最终肯定都会被代理的) // 2、是否添加 SpringProxy 接口:目标对象实现对就不添加了,没实现过就添加 true // 3、是否新增 Adviced 接口,注意不是 Advice 通知接口。实现过就不实现了,没实现过并且 advised.isOpaque()=false 就添加(默认是会添加的) // 4、是否新增 DecoratingProxy 接口(Spring4.3 后才提供)。传入的参数 decoratingProxy 为 true,并且没实现过就添加(显然这里,首次进来是会添加的) // 5、代理类的接口一共是目标对象的接口加上面三个接口 SpringProxy、Advised、DecoratingProxy(SpringProxy 是个标记接口而已,其余的接口都有对应的方法的) Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 第三个参数传的 this,处理器就是自己,到此一个代理对象就此 new 出来了 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } /** * 看接口里有没有自己定义 equals 和 hashCode方法,这个很重要,然后标记一下 */ private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) { for (Class<?> proxiedInterface : proxiedInterfaces) { Method[] methods = proxiedInterface.getDeclaredMethods(); // 此处用的是 getDeclaredMethods,只会找自己的 for (Method method : methods) { if (AopUtils.isEqualsMethod(method)) { this.equalsDefined = true; } if (AopUtils.isHashCodeMethod(method)) { this.hashCodeDefined = true; } if (this.equalsDefined && this.hashCodeDefined) { // 两个都找到了就没必要继续循环 return; } } } } /** * 对于这部分代码和采用 CGLIB 的大部分逻辑都是一样的,Spring 对此的解释很有意思: * 本来是可以抽取出来的,使得代码看起来更优雅。但是因为此会带来 10% 的性能损耗,所以 Spring 最终采用了粘贴复制的方式各用一份 * Spring 说它提供了基础的套件,来保证两个的执行行为是一致的。 * proxy:指的是我们所代理的那个真实对象;method:指的是我们所代理的那个真实对象的某个方法的 Method 对象;args:指的是调用那个真实对象方法的参数。 */ @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; // 进入 invoke 方法后,最终操作的是 targetSource 对象 // 因为 InvocationHandler 持久的就是 targetSource,最终通过 getTarget 拿到目标对象 TargetSource targetSource = this.advised.targetSource; Object target = null; try { // “通常情况” Spring AOP 不会对 equals、hashCode 方法进行拦截增强,所以此处做了处理 // equalsDefined 为 false(表示自己没有定义过 eequals 方法),那就交给代理去比较 // hashCode 同理,只要你自己没有实现过此方法,那就交给代理 // 需要注意的是:这里统一指的是,如果接口上有此方法,但是你自己并没有实现 equals 和 hashCode 方法,那就走 AOP 这里的实现 // 如果接口上没有定义此方法,只是实现类里自己 @Override 了 HashCode,那是无效的,就是普通执行 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); } // DecoratingProxy 的方法和 Advised 接口的方法,都是最终调用了 config,也就是 this.advised 去执行的 else if (method.getDeclaringClass() == DecoratingProxy.class) { return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; // 这个是最终该方法的返回值 // 是否暴露代理对象,默认 false 可配置为 true,如果暴露就意味着允许在线程内共享代理对象, // 注意这是在线程内,也就是说同一线程的任意地方都能通过 AopContext 获取该代理对象,这应该算是比较高级一点的用法了。 if (this.advised.exposeProxy) { // 这里缓存一份代理对象在 oldProxy 里,后面有用 oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 通过目标源获取目标对象(此处 Spring 建议获取目标对象靠后获取,而不是放在上面) target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 获取作用在这个方法上的所有拦截器链,参见 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法 // 会根据切点表达式去匹配这个方法。因此其实每个方法都会进入这里,只是有很多方法的 chain 是 Empty 而已 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { // 若拦截器为空,那就直接调用目标方法了 // 对参数进行适配:主要处理一些数组类型的参数,看是表示一个参数,还是表示多个参数(可变参数最终到此都是数组类型,所以最好是需要一次适配) Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 直接调用目标方法 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 创建一个 invocation ,此处为 ReflectiveMethodInvocation 最终是通过它,去执行前置加强、后置加强等等逻辑 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 此处会执行所有的拦截器链,交给 AOP 联盟的 MethodInvocation 去处理。当然实现还是 Spring 的 ReflectiveMethodInvocation retVal = invocation.proceed(); } // 获取返回值的类型 Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // 一些列的判断条件,如果返回值不为空,且为目标对象的话,就直接将目标对象赋值给 retVal retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { // 返回 null,且还不是 Void 类型,就抛错 throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // 释放 targetSource.releaseTarget(target); } if (setProxyContext) { // 把老的代理对象重新 set 进去 AopContext.setCurrentProxy(oldProxy); } } } /** * AOP 帮我们实现的 equals 方法 */ @Override public boolean equals(@Nullable Object other) { if (other == this) { return true; } if (other == null) { return false; } JdkDynamicAopProxy otherProxy; if (other instanceof JdkDynamicAopProxy) { otherProxy = (JdkDynamicAopProxy) other; } else if (Proxy.isProxyClass(other.getClass())) { InvocationHandler ih = Proxy.getInvocationHandler(other); if (!(ih instanceof JdkDynamicAopProxy)) { return false; } otherProxy = (JdkDynamicAopProxy) ih; } else { return false; } return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised); } /** * AOP 帮我们实现的 hashCode 方法 */ @Override public int hashCode() { return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } }
除了实现类里自己写的方法(接口上没有),其余方法统一都会进入代理的 invoke() 方法里面。只是 invoke 上做了很多特殊处理,比如 DecoratingProxy 和 Advised 等的方法,都是直接执行了。
object 的方法中,toString() 方法会被增强。
ObjenesisCglibAopProxy
/** * 继承自 CglibAopProxy,它只重写了 createProxyClassAndInstance 方法 */ class ObjenesisCglibAopProxy extends CglibAopProxy { private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class); // 另外一种创建实例的方式,可以不用空的构造函数 private static final SpringObjenesis objenesis = new SpringObjenesis(); public ObjenesisCglibAopProxy(AdvisedSupport config) { super(config); } @Override protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { // 创建一个代理得实例 Class<?> proxyClass = enhancer.createClass(); Object proxyInstance = null; if (objenesis.isWorthTrying()) { // 如果为 true,就采用 objenesis 去 new 一个实例 try { proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache()); } catch (Throwable ex) { logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex); } } if (proxyInstance == null) { // 若果还为 null,就再去拿构造函数(指定参数的) try { Constructor<?> ctor = (this.constructorArgs != null ? proxyClass.getDeclaredConstructor(this.constructorArgTypes) : proxyClass.getDeclaredConstructor()); // 通过此构造函数去 new 一个实例 ReflectionUtils.makeAccessible(ctor); proxyInstance = (this.constructorArgs != null ? ctor.newInstance(this.constructorArgs) : ctor.newInstance()); } catch (Throwable ex) { throw new AopConfigException("Unable to instantiate proxy using Objenesis, and regular proxy instantiation via default constructor fails as well", ex); } } ((Factory) proxyInstance).setCallbacks(callbacks); return proxyInstance; } }
父类 CglibAopProxy
class CglibAopProxy implements AopProxy, Serializable { /** * 它的两个 getProxy() 相对来说比较简单,就是使用 CGLIB 的方式,利用 Enhancer 创建了一个增强的实例 * 这里面比较复杂的地方在:getCallbacks() 这步是比较繁琐的 * setCallbackFilter 就是看看哪些方法需要拦截,哪些不需要 */ @Override public Object getProxy() { return getProxy(null); } // CGLIB 重写的两个方法 @Override public boolean equals(@Nullable Object other) { return (this == other || (other instanceof CglibAopProxy && AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised))); } @Override public int hashCode() { return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } /** * 最后,所有的被代理的类的所有的方法调用,都会进入 DynamicAdvisedInterceptor#intercept 这个方法里面来(相当于 JDK 动态代理的 invoke 方法) * 它实现了 MethodInterceptor 接口 */ private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) { this.advised = advised; } @Override @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; // 目标对象源 TargetSource targetSource = this.advised.getTargetSource(); try { if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 拿到目标对象,这里就是使用 targetSource 的意义,它提供多个实现类,从而实现了更多的可能性 // 比如:SingletonTargetSource、HotSwappableTargetSource、PrototypeTargetSource、ThreadLocalTargetSource 等 target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 一样的,也是拿到和这个方法匹配的所有增强器和通知,和 JDK Proxy 中是一样的 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // 没有增强器,同时该方法是 public 的,就直接调用目标方法(不拦截) Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // CglibMethodInvocation 这里采用的是 CglibMethodInvocation,它是 ReflectiveMethodInvocation 的子类,到这里就和 JDK Proxy 保持一致了 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } @Override public boolean equals(@Nullable Object other) { return (this == other || (other instanceof DynamicAdvisedInterceptor && this.advised.equals(((DynamicAdvisedInterceptor) other).advised))); } @Override public int hashCode() { return this.advised.hashCode(); } } private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
和 JDK 的一样,Object 的方法,只有 toString() 会被拦截(执行通知)
生成出来的代理对象,Spring 默认都给你实现了接口:SpringProxy、Advised
和 JDK 不同的是,比如 equals 和 hashCode 等方法根本就不会进入 intecept 方法,而是在 getCallbacks() 那里就给特殊处理掉了
总结
关于 final 方法
- JDK 代理:因为接口的方法不能使用 final 关键字,所以编译器就过不去
- CGLIB 代理:final 修饰某个方法后,不报错。但也不会拦截了
关于 static 方法
- JDK 代理:static 修饰接口上的方法,要求有 body 体(JDK8 后支持)。但是因为子类不能 @Override了,所以编译就报错了
- CGLIB 代理:父类方法用 static 修饰后,子类也是无法进行重写的。因此不报错,但也不会拦截了
关于非 public 方法
- JDK 代理:接口中的方法都是 public的,所以对于它不存在这种现象
- CGLIB 代理:记住结论,只有 private 的方法不能被代理(因为子类无法访问),其余的访问权限级别的,都能够被正常代理
使用 JDK 动态代理的入口方法是 JdkDynamicAopProxy.invoke() 方法,使用 CGLIB 动态代理入口方法是 DynamicAdvisedInterceptor.intercept() 方法
JDK 动态代理使用的 MethodInvocation 是: ReflectiveMethodInvocation,CGLIB 动态代理使用的是 CglibMethodInvocation,它俩都是 ProxyMethodInvocation 接口的实现类。且 CglibMethodInvocation 继承自 ReflectiveMethodInvocation
CGLib 更适合代理不需要频繁实例化的类,而 Spring 绝大多数 Bean 都是单例的,因此在 Spring AOP 中推荐使用 CGLib,它的功能更强大些