SpringAop原始碼分析(基於註解)一
在之前的文章中,我學習了Spring Ioc的原始碼,對Spring原理有了初步瞭解,所以準備趁熱打鐵,把SpringAop的原始碼也看一遍,接下來的文章都會圍繞Aop
一、AOP原理
關於Aop的原理,簡單來講無非就是用代理模式為目標物件生產代理物件,對原有的方法進行增強。看上去挺簡單,但在Spring中,有許多細節是要注意到的。比如:
- AOP是怎麼觸發的?
- 代理物件是什麼時候生成的?
- 怎麼發現目標物件?
- 怎麼判斷目標物件的哪些方法需要增強?
- 怎麼實現前置通知,後置通知,環繞通知?
- 一個方法有多個切面代理怎麼處理?
我們可以帶著這些疑問來看原始碼,有助於我們的理解。
二、AOP術語
AOP的術語有很多並且很重要,看原始碼之前還是要對術語有所瞭解,這裡就不一一介紹了,感興趣的同學可以移步
三、demo
先來一個註解方式實現AOP的demo,然後我們後面根據這個demo來分析原始碼。
@Aspect
@Component
@EnableAspectJAutoProxy
public class LogAspect {
@Before("execution(* com.mydemo.work.StudentController.getName(..))")
public void doBefore() {
System.out.println("========before");
}
@After("execution(* com.mydemo.work.StudentController.getName(..))" )
public void doAfter() {
System.out.println("========after");
}
}
複製程式碼
這是一個簡單的日誌AOP,對StudentController類的getName(..)方法進行增強,在這個方法執行前後會列印不同的資訊。
四、準備
可以看到,在最開始的demo工程中,為了開啟AOP功能,我使用了一個@EnableAspectJAutoProxy
註解,程式碼如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import (AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
//代理的實現方式,true為CGLIB,false為JDK,預設false
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default,i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
//代理的暴露方式,解決內部呼叫不能使用代理的場景,預設為false
boolean exposeProxy() default false;
}
複製程式碼
可以看到這個註解有2個屬性proxyTargetClass
和exposeProxy
。除此之外還使用@Import註解引入了一個配置類AspectJAutoProxyRegistrar
。
我們來看下這個關鍵的類:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register,escalate,and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
<1> //註冊一個專門管理AOP的Bean到IOC容器中
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
//獲取@EnableAspectJAutoProxy註解
<2> AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata,EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
//處理該註解的2個屬性
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
複製程式碼
這段程式碼看起來不難,我們肯定要有一個處理AOP邏輯的程式碼類,那在Spring中就要把這個類交給Spring容器來管理,所以有了第<1>步。我們來看下詳細邏輯, 直接追蹤到最後呼叫的地方:
//AopConfigUtils.java
/**
* The bean name of the internally managed auto-proxy creator.
*/
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls,BeanDefinitionRegistry registry,@Nullable Object source) {
Assert.notNull(registry,"BeanDefinitionRegistry must not be null");
//檢查容器中是否已經註冊過該Bean
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
//註冊過,判斷Bean的ClassName是否為AnnotationAwareAspectJAutoProxyCreator
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//沒有註冊過,則註冊
//cls = AnnotationAwareAspectJAutoProxyCreator.class
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order",Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME,beanDefinition);
return beanDefinition;
}
複製程式碼
這段程式碼就是把AnnotationAwareAspectJAutoProxyCreator
這個類註冊到SpringIOC容器中,實際上AnnotationAwareAspectJAutoProxyCreator這個類的BeanName就是org.springframework.aop.config.internalAutoProxyCreator
。
五、註冊BeanPostProcessor
現在我們已經有了處理AOP的類AnnotationAwareAspectJAutoProxyCreator
,
先來看下這個類的繼承圖:
BeanPostProcessor
介面,這個介面大家應該很熟悉,是Spring的一個後置處理器介面。
public interface BeanPostProcessor {
//在Bean的初始化前回調
@Nullable
default Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException {
return bean;
}
//在Bean的初始化之後回撥
@Nullable
default Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException {
return bean;
}
}
複製程式碼
BeanPostProcessor
可以理解為是 Spring 的一個工廠鉤子(其實 Spring 提供一系列的鉤子,如 Aware 、InitializingBean、DisposableBean),它是 Spring 提供的物件例項化階段強有力的擴充套件點,允許 Spring 在例項化 bean 的前後對其進行修改,比較常見的使用場景是處理標記介面實現類或者為當前物件提供代理實現(例如 AOP)。
一般普通的 BeanFactory
是不支援自動註冊 BeanPostProcessor 的,需要我們手動呼叫addBeanostProcessor()方法進行註冊。如下:
beanFactory.addBeanPostProcessor(BeanPostProcessor beanPostProcessor)
複製程式碼
註冊後的 BeanPostProcessor 適用於所有該 BeanFactory 建立的 bean,但是 ApplicationContext
可以在其 bean 定義中自動檢測所有的 BeanPostProcessor 並自動完成註冊,同時將他們應用到隨後建立的任何 Bean 中。
在這裡我們的容器是ApplicationContext
,所以會自動檢測所有BeanPostProcessor
並完成註冊。接下來我們就看下自動註冊的邏輯。
我們都知道在 ApplicationContext 中有一個重要的方法refresh()
,會在容器啟動時執行,程式碼如下:
//AbstractApplicationContext.java
public void refresh() throws BeansException,IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//1、呼叫spring容器準備重新整理的方法,獲取容器的當時時間,同時給容器設定同步標識
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//2、建立並初始化 BeanFactory ----> 獲取IOC容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//3、填充BeanFactory功能。 配置容器特性,例如類載入器、事件處理器等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//4、提供子類覆蓋的額外處理,即子類處理自定義的BeanFactoryPostProcess
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//5、啟用各種BeanFactory處理器。 呼叫所有註冊的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//6、註冊BeanPostProcessor後置處理器.
//AutowiredAnnotationBeanPostProcessor(處理被@Autowired註解修飾的bean並注入)
//RequiredAnnotationBeanPostProcessor(處理被@Required註解修飾的方法)
//CommonAnnotationBeanPostProcessor(處理@PreDestroy、@PostConstruct、@Resource等多個註解的作用)等
//AutoProxyCreator(aop代理 @Aspect)
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//7、初始化資訊源,和國際化相關.
initMessageSource();
// Initialize event multicaster for this context.
//8、初始化容器事件傳播器.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//9、呼叫子類的某些特殊Bean初始化方法
onRefresh();
// Check for listener beans and register them.
//10、為事件傳播器註冊事件監聽器.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//11、初始化剩下的單例Bean(非延遲載入的)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//12、初始化容器的生命週期事件處理器,併發布容器的生命週期事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
//13、銷燬已建立的Bean
destroyBeans();
// Reset 'active' flag.
//14、取消refresh操作,重置容器的同步標識。
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core,since we
// might not ever need metadata for singleton beans anymore...
//15、重設公共快取
resetCommonCaches();
}
}
}
複製程式碼
程式碼很長,其他的暫時先不管,直接看第6步registerBeanPostProcessors(beanFactory)
,這行程式碼是需要我們關注的,它就是對 BeanPostProcessors 進行自動註冊的方法。
//PostProcessorRegistrationDelegate.java
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory,AbstractApplicationContext applicationContext) {
<1> //獲取容器中所有的BeanPostProcessor名稱
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class,true,false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation,i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
//註冊BeanPostProcessorChecker到容器中
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory,beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered,and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
<2> //遍歷所有BeanPostProcessor名稱
for (String ppName : postProcessorNames) {
//判斷當前BeanPostProcessor是否實現PriorityOrdered介面
if (beanFactory.isTypeMatch(ppName,PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName,BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//判斷當前BeanPostProcessor是否實現Ordered介面
else if (beanFactory.isTypeMatch(ppName,Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First,register the BeanPostProcessors that implement PriorityOrdered.
<3> //對實現PriorityOrdered介面的BeanPostProcessors進行排序
sortPostProcessors(priorityOrderedPostProcessors,beanFactory);
//註冊
registerBeanPostProcessors(beanFactory,priorityOrderedPostProcessors);
// Next,register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName,BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
<4> //對實現Ordered介面的BeanPostProcessors進行排序
sortPostProcessors(orderedPostProcessors,orderedPostProcessors);
// Now,register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName,BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
<5> //註冊沒有實現排序介面的BeanPostProcessors
registerBeanPostProcessors(beanFactory,nonOrderedPostProcessors);
// Finally,re-register all internal BeanPostProcessors.
<6> //排序並註冊內部BeanPostProcessors
sortPostProcessors(internalPostProcessors,beanFactory);
registerBeanPostProcessors(beanFactory,internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
複製程式碼
//PostProcessorRegistrationDelegate.java
//具體註冊方法
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory,List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
//核心
beanFactory.addBeanPostProcessor(postProcessor);
}
}
複製程式碼
這段程式碼看起來很長,但其實很簡單。
-
<1>處,先從容器中獲取所有
BeanPostProcessors
型別的BeanName。
在上一步我們已經通過@EnableAspectJAutoProxy
註解把處理AOP的Bean->internalAutoProxyCreator
給註冊到容器中了,所以這裡可以拿到。 -
<2>處,遍歷所有BeanName,進行分類,分為4類。
- 實現PriorityOrdered介面的BeanPostProcessors
- 實現Ordered介面的BeanPostProcessors
- 沒有實現排序介面的BeanPostProcessors
- Spring內部的BeanPostProcessors
我們通過
@EnableAspectJAutoProxy
註解註冊的internalAutoProxyCreator
是屬於第2類。 -
<3>處,排序並註冊實現PriorityOrdered介面的BeanPostProcessors
-
<4>處,排序並註冊實現Ordered介面的BeanPostProcessors
-
<5>處,註冊沒有實現排序介面的BeanPostProcessors
-
<6>處,排序並註冊Spring內部的BeanPostProcessors
至此,我們已經把所有的BeanPostProcessors註冊到了容器ApplicationContext
中,包括我們專門處理AOP的BeanPostProcessors,接下來就可以使用了。
總結
總結一下到目前位置的步驟:
- 通過
@EnableAspectJAutoProxy
註解把專門處理AOP的Bean註冊到IOC容器中 - 通過
ApplicationContext.refresh()
方法把專門處理AOP的BeanPostProcessors註冊到IOC容器中。
那這兩步之間有什麼關聯呢?
-
首先,我們要把專門處理AOP的Bean註冊到IOC容器中,交給spring來管理。-->@EnableAspectJAutoProxy
-
然後,通過IOC容器的
getBean()
方法生成例項AnnotationAwareAspectJAutoProxyCreator
。-->refresh() -
最後,因為該例項間接實現了
BeanPostProcessors
,而BeanPostProcessors
想起作用的話,必須要呼叫beanFactory.addBeanPostProcessor()
方法註冊到容器中。-->refresh()
下篇文章我們將分析AnnotationAwareAspectJAutoProxyCreator
類是怎麼起作用的。