寫在AOP之前
實現MethodInterceptor接口,重寫intercept方法
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
至此,註冊了AnnotationAwareAspectJAutoProxyCreator到容器中。
可以看到,AnnotationAwareAspectJAutoProxyCreator是一個BeanPostProcessor後置處理器,並且實現了Ordered接口
它的父類AbstractAutoProxyCreator重寫了postProcessBeforeInitialization和postProcessAfterInitialization方法
接下來,在初始化Bean的時候,會調用這個BeanPostProcessor的初始化後處理
然後進到AbstractBeanFactory的getBean()方法,最終進到Bean的初始化方法
調用AbstractAutoProxyCreator的postProcessAfterInitialization方法
獲取以上Bean裏的所有Advisor,方法和Advisor一對一
方法1獲取類裏所有的沒有@Pointcut註解的Method(可能包含普通的方法),可能是以下幾種:
方法2獲取以上通知方法的expressionPointcut 切點表達式(普通方法會被過濾掉)
遍歷所有的Advisors,是否有任意的Advisors的切點matches(當前的bean)。篩選出所有matches的Advisor
方法1:檢查目標對象是否實現了接口,如果是則調用proxyFactory.addInterface(ifc);方法,這樣在後面的判斷hasNoUserSuppliedProxyInterfaces(config)時就爲false
如果否則設置proxyTargetClass屬性爲true(只有在proxyTargetClass=false的情況下才會進到此方法)
3.可以通過配置文件指定對接口使用CGLIB生成代理(配置proxy-target-class=true)
默認使用JDK自帶的Proxy生成代理,碰到以下三種情況例外:
1.ProxyConfig的isOptimize方法爲true,這表示讓Spring自己去優化而不是用戶指定
2.ProxyConfig的isProxyTargetClass方法爲true,這表示配置了proxy-target-class="true"
3.ProxyConfig滿足hasNoUserSuppliedProxyInterfaces方法執行結果爲true,這表示<bean>對象沒有實現任何接口或者實現的接口是SpringProxy接口
注:SpringBoot的AOP是自動開啓的(spring.aop.auto = true)
可配置spring.aop.proxy-target-class = true強制使用CGLIB動態代理
Proxy.newProxyInstance()方法是執行的關鍵,有三個參數:
底層實際是調用InvocationHandler.invoke()方法,在這裏,也就是調用JdkDynamicAopProxy.invoke()方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
// 如果 expose-proxy 屬性爲 true,則暴露代理對象
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 如果方法返回值爲 this,即 return this; 則將代理對象 proxy 賦值給 retVal
// 如果返回值類型爲基礎類型,比如 int,long 等,當返回值爲 null,拋出異常
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);
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
AopContext.setCurrentProxy(oldProxy);
1. 檢測 expose-proxy 是否爲 true,若爲 true,則暴露代理對象
4. 若攔截器鏈不爲空,則創建方法調用器 ReflectiveMethodInvocation 對象
5. 調用 ReflectiveMethodInvocation 對象的 proceed() 方法啓動攔截器鏈
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this.methodCache.put(cacheKey, cached);
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
// registry 爲 DefaultAdvisorAdapterRegistry 類型
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
* 調用 ClassFilter 對 bean 類型進行匹配,無法匹配則說明當前通知器
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 將 advisor 中的 advice 轉成相應的攔截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
// 若 isRuntime 返回 true,則表明 MethodMatcher 要在運行時做一些檢測
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
interceptorList.addAll(Arrays.asList(interceptors));
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
// IntroductionAdvisor 類型的通知器,僅需進行類級別的匹配即可
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
* 若 advice 是 MethodInterceptor 類型的,直接添加到 interceptors 中即可。
* 比如 AspectJAfterAdvice 就實現了 MethodInterceptor 接口
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
* 對於 AspectJMethodBeforeAdvice 等類型的通知,由於沒有實現 MethodInterceptor
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
throw new UnknownAdviceTypeException(advisor.getAdvice());
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
2. 若緩存未命中,則調用 getInterceptorsAndDynamicInterceptionAdvice 獲取攔截器鏈
4. 對於 PointcutAdvisor 類型的通知器,這裏要調用通知器所持有的切點(Pointcut)對類和方法進行匹配,匹配成功說明應向當前方法織入通知邏輯
5. 調用 getInterceptors 方法對非 MethodInterceptor 類型的通知進行轉換(如:@Before @AfterReturning @AfterThrowing)
接下來就是調用 ReflectiveMethodInvocation 對象的 proceed() 方法啓動攔截器鏈
interceptorOrInterceptionAdvice).invoke(this);
這裏會先執行一個默認MethodInterceptor的invoke()方法,即ExposeInvocationInterceptor
然後遞歸調用ReflectiveMethodInvocation.proceed()方法,以@Before前置通知爲例:
此時這裏調用的是MethodBeforeAdviceInterceptor.invoke()方法
先執行前置通知切面邏輯,然後遞歸調用下一個攔截器的invoke()方法
https://blog.csdn.net/qq_32331073/article/details/80596084
方法執行的時候,實際上是回調的CglibAopProxy.DynamicAdvisedInterceptor.intercept()方法。
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) {
// 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 = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
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 && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1. 檢測 expose-proxy 是否爲 true,若爲 true,則暴露代理對象
3. 如果攔截器鏈爲空並且該方法是public修飾的,則直接通過反射執行目標方法
4. 若攔截器鏈不爲空,則創建方法調用器 CglibMethodInvocation 對象