深入分析Spring框架中AOP與動態(tài)代理的整合原理
從本文可以了解到什么
Spring的核心之一AOP具體是如何實現(xiàn)的Spring AOP使用了哪些動態(tài)代理方式如何使用Spring AOP創(chuàng)建代理對象Spring有哪些代理切入方式,如何增加切面在Spring之外有哪些代理方式Spring的各類注解如@Async等,是如何生效的等等... 你想了解的內(nèi)容,都會在本文進行呈現(xiàn)。
涉及到的相關(guān)源碼都有中文注釋,讓你一次看個明白。
做好準(zhǔn)備,正文開始了哦
Spring AOP動態(tài)代理支持的核心
jdk動態(tài)代理:java.lang.reflect.InvocationHandler對應(yīng)的方法攔截器:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;調(diào)用時使用method.invoke(Object, args)
該動態(tài)代理是基于接口的動態(tài)代理,所以并沒有一個原始方法的調(diào)用過程,整個方法都是被攔截的。
通過cglib動態(tài)創(chuàng)建類進行動態(tài)代理。org.springframework.cglib.proxy包下的原生接口,同net.sf.cglib.proxy包下的接口,都是源自cglib庫。Spring內(nèi)部的cglib動態(tài)代理使用了這種方式。對應(yīng)的方法攔截器:
org.springframework.cglib.proxy.Callback、org.springframework.cglib.proxy.MethodInterceptor
public interface MethodInterceptor extends Callback { Object intercept(Object obj, Method m, Object[] args, MethodProxy mp) throws Throwable }調(diào)用時,使用mp.invoke(Object obj, Object[] args)調(diào)用其他同類對象的原方法或者mp.invokeSuper(Object obj, Object[] args)調(diào)用原始(父類)方法。
org.aopalliance的攔截體系該包是AOP組織下的公用包,用于AOP中方法增強和調(diào)用。相當(dāng)于一個jsr標(biāo)準(zhǔn),只有接口和異常。在AspectJ、Spring等AOP框架中使用。
對應(yīng)的方法攔截器org.aopalliance.intercept.MethodInterceptor:
public interface MethodInterceptor extends Interceptor { Object invoke(MethodInvocation inv) throws Throwable; }調(diào)用時使用inv.proceed()調(diào)用原始方法。
附aopalliance包介紹:
整個包的結(jié)構(gòu)
詳細(xì)介紹:
Advice增強器標(biāo)記接口Interceptor攔截器,Advice的子接口,標(biāo)記攔截器。攔截器是增強器的一種。MethodInterceptor方法攔截器,Interceptor的子接口,攔截方法并處理。ConstructorInterceptor構(gòu)造器攔截器,Interceptor的子接口,攔截構(gòu)造器并處理。Joinpoint連接點。在攔截器中使用,封裝了原方法調(diào)用的相關(guān)信息,如參數(shù)、原對象信息,以及直接調(diào)用原方法的proceed方法。InvocationJoinpoint的子類,添加了獲取調(diào)用參數(shù)方法。MethodInvocationInvocation的子類,包含了獲取調(diào)用方法的方法。ConstructorInvocationInvocation的子類,包含了獲取構(gòu)造器的方法。Spring AOP框架的整合
先看一下通過Spring生成代理對象的代碼:
// 生成基于實例的代理 public Object createProxy(Object bean, Advice advice) { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(bean); proxyFactory.addAdvice(advice); return proxyFactory.getProxy(); } // 生成基于接口的代理 public T createProxy(Class interface, Interceptor interceptor) { T proxy = new ProxyFactory(interface, interceptor).getProxy(); // 或者ProxyFactory.getProxy(interface, interceptor).getProxy(); return proxy; }針對上面的代碼,結(jié)合源碼進行分析,得到整個代理對象的創(chuàng)建過程。
準(zhǔn)備:過程中出現(xiàn)的對象
AopProxyFactory接口AopProxy代理工廠類,用于生成代理對象AopProxy。public interface AopProxyFactory { AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException; }AopProxy代表一個AopProxy代理對象,可以通過這個對象構(gòu)造代理對象實例。public interface AopProxy { Object getProxy(); Object getProxy(ClassLoader classLoader); }Advised接口代表被Advice增強的對象,包括添加advisor的方法、添加advice等的方法。ProxyConfig類一個代理對象的配置信息,包括代理的各種屬性,如基于接口還是基于類構(gòu)造代理。AdvisedSupport類對Advised的構(gòu)建提供支持,Advised的實現(xiàn)類以及ProxyConfig的子類。ProxyCreatorSupport類AdvisedSupport的子類,創(chuàng)建代理對象的支持類,內(nèi)部包含AopProxyFactory工廠成員,可直接使用工廠成員創(chuàng)建Proxy。ProxyFactory類ProxyCreatorSupport的子類,用于生成代理對象實例的工廠類,生成代碼參考下面。Advisor接口代表一個增強器提供者的對象,內(nèi)部包含getAdvice方法獲取增強器。AdvisorChainFactory接口獲取增強器鏈的工廠接口。提供方法返回所有增強器,以數(shù)組返回。Pointcut接口切入點,用于匹配類與方法,滿足切入點的條件是才插入advice。相關(guān)接口:ClassFilter、MethodMatcher。類圖如下:
分析:結(jié)合源碼分析創(chuàng)建過程
以上準(zhǔn)備做完之后,就可以看源碼了,從獲取代理對象的實例入口ProxyFactory.getProxy()開始:
public Object getProxy() { // 創(chuàng)建AopProxy對象再獲取代理對象實例 return createAopProxy().getProxy(); } // createAopProxy方法在父類ProxyCreatorSupport中 protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } // 先獲取AopProxy的工廠對象,再把自己作為createAopProxy的參數(shù)AdvisedSupport傳進去,用自己作為代理對象的配置 return getAopProxyFactory().createAopProxy(this); }代理對象實例最終是使用AopProxy.getProxy()得到的,他的調(diào)用是在AopProxyFactory.createAopProxy(AdvisedSupport config,createAopProxy有兩個結(jié)果。一個是基于接口的JDK動態(tài)代理JdkDynamicAopProxy,一個是基于CGLib的生成類代理ObjenesisCglibAopProxy。源碼如下:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 如果是需要優(yōu)化的代理,或者標(biāo)記代理目標(biāo)類,或者代理配置中沒有需要代理的接口 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)) { // 如果目標(biāo)類是接口,或者已經(jīng)是Jdk的動態(tài)代理類,則創(chuàng)建jdk動態(tài)代理 return new JdkDynamicAopProxy(config); } // 否則創(chuàng)建Cglib動態(tài)代理 return new ObjenesisCglibAopProxy(config); } else { // 如果聲明創(chuàng)建Jdk動態(tài)代理則返回Jdk動態(tài)代理 return new JdkDynamicAopProxy(config); } } }傳入的AdvisedSupport config中包含了需要注冊的Method攔截器,AopProxy會保存這個config為advised對象。
基于JDK的動態(tài)代理
JdkDynamicAopProxy中g(shù)etProxy會返回:
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, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 返回代理對象的實例 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }自己作為InvocationHandler注冊,看他的invoke方法
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. // 沒有聲明equals方法,調(diào)用equals方法時,委托調(diào)用。 return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. // 沒有聲明hashCode方法,調(diào)用hashCode方法時,委托調(diào)用。 return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. // 如果調(diào)用的方法是DecoratingProxy中的方法,因為其中只有一個getDecoratedClass方法,這里直接返回被裝飾的Class即可 return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // 代理不是不透明的,且是接口中聲明的方法,且是Advised或其父接口的方法,則直接調(diào)用構(gòu)造時傳入的advised對象的相應(yīng)方法 // 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. // 如果暴露代理,則用AopContext保存當(dāng)前代理對象。用于多級代理時獲取當(dāng)前的代理對象,一個有效應(yīng)用是同類中調(diào)用方法,代理攔截器會無效??梢允褂肁opContext.currentProxy()獲得代理對象并調(diào)用。 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 // 這里是關(guān)鍵,獲得攔截鏈chain,是通過advised對象,即config對象獲得的。 method. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we dont, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. if (chain.isEmpty()) { // 如果鏈?zhǔn)强?,則直接調(diào)用被代理對象的方法 // 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. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // We need to create a method invocation... // 否則創(chuàng)建一個MethodInvocation對象,用于鏈?zhǔn)秸{(diào)用攔截器鏈chain中的攔截器。 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. // 開始執(zhí)行鏈?zhǔn)秸{(diào)用,得到返回結(jié)果 retVal = invocation.proceed(); } // Massage return value if necessary. Class returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // 處理返回值 // 如果返回結(jié)果是this,即原始對象,且方法所在類沒有標(biāo)記為RawTargetAccess(不是RawTargetAccess的實現(xiàn)類或者子接口),則返回代理對象。 // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we cant 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); } } }注冊的Method攔截器都是通過AdvisedSupport這個config對象的addAdvice或者addAdvisor注冊進去的。
public void addAdvice(int pos, Advice advice) throws AopConfigException { Assert.notNull(advice, "Advice must not be null"); if (advice instanceof IntroductionInfo) { // We dont need an IntroductionAdvisor for this kind of introduction: // Its fully self-describing. // 如果是引介,則加入引介advisor。(新增功能) addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice)); } else if (advice instanceof DynamicIntroductionAdvice) { // We need an IntroductionAdvisor for this kind of introduction. // jdk動態(tài)代理不支持動態(tài)引介 throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor"); } else { // 把advice轉(zhuǎn)換為advisor并添加,目標(biāo)是DefaultPointcutAdvisor。 addAdvisor(pos, new DefaultPointcutAdvisor(advice)); } }其實也是把advice轉(zhuǎn)成了advisor注冊的。 看下最上面invoke方法中有一個方法調(diào)用:
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List cached = this.methodCache.get(cacheKey); if (cached == null) { // 其實是通過advisorChainFactory工廠對象獲得的 cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }是通過AdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法獲取的,也把config對象傳入了,且加的有緩存。其實是通過method獲取該method對應(yīng)的advisor。下面是他的唯一實現(xiàn):
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { @Override public List getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. List interceptorList = new ArrayList(config.getAdvisors().length); Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isnt a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; } /** * Determine whether the Advisors contain matching introductions. */ private static boolean hasMatchingIntroductions(Advised config, Class actualClass) { for (int i = 0; i < config.getAdvisors().length; i++) { Advisor advisor = config.getAdvisors()[i]; if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (ia.getClassFilter().matches(actualClass)) { return true; } } } return false; } }上面包括了各種對Advisor包裝,通過Pointcut等的判斷把Advisor中的Advice包裝成MethodInterceptor、InterceptorAndDynamicMethodMatcher或者Interceptor。
之后在調(diào)用方法前,又把chain轉(zhuǎn)換為了aopalliance體系的的MethodInvocation。
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
最終執(zhí)行的是retVal = invocation.proceed()。 在ReflectiveMethodInvocation的proceed方法中,有整個攔截器鏈的責(zé)任鏈模式的執(zhí)行過程,可以仔細(xì)看看,通過責(zé)任鏈序號方式執(zhí)行的。
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { // 鏈全部執(zhí)行完,再次調(diào)用proceed時,返回原始對象方法調(diào)用執(zhí)行結(jié)果。遞歸的終止。 return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); // 用currentInterceptorIndex記錄當(dāng)前的interceptor位置,初值-1,先++再獲取。當(dāng)再攔截器中調(diào)用invocation.proceed()時,遞歸進入此方法,索引向下移位,獲取下一個攔截器。 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 如果是InterceptorAndDynamicMethodMatcher則再執(zhí)行一次動態(tài)匹配 // 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)) { // 匹配成功,執(zhí)行 return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. // 匹配失敗,跳過該攔截器,遞歸調(diào)用本方法,執(zhí)行下一個攔截器。 return proceed(); } } else { // Its an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. // 如果是interceptor,則直接調(diào)用invoke。把自己作為invocation,以便在invoke方法中,調(diào)用invocation.proceed()來執(zhí)行遞歸。或者invoke中也可以不執(zhí)行invocation.proceed(),強制結(jié)束遞歸,返回指定對象作為結(jié)果。 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }基于Cglib的動態(tài)代理
看另外一種情況,Cglib的代理類:
ObjenesisCglibAopProxy繼承自CglibAopProxy,整體對外暴露的接口和方法是與上面一致的,只有其真實實現(xiàn)換成了Cglib而已。
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, classLoader); // Configure CGLIB Enhancer... // 使用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); // 設(shè)置類生成策略,直接生成類的字節(jié)碼byte[],可以深入研究 enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); // 獲取所有的callback,此時callback是cglib 的,getCallbacks中會把advisors封裝成callback傳入 Callback[] callbacks = getCallbacks(rootClass); Class[] types = new Class[callbacks.length]; // 生成callback類型數(shù)組 for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above // 加入是否需要進行callback的過濾器,根據(jù)filter的返回的int值,cglib會執(zhí)行不同的callback,索引分別對應(yīng)上面的callback數(shù)組的索引: // 0:AOP_PROXY、1:INVOKE_TARGET、2:NO_OVERRIDE、3:DISPATCH_TARGET、4:DISPATCH_ADVISED、5:INVOKE_EQUALS、6:INVOKE_HASHCODE 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 (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } } protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { // 不攔截構(gòu)造方法 enhancer.setInterceptDuringConstruction(false); // 設(shè)置攔截器callback enhancer.setCallbacks(callbacks); // 創(chuàng)建代理對象實例 return (this.constructorArgs != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create()); }直接看方法攔截器部分。注冊攔截器是在getProxy方法中,注冊進去的是cglib中的callback:
Callback[] callbacks = getCallbacks(rootClass) enhancer.setCallbacks(callbacks); private Callback[] getCallbacks(Class rootClass) throws Exception { // Parameters used for optimization choices... boolean exposeProxy = this.advised.isExposeProxy(); boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); // Choose an "aop" interceptor (used for AOP calls). // 生成aopInterceptor,用于AOP調(diào)用,這是調(diào)用攔截器鏈的核心,詳看后面。 Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); // Choose a "straight to target" interceptor. (used for calls that are // unadvised but can return this). May be required to expose the proxy. Callback targetInterceptor; // 下面根據(jù)不同情況,返回不同的Callback。 // targetSource的isStatic為true表示targetSource中的target是靜態(tài)的不改變的,故直接緩存target即可。 // 為false則代表是動態(tài)的target,每次都需要getTarget來獲取,這兩種返回不同的callback,以便后續(xù)執(zhí)行時使用不同情況的target。 // 而exposeProxy代表是否暴露代理對象到AopProxyContext中。 // 為true代表暴露,false不暴露。都需要返回不同的callback。 // 故總共有四種callback,且四種callback都有一個processReturnType的過程,同JdkDynamicAopProxy中的處理返回值。前面的操作也與JdkDynamicAopProxy中開始的目的相同。 if (exposeProxy) { targetInterceptor = isStatic ? new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()); } else { targetInterceptor = isStatic ? new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedInterceptor(this.advised.getTargetSource()); } // Choose a "direct to target" dispatcher (used for // unadvised calls to static targets that cannot return this). // 直接調(diào)用target的callback Callback targetDispatcher = isStatic ? new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp(); // callbackFilter返回的是callback的索引,用于調(diào)用這里的索引值對應(yīng)的callback。 Callback[] mainCallbacks = new Callback[] { aopInterceptor, // for normal advice // 經(jīng)過callbackFilter后,不需要被advice的對象,直接調(diào)用這個interceptor,性能最高。 targetInterceptor, // invoke target without considering advice, if optimized new SerializableNoOp(), // no override for methods mapped to this targetDispatcher, // 調(diào)用advised中方法時,直接分配到advised中。 this.advisedDispatcher, // equals方法 new EqualsInterceptor(this.advised), // hashCode方法 new HashCodeInterceptor(this.advised) }; Callback[] callbacks; // If the target is a static one and the advice chain is frozen, // then we can make some optimizations by sending the AOP calls // direct to the target using the fixed chain for that method. // 這是一個優(yōu)化,如果target是個不可變的靜態(tài)對象,且advice鏈?zhǔn)枪潭ú蛔兊?,則進行優(yōu)化。內(nèi)容見后面。 if (isStatic && isFrozen) { Method[] methods = rootClass.getMethods(); Callback[] fixedCallbacks = new Callback[methods.length]; this.fixedInterceptorMap = new HashMap(methods.length); // TODO: small memory optimization here (can skip creation for methods with no advice) for (int x = 0; x < methods.length; x++) { // 遍歷所有方法,返回每個方法的攔截器鏈,并為每個方法生成一個包含攔截器鏈的callback。 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass); fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); // 注意,這個fixedInterceptorMap還與callbackFilter關(guān)聯(lián),以便達(dá)到filter的目的。 // 同時保存索引到map中,以用于callbackFilter中返回索引。 this.fixedInterceptorMap.put(methods[x].toString(), x); } // Now copy both the callbacks from mainCallbacks // and fixedCallbacks into the callbacks array. // 聚合所有callback callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length]; System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length); System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length); // 標(biāo)記fixedInterceptor的偏移量,也會傳入filter。 this.fixedInterceptorOffset = mainCallbacks.length; } else { callbacks = mainCallbacks; } return callbacks; }上面提到callbackFilter的作用是返回需要調(diào)用的callback的序號,與上面的getCallbacks有比較大的關(guān)聯(lián),源碼如下
// aopInterceptor: DynamicAdvisedInterceptor private static final int AOP_PROXY = 0; // targetInterceptor: 沒有advise的方法 private static final int INVOKE_TARGET = 1; // noOp: SerializableNoOp private static final int NO_OVERRIDE = 2; // targetDispatcher: isStatic ? StaticDispatcher : SerializableNoOp private static final int DISPATCH_TARGET = 3; // advisedDispatcher: AdvisedDispatcher private static final int DISPATCH_ADVISED = 4; // EqualsInterceptor private static final int INVOKE_EQUALS = 5; // HashCodeInterceptor private static final int INVOKE_HASHCODE = 6; // 其他索引直接通過fixedInterceptorMap獲得 // 下面邏輯基本對應(yīng)JdkDynamicAopProxy中判斷邏輯 public int accept(Method method) { if (AopUtils.isFinalizeMethod(method)) { // 如果是final的方法,則返回NO_OVERRIDE logger.debug("Found finalize() method - using NO_OVERRIDE"); return NO_OVERRIDE; } if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { if (logger.isDebugEnabled()) { logger.debug("Method is declared on Advised interface: " + method); } // advised上的方法,直接調(diào)用advised對象的對應(yīng)方法 return DISPATCH_ADVISED; } // We must always proxy equals, to direct calls to this. if (AopUtils.isEqualsMethod(method)) { // 返回調(diào)用equals logger.debug("Found equals method: " + method); return INVOKE_EQUALS; } // We must always calculate hashCode based on the proxy. if (AopUtils.isHashCodeMethod(method)) { // 返回調(diào)用hashCode logger.debug("Found hashCode method: " + method); return INVOKE_HASHCODE; } Class targetClass = this.advised.getTargetClass(); // Proxy is not yet available, but that shouldnt matter. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 判斷是否有攔截器鏈 boolean haveAdvice = !chain.isEmpty(); boolean exposeProxy = this.advised.isExposeProxy(); boolean isStatic = this.advised.getTargetSource().isStatic(); boolean isFrozen = this.advised.isFrozen(); if (haveAdvice || !isFrozen) { // 如果有advice或者不是凍結(jié)的(不可改變的) // If exposing the proxy, then AOP_PROXY must be used. if (exposeProxy) { if (logger.isDebugEnabled()) { logger.debug("Must expose proxy on advised method: " + method); } // 如果需要暴露Proxy則返回aop代理 return AOP_PROXY; } String key = method.toString(); // Check to see if we have fixed interceptor to serve this method. // Else use the AOP_PROXY. if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) { // 通過fixedInterceptorMap獲得對應(yīng)索引,返回callback。 if (logger.isDebugEnabled()) { logger.debug("Method has advice and optimizations are enabled: " + method); } // We know that we are optimizing so we can use the FixedStaticChainInterceptors. int index = this.fixedInterceptorMap.get(key); return (index + this.fixedInterceptorOffset); } else { if (logger.isDebugEnabled()) { logger.debug("Unable to apply any optimizations to advised method: " + method); } return AOP_PROXY; } } else { // See if the return type of the method is outside the class hierarchy of the target type. // If so we know it never needs to have return type massage and can use a dispatcher. // If the proxy is being exposed, then must use the interceptor the correct one is already // configured. If the target is not static, then we cannot use a dispatcher because the // target needs to be explicitly released after the invocation. if (exposeProxy || !isStatic) { // 如果需要暴露,則要使用targetInterceptor return INVOKE_TARGET; } Class returnType = method.getReturnType(); if (returnType.isAssignableFrom(targetClass)) { // 如果返回類型是被代理類型的父類或者接口,有可能是返回this引用,需要用INVOKE_TARGET對返回值做處理 if (logger.isDebugEnabled()) { logger.debug("Method return type is assignable from target type and " + "may therefore return this - using INVOKE_TARGET: " + method); } return INVOKE_TARGET; } else { if (logger.isDebugEnabled()) { logger.debug("Method return type ensures this cannot be returned - " + "using DISPATCH_TARGET: " + method); } // 不需要攔截,直接返回目標(biāo)調(diào)用 return DISPATCH_TARGET; } } }這里的核心是把advised對象轉(zhuǎn)成了Callback,注冊到Enhancer中,那么攔截器鏈的執(zhí)行應(yīng)該是在
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 下面這段代碼在我們調(diào)試Spring的時候回經(jīng)常進來,特別是進入一個Bean的方法后再返回上一級調(diào)用時,最常見的就是這里。 // 這段代碼基本與JdkDynamicAopProxy的invoke方法一致 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Class targetClass = null; Object target = null; try { 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 = getTarget(); if (target != null) { targetClass = target.getClass(); } // 獲取攔截器鏈 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // 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. // 如果鏈?zhǔn)强涨沂莗ublic方法,則直接調(diào)用 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation... // 否則創(chuàng)建一個CglibMethodInvocation以便驅(qū)動攔截器鏈 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } // 處理返回值,同JDK動態(tài)代理 retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null) { releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }這個和上面的jdk動態(tài)代理的invoke就比較像了,一樣有List chain =this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
最終的執(zhí)行則是:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
一樣是轉(zhuǎn)換為了aopalliance的invocation。注意CglibMethodInvocation是ReflectiveMethodInvocation的子類。區(qū)別在于CglibMethodInvocation內(nèi)維護了cglib的MethodProxy,調(diào)用鏈執(zhí)行完進行最終真實調(diào)用時,是調(diào)用了methodProxy.invoke(this.target, this.arguments)。
protected Object invokeJoinpoint() throws Throwable { if (this.publicMethod) { return this.methodProxy.invoke(this.target, this.arguments); } else { return super.invokeJoinpoint(); } }其父類ReflectiveMethodInvocation的該方法是:
protected Object invokeJoinpoint() throws Throwable { return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments); }到這里基本問題都已經(jīng)解決,還差最后一個優(yōu)化點沒有說,上面的FixedChainStaticTargetInterceptor與DynamicAdvisedInterceptor的區(qū)別在哪?代碼如下,一看便知
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 直接生成了CglibMethodInvocation,因為adviceChain是固定不變的,故在創(chuàng)建時已經(jīng)傳入,不需要每次執(zhí)行時動態(tài)再計算了。 // 省略了暴露代理判斷,無需進行context設(shè)置 MethodInvocation invocation = new CglibMethodInvocation(proxy, this.target, method, args, this.targetClass, this.adviceChain, methodProxy); // If we get here, we need to create a MethodInvocation. Object retVal = invocation.proceed(); retVal = processReturnType(proxy, this.target, method, retVal); return retVal; }致此結(jié)束,后面進行總結(jié)。
總結(jié)
再回顧一下上面的config對象,config為AdvisedSupport對象,其實整體是個代理配置對象
public class ProxyConfig implements Serializable - public class AdvisedSupport extends ProxyConfig implements Advised -- public class ProxyCreatorSupport extends AdvisedSupport --- public class ProxyFactory extends ProxyCreatorSupport最下層的ProxyFactory包含了特殊的功能,只能創(chuàng)建proxy對象,他是通過AopProxyFactory來做的:
public Object getProxy() { return createAopProxy().getProxy(); }createAopProxy()方法是ProxyCreatorSupport類支持的:
protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); } public AopProxyFactory getAopProxyFactory() { return this.aopProxyFactory; } public ProxyCreatorSupport() { this.aopProxyFactory = new DefaultAopProxyFactory(); }這樣,ProxyFactory(AdvisedSupport config)就和AopProxyFactory有了聯(lián)系,AopProxyFactory和AopProxy也有了聯(lián)系,AopProxy和Proxy也有了聯(lián)系。
結(jié)論
那么最終的結(jié)論是,Spring使用了Jdk動態(tài)代理和Cglib做代理,但是會把兩種代理的攔截器轉(zhuǎn)換為aopalliance這種標(biāo)準(zhǔn)形式進行處理。但是在公開給外部時,其實使用的是advisor這種形式,都注冊為advisor或者advised即可。這樣就統(tǒng)一了入口。
AspectJ框架也使用了aopalliance這種標(biāo)準(zhǔn)形式進行AOP代理,Spring對AspectJ在上層也有包裝,可以研究一下。
相關(guān)研究
Spring與aopalliance標(biāo)準(zhǔn)相關(guān)的類圖Advice實現(xiàn)類中有一些adaptor,以及org.springframework.aop.framework.adapter包下一些其他適配器,類圖如下:他們的作用是把advice包裝為advisor,把advice包裝為MethodInterceptor。Spring其他聲明代理對象Bean的方法BeanNameAutoProxyCreator// org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator @Bean public BeanNameAutoProxyCreator beanNameAutoProxyCreator() { BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator(); beanNameAutoProxyCreator.setBeanNames("test"); beanNameAutoProxyCreator.setInterceptorNames("testInterceptor"); return beanNameAutoProxyCreator; }基本原理是使用BeanNameAutoProxyCreator自動對特定的Bean轉(zhuǎn)換為特定攔截包裝后的代理Bean,依然是使用了BeanPostProcessor,相關(guān)類參考下面。
public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessorii. 使用@Aspect自動織入攔截器
@Component @Aspect public class LogAspect { @Pointcut("execution(* com.demo.service..*.*(..))" ) public void inServiceLayer() { } @Before(value = "execution(public * com.demo.service..*.*(..))" ) public void beforeShow() { System.out.println("before show." ); } @After(value = "execution(public * com.demo.service..*.*(..))" ) public void afterShow() { System.out.println("after show." ); } @Around("inServiceLayer()") public Object around(ProceedingJoinPoint thisJoinPoint) throws Throwable { return thisJoinPoint.proceed(); } }詳細(xì)原理參考3
Spring中@Aspect注解聲明的各種接入點是如何代理到Bean里面的,以及@Pointcut、@Before、@After、@AfterReturning、@AfterThrowing、@Around被包裝為了什么。相關(guān)類的類圖如下:4. 其他各種注解如何影響對象,如@Async、@Transactional(參考5)等。
基本原理是在@Async等的bpp(BeanPostProcessor,詳細(xì)作用參考后續(xù)文章)的處理階段中,檢查目標(biāo)bean是否被標(biāo)記Advised接口,如果是則直接添加自己聲明的實現(xiàn)特定功能的advisor,否則則使用ProxyFactory生成代理并添加自己的advisor。最終返回代理對象實例。Transaction 在 Controller 層的探索補充案例
Spring中一個動態(tài)代理實例,一個類中的一個方法,直接調(diào)用本類的@Async方法不觸發(fā)代理,而@Configuration注解配置類卻可以進行代理。為什么?
@Component public class AsyncService { AsyncService asyncService; public void setCurrent(AsyncService asyncService) { this.asyncService = asyncService; } public void async1() { System.out.println("1:" + Thread.currentThread().getName()); // 通過代理對象調(diào)用 asyncService.async3(); // 通過this調(diào)用,不通過代理。因為this不是代理對象,而是真實對象。 this.async3(); // 即使創(chuàng)建了代理,最后一層的調(diào)用仍然是調(diào)用原始對象的對應(yīng)方法,而不是使用代理對象的super.method()來進行調(diào)用的。 } public void async2() { System.out.println("2:" + Thread.currentThread().getName()); async3(); } @Async public void async3() { System.out.println("3:" + Thread.currentThread().getName()); } }當(dāng)基于接口進行代理時,又是怎樣的一種情況?
欲知詳情,可參考本人下一篇文章
小技巧
如何導(dǎo)出被cglib代理的類:Spring調(diào)用Enhance生成類時,最終總會生成類的字節(jié)碼,在生成的地方導(dǎo)出即可,調(diào)試下發(fā)現(xiàn)是在這里:
org.springframework.cglib.core.DefaultGeneratorStrategy.generate(ClassGenerator cg)方法。
cglib生成類時,callbackFilter是生成時已經(jīng)確定的,而不是動態(tài)調(diào)用filter來獲得要調(diào)用的callback。即類生成時,每個方法要調(diào)用的callback已經(jīng)自動織入到被代理方法的調(diào)用中了。在callbackFilter的accept方法中打斷點,就能看到整個類的生成過程了。找到生成類的字節(jié)碼也是在這里打斷點找到的。
導(dǎo)出類文件:
File file = new File("E:\\Test.class"); // 建立輸出字節(jié)流 FileOutputStream fos = null; try { fos = new FileOutputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } // 用FileOutputStream 的write方法寫入字節(jié)數(shù)組 try { fos.write(b); } catch (IOException e) { e.printStackTrace(); } System.out.println("寫入成功"); // 為了節(jié)省IO流的開銷,需要關(guān)閉 try { fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }也可使用javaagent來導(dǎo)出,見后面。
擴展知識
Advice:增強,在目標(biāo)方法范圍內(nèi)織入
Introduction: 引介,直接在類級別上添加目標(biāo)未實現(xiàn)的接口方法
上面提到的動態(tài)代理有兩種:
Jdk動態(tài)代理Jdk自帶的動態(tài)代理,使用Sun內(nèi)部實現(xiàn)動態(tài)生成類,限制是只能對接口進行動態(tài)代理。CGLIB動態(tài)字節(jié)碼生成動態(tài)生成現(xiàn)有類的子類并加載,可代理非接口。缺點是對于final聲明的類以及private的方法無法進行代理。除了上述兩種方法外,還有以下三種代理方式
自定義類加載器通過自定義的類加載器,在類加載前對原類字節(jié)碼進行替換,返回加入動態(tài)代理后的類的字節(jié)碼加載到內(nèi)存中。這種方式可代理任意類、接口。包括private方法和final類。但是當(dāng)項目中使用了一些其他類加載器時,會導(dǎo)致使用其他類加載器的類代理無效化。參考FakeClassloader。使用java agent進行字節(jié)碼轉(zhuǎn)換使用java.lang.Instrumentation接口提供的方法,在java agent的方法中進行動態(tài)字節(jié)碼轉(zhuǎn)換。對于預(yù)先加載的agent,可使用premain在main方法執(zhí)行前進行類替換。對于動態(tài)attach的java agent,可在agentmain方法中動態(tài)替換當(dāng)前內(nèi)存中的類。對于預(yù)先加載的agent來說,這種方式幾乎是萬能的,除了需要額外加入啟動參數(shù)外,幾乎沒有缺點。而對于動態(tài)attach的,則略微有些限制,只能替換方法中的實現(xiàn),而不能修改方法簽名。靜態(tài)AOP例如AspectJ框架,就是個靜態(tài)代理的框架,在編譯期直接編譯進入字節(jié)碼。對系統(tǒng)性能幾乎無損耗,但是靈活度略微有些欠缺。