源碼:
# 前言
前兩篇文章我們分析了AOP的原理,知道了AOP的核心就是代理,通知器,切點。我們也知道了XML配置方式和注解方式的底層實現都是相同的,都是通過 ProxyCreatorSupport 創建代理,但是XML是通過 ProxyFactoryBean 來實現的,而 注解是通過 BeanPostProcessor 來實現創建代理的邏輯。
我們上篇講解注解方式的文章,剖析了 AnnotationAwareAspectJAutoProxyCreator 這個類,這個類就是根據注解創建代理的默認類。那么到底該類在Spring 中是如何運行的?基于注解的 AOP 在現在流行的 SpringBoot 中是如何設計實現的?今天樓主就要以一個簡單的demo來 debug 一次源碼,徹底了解 SpringBoot 下的AOP 是如何運作的。
我們將分為幾個方面來講:
- AnnotationAwareAspectJAutoProxyCreator 后置處理器注冊過程。
- 標注 @Aspect 注解的 bean 的后置處理器的處理過程
- 創建代理的過程
- 目標對象方法調用的過程
1. AnnotationAwareAspectJAutoProxyCreator 后置處理器注冊過程
1.1 后置處理器繼承圖譜
我們先回顧一下該類的繼承圖譜 ,看圖中紅框部分,可以看到該類間接實現了 BeanPostProcessor 接口,而且也實現了 InstantiationAwareBeanPostProcessor 接口,InstantiationAwareBeanPostProcessor 接口繼承了BeanPostProcessor 接口。
我們重點看看這兩個接口的關系,InstantiationAwareBeanPostProcessor 接口通過繼承 BeanPostProcessor 擁有了父接口的兩個方法,父類的兩個方法是在bean初始化前后做一些控制,而 InstantiationAwareBeanPostProcessor 自己增加的方法則是在bean的實例化做一些控制,順序:先執行 InstantiationAwareBeanPostProcessor 自身的兩個實例化方法,再執行父接口的初始化方法。
我們看到這些方法肯定會問,BeanPostProcessor 這個接口不是在初始化前和初始化后都能做一些操作嗎,為什么只叫后置處理器,應該叫前后置處理器啊?那么我們就去看看源碼,該方法被多處重寫,我們查看重寫該方法的所有的實現,可以看到所有處理該方法的邏輯都是直接返回bean,沒有任何邏輯操作,可見該方法就是一個空方法。而 postProcessAfterInitialization 后置處理初始化方法各個實現類都有不同的操作。還有一個需要注意的的地方就是,InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個方法名稱極其相似,注意區分,BeanPostProcessor 是初始化,InstantiationAwareBeanPostProcessor 是實例化,實例化先執行,初始化后執行。
為什么大張旗鼓的說后置處理器這個事情呢?因為 AnnotationAwareAspectJAutoProxyCreator 就是后置處理器啊,他繼承了 AbstractAutoProxyCreator 抽象類,該類實現了后置處理器接口的方法。
既然是個后置處理器,那么就需要注冊,我們就看看注冊后置處理器的過程。
1.2 后置處理器注冊過程
我們會議一下Spring 容器初始化的方法 refresh ,當時我們說,該方法是整個spring 的核心代碼,所有的邏輯都是從這里作為入口,那么該方法中有注冊后置處理器的邏輯嗎?
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 為刷新準備應用上下文
prepareRefresh();
// 告訴子類刷新內部bean工廠,即在子類中啟動refreshBeanFactory()的地方----創建bean工廠,根據配置文件生成bean定義
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 在這個上下文中使用bean工廠
prepareBeanFactory(beanFactory);
try {
// 設置BeanFactory的后置處理器// 默認什么都不做
postProcessBeanFactory(beanFactory);
// 調用BeanFactory的后處理器,這些后處理器是在Bean定義中向容器注冊的
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊Bean的后處理器,在Bean創建過程中調用
registerBeanPostProcessors(beanFactory);
//對上下文的消息源進行初始化
initMessageSource();
// 初始化上下文中的事件機制
initApplicationEventMulticaster();
// 初始化其他的特殊Bean
onRefresh();
// 檢查監聽Bean并且將這些Bean向容器注冊
registerListeners();
// 實例化所有的(non-lazy-init)單件
finishBeanFactoryInitialization(beanFactory);
// 發布容器事件,結束refresh過程
finishRefresh();
} catch (BeansException ex) {
// 為防止bean資源占用,在異常處理中,銷毀已經在前面過程中生成的單件bean
destroyBeans();
// 重置“active”標志
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
resetCommonCaches();
}
}
}
我們看一下代碼,可以看到,其中有一行代碼,registerBeanPostProcessors(beanFactory),注冊后置處理器,攜帶BeanFactory參數,該方法會調用 PostProcessorRegistrationDelegate 的一個靜態方法:
該靜態方法很長,主要邏輯就是,從BeanFactory 中找到所有實現了 BeanPostProcessor 接口的bean,然后添加進集合,最后調用自身的 registerBeanPostProcessors 靜態方法,循環調用 beanFactory 的addBeanPostProcessor 方法,將后置處理器添加進bean工廠。
bean工廠的 addBeanPostProcessor 方法如下:
將后置處理器放在一個集合中,并保證只有一個不會重復。然后判斷是否 InstantiationAwareBeanPostProcessor 類型的后置處理器,如果有,就將狀態hasInstantiationAwareBeanPostProcessors 改為 true。
這個時候也就是完成了后置處理器的注冊過程。
2. 標注 @Aspect 注解的 bean 的后置處理器的處理過程
我們在使用 @Aspec 同時也會使用類似 @Component 的注解,表示這是一個Bean,只要是bean,就會調用getBean方法,只要調用 getBean 方法,都會調用 AbstractAutowireCapableBeanFactory 的 createBean 方法,該方法其中有一行函數調用:
注釋說,會返回一個代理,我們看看該方法到底是什么邏輯:
我們注意看該方法的 if 判斷,hasInstantiationAwareBeanPostProcessors, 就是判斷我們剛剛設置的狀態,向下走,獲取到Bean的類型,先調用 applyBeanPostProcessorsBeforeInstantiation 方法,如果該方法有返回值,則調用 applyBeanPostProcessorsAfterInitialization 方法,注意,上面調用的是 “實例化前方法”,下面那個調用的是 “初始化后方法”,是不同的接口實現。通常在第一次調用的的時候,是不會有返回值的。我們看看該方法實現:
該方法會獲取所有的后置處理器,就是之前注冊在BeanFactory 的后置處理器,并循環調用他們的 postProcessBeforeInstantiation 方法,但是還是要判斷是不是 InstantiationAwareBeanPostProcessor 類型,我們關注的當然是我們在之前的說的 AbstractAutoProxyCreator 后置處理器,我們看看他的 postProcessBeforeInstantiation 方法:
該方法首先檢驗參數,如果緩存中存在的話就直接返回。如果不在,則判斷該bean的類型是否是基礎類型,上面是基礎類型? 我們看代碼:
該方法首先調用父類的的 isInfrastructureClass 方法,然后調用 isAspcet 方法。我們看看這兩個方法的實現:
isInfrastructureClass
判斷是否是這幾個基礎類。
isAspect
判斷該類是否含有Aspect 注解并且該類屬性中含有 “ajc$” 開頭的成員變量。
那么后面的那個判斷呢?shouldSkip ,字面意思:是否應該跳過。 該方法默認實現是false,但該類注釋說,子類需要重寫該方法。我們看看該方法是如何重寫的:
首先找到所有候選的通知器,然后循環通知器數組,如果該通知器是 AspectJPointcutAdvisor 類型,并且該通知器的通知的切面名稱和bean的名字相同,就返回 true。重點在如果獲取通知器,在XML配置中,我們知道,通知器是我們顯式的實現了 PointcutAdvisor 接口的類,并在配置文件中配置。而這里我們沒有配置。Spring 是如何找到的呢?我們看看 findCandidateAdvisors 方法,該方法委托了 advisorRetrievalHelper 調用 findAdvisorBeans 方法,我們看看該方法實現。
注意:findCandidateAdvisors 方法被重寫了,我們看子類實現。
子類方法比父類方法多了一行 buildAspectJAdvisors。
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
該方法會通過 BeanFactoryUtils.beanNamesForTypeIncludingAncestors 方法獲取容器中所有實現了Advisor 接口的Bean,然而我們的demo程序里上面都沒有。如果是XML就會返回了。
那我們看第二行的 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()方法,該方法根據注解創建通知器。我們看看該方法邏輯:
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
方法很長,我們看看主要邏輯:先調用靜態方法 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false) ,也就是獲取容器中所有的bean,然后循環處理每個bean。這個 buildAspectJAdvisors 有個注意的地方就是,每次執行該方法,最后都會更新 aspectBeanNames 屬性,該屬性是通知器的名稱集合。在循環中,會先創建一個 AspectMetadata 切面元數據對象,然后創建 BeanFactoryAspectInstanceFactory 對象,在使用 advisorFactory 的 getAdvisors 方法攜帶剛剛創建的 factory 對象獲取該Class 對應的所有 通知器。
我們看看 getAdvisors 的標準實現:
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
在 getAdvisors 方法中,會先根據Bean 的Class,比如 Aop.class,和 切面名稱,也就是benaNanme,然后根據class,獲取所有不帶 @Pointcut.class 的 Method 對象集合,也就是 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 這些注解。拿到這些方法數組后,進行循環處理,調用自己的 getAdvisor 方法,我們看看 getAdvisor 方法。
@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
在該方法中,則根據method 對象獲取Pointcut,getPointcut 會將該方法上面的注解解析成一個 AspectJExpressionPointcut 切面表達式切入點對象,最后 getAdvisor 將所有參數和 剛剛創建的對象 包裝成 InstantiationModelAwarePointcutAdvisorImpl 對象也就是 Advisor 的子類 返回。
回到 getAdvisors 方法中, 該方法會將 getAdvisor 方法的返回值添加到 Advisors 數組中,然后如果數組不為空的話,創建一個合成的,沒有作用的通知器。 然后,循環切面類的所有屬性,解析含有 DeclareParents 注解的成員變量。
至此,得到了該類所有的通知器。然后放入緩存。最后 ,將 aspectBeanNames 屬性重新賦值。并返回 advisors。
回到 findCandidateAdvisors 方法,也就是尋找候選的通知器。然后將創建的通知器返回。
回到 AbstractAutoProxyCreator 的 postProcessBeforeInstantiation 的方法, 該方法的 shouldSkip 判斷返回false, 沒能進入if塊返回,繼續向下走。
首先尋找 Bean 的目標類,我們并沒有設置目標類,然后,就返回null。至此,resolveBeforeInstantiation 方法返回了null。并沒有像注釋說的返回一個代理,除非設置了 customTargetSourceCreators。雖然這里也能創建代理。而該方法也就結束了。該方法主要執行了后置處理器的 “實例化之前” 方法。
3. 創建代理的過程
在執行完 resolveBeforeInstantiation 返回 null 之后,就執行 doCreateBean 方法,我們很熟悉這個方法,該方法在調用 populateBean 方法后完成了依賴注入,然后進行初始化, 調用 initializeBean 方法。
initializeBean 方法
initializeBean 方法中調用了3個重要的邏輯,applyBeanPostProcessorsBeforeInitialization 方法 , 和 invokeInitMethods 方法(如果實現了InitializingBean 接口,則會調用 afterPropertiesSet 方法),還有重要的 applyBeanPostProcessorsAfterInitialization 方法。
首先調用了前置處理器的 postProcessBeforeInitialization 方法,簡單的返回了bean。
然后判斷是否實現 InitializingBean 接口從而決定是否調用 afterPropertiesSet 方法。
最后到了最重要的 applyBeanPostProcessorsAfterInitialization 方法, 該方法會循環調用每個bean的后置處理器的 postProcessAfterInitialization 方法。
現在,來到了我們熟悉的 postProcessAfterInitialization 方法,該方法重寫了 BeanPostProcessor 接口的方法,然后進入到 wrapIfNecessary 方法。
首先判斷是否 targetSourcedBeans 目標bean 集合中是否存在,有則直接返回。
再判斷對應的bean是否含有通知器。
再判斷是不是基礎類,我們之前看過了,如果有,則返回true。也就會直接返回bean。或則調用 shouldSkip 方法判斷,如果其中某個通知器 實現了AspectJPointcutAdvisor 接口,則返回 true。我們的Bean 兩者都不是,所以都是false,向下走。
這里就是我們曾經分析過的代碼,今天再分析一下,主要還是創建代理。首先獲取所有的通知器。如果在后置處理器注冊的時候該Bean沒有設置通知器,則不會創建代理。然后還有就是我們之前注冊的后置處理器了。如過后置處理不是null,則再緩存中存儲bean的名字和是否有通知器的boolean值,再創建完代理后,將代理類和bean的名字存入代理類型緩存。以便以后可以隨時實例化代理。
createProxy 是我們的老朋友,首先判斷 BeanFactory 是否實現了 ConfigurableListableBeanFactory 接口,默認是實現了的。調用 AutoProxyUtils.exposeTargetClass 方法,
然后創建 ProxyFactory 實例,這個我們分析過了,然后將 AnnotationAwareAspectJAutoProxyCreator 數據復制到 ProxyFactory 中。
buildAdvisors 創建通知器數組,根據bean的名稱,和剛剛注冊的通知器。我們看看該方法,該方法首先調用 resolveInterceptorNames 方法,生成通知器數組,但我們沒有設置該屬性(XML 配置曾經設置過)。 然后將我們給定的通知器添加到一個數組,然后判斷,如果配置了通知器,則將配置的通知器放在數組前面, 否則就放在后面。
最后,循環該通知器數組,調用 advisorAdapterRegistry 的warp 方法,包裝通知器。最后返回,如何包裝呢?
我們看看warp 方法,判斷如果是Advisor 類型,則直接返回,如果不是Advice類型,拋出異常,如果是,則判斷是否是 MethodInterceptor 類型,如果是,則包裝成 DefaultPointcutAdvisor 類型返回。如果都不滿足,則循環該類的adappters 適配器數組, 判斷如果支持 Advice ,則也創建一個默認的 DefaultPointcutAdvisor 返回。該適配器數組,默認就有3個適配器,一個before,一個after,一個throws。而我們的通知器都是 Advisor,所以直接返回了。
到這里 buildAdvisors 方法也就結束了,返回了一個Advisors 數組。
回到 createProxy 方法, 得到了注冊的通知器,于是 proxyFactory 可以設置 通知器屬性了,也設置了目標類屬性,這時候就可以拿著工廠去創建代理了。
如何創建代理工廠我們就不看了,因為我們之前已經分析過了,我們的demo肯定創建的是 Cglib 代理,因此我們進入到Cglib 的getProxy 方法中查看。
@Override
public Object getProxy(ClassLoader classLoader) {
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...
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 ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
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);
}
}
首先判斷是否是Cglib類型,怎么判斷呢?就判斷類名中是否含有兩個$$ 符號,如果是的,則從當前類中獲取所有接口,并添加到 advised 屬性中,很明顯,我們不是。
然后校驗Class,寫日志。
創建一個增強器。是 org.springframework.cglib.proxy 包下的。給增強器設置類加載器,設置父類,設置接口,設置命名規則,默認是 BySpringCGLIB,設置策略(不知道是什么意思),,設置回調類型(七個回調,都是CglibAopProxy 的內部類),設置了回調的過濾器,最后創建代理,再下面我們就不深究了。
我們從整個流程可以看到,AOP的編織是通過定義@Aspect 和 @Around 等注解創建通知器,和我們在XML中編程幾乎一樣,只是Sprng 向我們屏蔽了底層。最后,Spring 拿著目標類和通過器去創建代理。
4. 目標對象方法調用的過程
那么創建代理后做什么呢?
這時候就需要調用被 @PostConstruct 注解 的方法了,該注解的作用就是在Spring 實例化該bena后執行該方法。
此時返回的已經是代理類了,代理類執行testController 方法,代理類內部回調了 CglibAopProxy 的內部類 DynamicAdvisedInterceptor 的 intercept 方法,
@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) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
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) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
首先獲取目標類, 然后傳入目標方法和 目標類獲取通知器鏈, 最終調用 DefaultAdvisorChainFactory 的 getInterceptorsAndDynamicInterceptionAdvice 方法, 該方法參數為 AdvisedSupport, 目標方法,目標類。我們進入該方法查看:
@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;
}
首先調用 hasMatchingIntroductions 方法,返回false,該方法會判斷通知器是否是 IntroductionAdvisor 類型,如果是,則判斷類過濾器是否匹配當前的目標類型。我們這里不是 IntroductionAdvisor 類型,因此都返回false。然后獲取全局的三個通知器適配器,然后循環匹配,最后將匹配成功的包裝到 InterceptorAndDynamicMethodMatcher 中后添加到攔截器數組中。
回到 intercept ,得到了攔截器數組,如果攔截器數組是空的并且方法修飾符是public 的,就直接調用該方法,如果不是,則創建一個Cglib 方法調用器。并執行proceed方法,
由于我們的方法不是public 的,則執行 else 邏輯,我們看看該 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); // 執行這里
}
}
proceed 方法會先獲取第一個攔截器,如果攔截器不是 InterceptorAndDynamicMethodMatcher 類型的,則執行攔截器的invoke 方法。
在invoke 方法中,先將 mehodInvocation 對象放置在ThreadLocal 中,然后又回調自己的proceed方法,判斷當前攔截器下標是否到了最大。再次執行的攔截器也就是通知器是 AspectJAroundAdvice 的invoke 方法,也就是我們定義的@Around 注解的方法。
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}
首先創建一個我們熟知的 ProceedingJoinPoint 對象,然后調用 invokeAdviceMethod 方法,是其抽象父類的AbstractAspectJAdvice 的方法。該方法繼續調用invokeAdviceMethodWithGivenArgs 方法。
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
終于,在這里調用我們的test方法了。執行反射方法this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs) 。
然后回調自己的proceed 方法,回到了 ReflectiveMethodInvocation 的 proceed 方法,繼續判斷是否還有攔截器,沒有則執行 invokeJoinpoint 方法,也就是目標類本身的方法。
如果方法是public 的,則直接執行方法代理的invoke方法,如果不是,執行父類的 invokeJoinpoint 方法, 實際上是執行的 AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments) 方法,該方法執行反射方法 method.invoke ,最終執行目標方法。
最終返回到攔截器的方法中,也就是我們的Aop.tesst 方法,繼續執行下面的邏輯。
執行完畢,AbstractAspectJAdvice 通知器的invokeAdviceMethod 的方法結束,開始逐層返回。返回到 intercept 方法, 繼續向下執行。下面就是一些處理返回值的邏輯,最后返回返回值。完成了代理的一次調用。
5. 總結
這篇文章可以說是非常的長,從 AOP 的切面編織,到代理的生成,到方法的調用,可以說,非常的復雜。 不過,Spring 中最復雜的 AOP 我們已經徹底搞清楚了他的原理,功夫不負苦心人。不論是老舊的 XML 配置方式,還是新的 SpringBoot 方式,我們都能夠了解他的原理,在以后的程序排錯中,也更加游刃有余,實際上,我們得到的不止是這個,我們知道了Spring 的眾多擴展接口,這些接口是AOP 賴以生存的條件,正式通過他們,完成了AOP的增強。我們也知道了,無論是注解還是配置文件,都是依賴同一個底層原理,這也警醒了我們,無論多么復雜的系統,底層都是相似的,通過層層封裝后變得更加好用的同時也變得難以理解,但只要明白底層原理,一切都沒那么復雜,樓主認為底層原理更是網絡,OS,計組,編譯原理,數據結構這些。山高路遠,我們將一直走下去。
good luck !!!!!