Spring|Spring AOP之原理解析(三)

这里只是列出来一些必要high level的点,可以帮助理解AOP底层是怎么工作的。
1. Spring AOP的原理-动态代理 Spring AOP 的原理很简单,就是动态代理,它和 AspectJ 不一样,AspectJ 是直接修改掉你的字节码。
代理模式很简单,接口 + 真实实现类 + 代理类,其中 真实实现类 和 代理类 都要实现接口,实例化的时候要使用代理类。所以,Spring AOP 需要做的是生成这么一个代理类,然后替换掉真实实现类来对外提供服务。
替换的过程怎么理解呢?在 Spring IOC 容器中非常容易实现,就是在 getBean(…) 的时候返回的实际上是代理类的实例,而这个代理类我们自己没写代码,它是 Spring 采用 JDK Proxy 或 CGLIB 动态生成的。

getBean(…) 方法用于查找或实例化容器中的 bean,这也是为什么 Spring AOP 只能作用于 Spring 容器中的 bean 的原因,对于不是使用 IOC 容器管理的对象,Spring AOP 是无能为力的。
XML配置中,总是会声明如下bean:

或者是其他的*AutoProxyCreator,如AbstractAutoProxyCreator等,其实他们都实现了SmartInstantiationAwareBeanPostProcessor,最终继承自BeanPostProcessor。postProcessAfterInitialization方法正式生成自动代理类来替换具体实现Bean的地方。
/** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } /** * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. * @param bean the raw bean instance * @param beanName the name of the bean * @param cacheKey the cache key for metadata access * @return a proxy wrapping the bean, or the raw bean instance as-is */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }// Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; }this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }

IoC容器实例化Bean的时候,getBean -> initializeBean -> beanPostProcessor.postProcessAfterInitialization。
2. JDK/CGLib 动态代理 相关源码:接上面createProxy的调用:
protected Object createProxy( Class beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {ProxyFactory proxyFactory = new ProxyFactory(); // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } }Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); }proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); }return proxyFactory.getProxy(this.proxyClassLoader); }

到ProxyFactory中getProxy方法:
/** * Create a new proxy according to the settings in this factory. * Can be called repeatedly. Effect will vary if we've added * or removed interfaces. Can add and remove interceptors. * 【Spring|Spring AOP之原理解析(三)】Uses the given class loader (if necessary for proxy creation). * @param classLoader the class loader to create the proxy with * (or {@code null} for the low-level proxy facility's default) * @return the proxy object */ public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }//ProxyCreatorSupport.java /** * Subclasses should call this to get a new AOP proxy. They should not * create an AOP proxy with {@code this} as an argument. */ protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); }//DefaultAopProxyFactory.java @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()) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }

得结论:
createAopProxy 方法有可能返回 JdkDynamicAopProxy 实例,也有可能返回 ObjenesisCglibAopProxy 实例。
  • 如果被代理的目标类实现了一个或多个自定义的接口,那么就会使用 JDK 动态代理;
  • 如果没有实现任何接口,会使用 CGLIB 实现代理;
  • 如果设置了 proxy-target-class="true",那么都会使用 CGLIB。
JDK 动态代理基于接口,所以只有接口中的方法会被增强;
CGLIB 基于类继承,可以增强类中非final和非private的方法。
3. 动态代理-方法的调用 AopProxy接口的两个实现类:JdkDynamicAopProxy和CglibAopProxy,分别对应JDK和CGLIB动态代理的实现。
public interface AopProxy {/** * Create a new proxy object. * Uses the AopProxy's default class loader (if necessary for proxy creation): * usually, the thread context class loader. * @return the new proxy object (never {@code null}) * @see Thread#getContextClassLoader() */ Object getProxy(); /** * Create a new proxy object. * Uses the given class loader (if necessary for proxy creation). * {@code null} will simply be passed down and thus lead to the low-level * proxy facility's default, which is usually different from the default chosen * by the AopProxy implementation's {@link #getProxy()} method. * @param classLoader the class loader to create the proxy with * (or {@code null} for the low-level proxy facility's default) * @return the new proxy object (never {@code null}) */ Object getProxy(ClassLoader classLoader); }//JdkDynamicAopProxy @Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }//CglibAopProxy @Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource()); }try { Class rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class[] additionalInterfaces = rootClass.getInterfaces(); for (Class additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } }// Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass); // Configure CGLIB Enhancer... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class)); Callback[] callbacks = getCallbacks(rootClass); Class[] types = new Class[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (Exception ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } }

结合Spring AOP之原理解析(一)看它们的实现本质。简单来说,JDK的实现基于InvocationHandler,JdkDynamicAopProxy本身就是先了InvocationHandler;CGLIB则基于Enhancer。
这里重点看下织入的切面方法是怎么被调用的。
/** * Implementation of {@code InvocationHandler.invoke}. * Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null; try { if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); }Object retVal; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; }// May be null. Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); }// Get the interception chain for this method. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. if (chain.isEmpty()) { // We can skip creating a MethodInvocation: just invoke the target directly // Note that the final invoker must be an InvokerInterceptor so we know it does // nothing but a reflective operation on the target, and no hot swapping or fancy proxying. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { // We need to create a method invocation... invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); }// Massage return value if necessary. Class returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
重点在这里:
// Get the interception chain for this method. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. if (chain.isEmpty()) { // We can skip creating a MethodInvocation: just invoke the target directly // Note that the final invoker must be an InvokerInterceptor so we know it does // nothing but a reflective operation on the target, and no hot swapping or fancy proxying. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { // We need to create a method invocation... invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); }//ReflectiveMethodInvocation protected ReflectiveMethodInvocation( Object proxy, Object target, Method method, Object[] arguments, Class targetClass, List interceptorsAndDynamicMethodMatchers) {this.proxy = proxy; this.target = target; this.targetClass = targetClass; this.method = BridgeMethodResolver.findBridgedMethod(method); this.arguments = arguments; this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; }@Override public Object proceed() throws Throwable { //We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); }Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
这里就是各个Advice或MethodInterceptor执行的地方。仔细阅读,其实这里是个递归调用,如果有多个增强的话,会分别执行。
CGLIB代理的调用是通过callback实现的,最终也是落到上面ReflectiveMethodInvocation的proceed方法。重点的源码片段如下:
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { enhancer.setInterceptDuringConstruction(false); enhancer.setCallbacks(callbacks); return (this.constructorArgs != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create()); }

每个Callback是MethodInterceptor的实现,以DynamicUnadvisedExposedInterceptor为例:
/** * Interceptor for unadvised dynamic targets when the proxy needs exposing. */ private static class DynamicUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {private final TargetSource targetSource; public DynamicUnadvisedExposedInterceptor(TargetSource targetSource) { this.targetSource = targetSource; }@Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; Object target = this.targetSource.getTarget(); try { oldProxy = AopContext.setCurrentProxy(proxy); Object retVal = methodProxy.invoke(target, args); return processReturnType(proxy, target, method, retVal); } finally { AopContext.setCurrentProxy(oldProxy); this.targetSource.releaseTarget(target); } } }

    推荐阅读