AOP源碼分析-CglibAopProxy DynamicAdvisedInterceptor,springaop源碼分析
最近新公司在用Spring MVC,跟蹤Spring的Service發現是通過動態代理來實現的,而公司的事務是配置在Service層。所以想看下Spring 的AOP的具體實現。本文源碼基於Spring 4.0。
我們可以使用debug跟蹤一次Service調用的整體流程,可以清晰的看到一次流程處理:
CglibAopProxy.intercept方法,該方法中通過
this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
擷取一個List攔截鏈,然後通過
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
方法執行對應的攔截鏈進行執行處理。
最後通過,
processReturnType(proxy, target, method, retVal);
處理傳回值,並返回。
整體過程完全採用動態代理模式來實現。最主要的代碼如下:
@Override 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<Object> 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. retVal = methodProxy.invoke(target, args); } else { // We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null) { releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
代碼看起來很簡單。
下面我們可以逐行對代碼進行分析。
方法簽名:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable
可以看出,改方法傳入代理對象,方法對象,參數以及方法代理。MethodProxy 包含我們的需要被代理的方法資訊,包含方法完整簽名。
if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; }
此處代碼是判斷代理是否可用,大概是這個意思,此處的代碼不是很明白。
target = getTarget(); if (target != null) { targetClass = target.getClass(); }
此處是擷取目標類對象。
下來是擷取對應的鏈對象。
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
在這個方法中,比較重要的應該是cacheKey的擷取。
/** * Simple wrapper class around a Method. Used as the key when * caching methods, for efficient equals and hashCode comparisons. */ private static class MethodCacheKey { private final Method method; private final int hashCode; public MethodCacheKey(Method method) { this.method = method; this.hashCode = method.hashCode(); } @Override public boolean equals(Object other) { if (other == this) { return true; } MethodCacheKey otherKey = (MethodCacheKey) other; return (this.method == otherKey.method); } @Override public int hashCode() { return this.hashCode; } }}
這個類比較簡單,定義了對應的Method對象,以及Method對應的hashCode。
List<Object> cached = this.methodCache.get(cacheKey); /** Cache with Method as key and advisor chain List as value */ private transient Map<MethodCacheKey, List<Object>> methodCache;
此處緩衝了對應的攔截器鏈。如果為null,則通過factory執行個體化,並放入緩衝。
if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); }@Override public List<Object> 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<Object> interceptorList = new ArrayList<Object>(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 // isn't 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; }
這個方法雖然很長,但是實際內容還是相對比較簡單。
首先擷取所有切點。
config.getAdvisors()
判斷不同的切點類型,放入List。
執行對應List方法。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();@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); } }
處理傳回值:
retVal = processReturnType(proxy, target, method, retVal); return retVal;