所有文章已遷移至csdn,csdn個人主頁bugpool.blog.csdn.net
Spring AOP源碼目錄
Spring AOP源碼01:Jdk動態(tài)代理底層源碼
Spring AOP源碼02:ProxyFactory
Spring AOP源碼03:JdkDynamicAopProxy
Spring AOP源碼04:MethodInvocation 攔截器調(diào)用
Spring AOP源碼05:DefaultAdvisorAutoProxyCreator
Spring期末考壓軸題:當Spring AOP遇上循環(huán)依賴
git注釋源碼地址:https://github.com/chaitou/spring-framework-master.git
前言
如下圖,結(jié)合第二篇Spring AOP核心源碼 ProxyFactory育八,Spring AOP動態(tài)代理有2中生成方式稽揭,當代理對象實現(xiàn)了接口且沒有配置強制使用cglib代理
時翔忽,將使用JdkDynamicAopProxy
生成代理呼渣。反之使用CglibAopProxy
生成代理蔑祟。同時我們在第一篇Jdk動態(tài)代理底層源碼中已知早敬,Jdk動態(tài)代理通過getProxy
生成代理忌傻,同時$proxy
代理對象在調(diào)用方法時,將會回調(diào)invoke
方法進行搞监。因此對于JdkDynamicAopProxy
來說水孩,最重要的代碼就是分析getProxy
和invoke
方法。至于生成代理的底層源碼琐驴,第一篇已經(jīng)介紹過俘种,這里不再贅述
源碼分析
getProxy
下面代碼在第一篇Jdk動態(tài)代理底層源碼中我們手動寫過一遍秤标,這里再復習一下
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 獲取代理接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 判斷接口是否又hashCode和equals方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 使用JDK代理(classLoader, 接口, 當前JdkDynamicAopProxy對象:用于回調(diào)invoke和target對象方法)
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
-
classLoader
:當前類加載器 -
proxiedInterfaces
:當前代理類所實現(xiàn)的接口數(shù)組 -
this
:將自身類對象傳給生成的代理,作為代理的屬性h宙刘,屬性h將被用于方法回調(diào)觸發(fā)h.invoke
方法苍姜,實現(xiàn)增強
invoke
在開始invoke
之前,先定一下目標悬包,為了抓住主干衙猪,本專題只關(guān)心普通增強
,引介增強
等將暫時跳過布近,另外獨立出章節(jié)詳解垫释,因此遇到引介增強
等可以暫時先不糾結(jié)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 獲取代理目標對象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// equals方法處理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// hashCode處理
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// Advised接口或者其父接口中定義的方法,直接反射調(diào)用
else 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;
// 目標對象內(nèi)部調(diào)用是無法實現(xiàn)增強的,如果exposeProxy設(shè)置為true撑瞧,需要暴露代理
// ThreadLocal<Object> currentProxy
// 對象是ThreadLocal饶号,在finally后會清除currentProxy
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 以防target來自對象池,所以在創(chuàng)建代理前調(diào)用get獲取target
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 1. 獲取攔截器鏈
List<Object> 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.
// 攔截器為空季蚂,直接調(diào)用切點方法
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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 2. 將攔截器統(tǒng)一封裝成ReflectiveMethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 3. 執(zhí)行攔截器鏈
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())) {
// 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茫船,釋放target資源池由子類實現(xiàn)
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1. 獲取攔截器鏈
該方法將獲取到所有與當前method
匹配的advice
(增強),跟蹤getInterceptorsAndDynamicInterceptionAdvice
代碼扭屁,發(fā)現(xiàn)Spring AOP也使用緩存進行提高性能算谈,如果該方法已經(jīng)獲取過攔截器,則直接取緩存料滥,否則通過advisorChainFactory
獲取攔截器鏈
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
// 從緩存中獲取
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 獲取攔截器鏈
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// 設(shè)置緩存
this.methodCache.put(cacheKey, cached);
}
return cached;
}
繼續(xù)跟中getInterceptorsAndDynamicInterceptionAdvice
方法
// DefaultAdvisorChainFactory.java
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
// 循環(huán)所有切面
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 校驗當前Advisor是否適用于當前對象
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 校驗Advisor是否應用到當前方法上
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 匹配成功
if (match) {
// 從advisor中獲取攔截器數(shù)組
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
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) {
// 添加動態(tài)攔截器
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));
}
}
// 其他類型的advisor
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
...
}
剖去引介增強
然眼,動態(tài)增強
,我們只關(guān)心普通攔截器
葵腹。整個代碼思路還是比較清晰的高每,獲取所有Advisor
(切面),通過pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)
校驗當前代理對象是否匹配該Advisor践宴,再通過pointcutAdvisor.getPointcut().getMethodMatcher()
校驗是否匹配當前調(diào)用method
鲸匿。如果通過校驗,則提取advisor
中的interceptors
攔截器阻肩,添加到interceptorList
中
2. 將攔截器封裝成ReflectiveMethodInvocation
一個構(gòu)造器的調(diào)用带欢,重點在下一步調(diào)用
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
3. 執(zhí)行攔截器鏈
// 執(zhí)行攔截器鏈
retVal = invocation.proceed();
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.
// 動態(tài)匹配
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, 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.
// 普通攔截器烤惊,直接觸發(fā)
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
同樣我們只關(guān)心普通攔截器
乔煞,但是看到普通攔截器
僅僅只有一行代碼
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
這一行代碼就可以讓攔截器按照Before、After甚至是用戶自定義的Order順序進行鏈式調(diào)用柒室,這也太神奇了吧渡贾?下一節(jié)我們將挑出AspectJAfterAdvice
和MethodBeforeAdviceInterceptor
探究攔截器是如何實現(xiàn)增強與method之前的有序調(diào)用
代理方法調(diào)用流程圖: