文章目錄
- 前言
- 相關Spring的定義接口
- 整體代碼
- StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh")
- prepareRefresh()
- obtainFreshBeanFactory()
- registerBeanPostProcessors(beanFactory)
- SpringAOP原碼流程
- @EnableAspectJAutoProxy
- AnnotationAwareAspectJAutoProxyCreator的創建時機
- AnnotationAwareAspectJAutoProxyCreator的執行時機
- 被代理方法的執行流程
前言
Spring 由17個方法構成,本文一以GenericApplicationContext為例
相關Spring的定義接口
- ImportBeanDefinitionRegistrar
可以向容器注冊自定義的RootBeanDefinition - BeanDefinitionRegistryPostProcessor
- BeanFactoryPostProcessor
在BeanDefinitionRegistryPostProcessor方法執行后執行 - BeanPostProcessor
- InstantiationAwareBeanPostProcessor
- SmartInstantiationAwareBeanPostProcessor
整體代碼
public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);beanPostProcess.end();this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var10) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);}this.destroyBeans();this.cancelRefresh(var10);throw var10;} finally {this.resetCommonCaches();contextRefresh.end();}}}
StartupStep contextRefresh = this.applicationStartup.start(“spring.context.refresh”)
this.applicationStartup初始化 :
ApplicationStartup.DEFAULT :
ApplicationStartup DEFAULT = new DefaultApplicationStartup();
prepareRefresh()
protected void prepareRefresh() {this.startupDate = System.currentTimeMillis();this.closed.set(false);//設置關閉狀態為真this.active.set(true);//設置存活狀態為真if (this.logger.isDebugEnabled()) {if (this.logger.isTraceEnabled()) {this.logger.trace("Refreshing " + this);} else {this.logger.debug("Refreshing " + this.getDisplayName());}}this.initPropertySources(); //自身空實現,留給子類重寫this.getEnvironment().validateRequiredProperties();if (this.earlyApplicationListeners == null) {this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);//創建早期容器監聽者} else {this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);//創建容器監聽者}this.earlyApplicationEvents = new LinkedHashSet();//創建早期事件存放容器
}
this.getEnvironment().validateRequiredProperties() 整體解析:
獲取環境變量及系統變量
this.getEnvironment().validateRequiredProperties() 中 getEnvironment() :
- getEnvironment()
public ConfigurableEnvironment getEnvironment() {if (this.environment == null) {this.environment = this.createEnvironment();}return this.environment;
}
- createEnvironment() :
return new StandardEnvironment();
public class StandardEnvironment extends AbstractEnvironment {public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";public StandardEnvironment() { //空構造調用父類構造,由父類調用customizePropertySources方法}protected StandardEnvironment(MutablePropertySources propertySources) {super(propertySources);}protected void customizePropertySources(MutablePropertySources propertySources) {propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));//獲取系統的參數變量propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));//獲取系統環境變量}
}
- AbstractEnvironment 構造器 :
public AbstractEnvironment() {this(new MutablePropertySources()); //調用下面構造方法}protected AbstractEnvironment(MutablePropertySources propertySources) {this.logger = LogFactory.getLog(this.getClass());this.activeProfiles = new LinkedHashSet();this.defaultProfiles = new LinkedHashSet(this.getReservedDefaultProfiles());this.propertySources = propertySources; //將propertySources賦值給本地propertySources變量this.propertyResolver = this.createPropertyResolver(propertySources);this.customizePropertySources(propertySources); //調用子類StandardEnvironment的customizePropertySources}
總之是new 一個 StandardEnvironment
類然后調用其的customizePropertySources
方法返回該 StandardEnvironment
類
this.getEnvironment().validateRequiredProperties() 中的validateRequiredProperties():
調用的是之前返回的 StandardEnvironment
的父類AbstractEnvironment
propertyResolver屬性的validateRequiredProperties的方法 :
propertyResolver.validateRequiredProperties();
propertyResolver
屬性是在上面創建StandardEnvironment
時候調用其父類AbstractEnvironment(MutablePropertySources propertySources)
構造中創建賦值的 :
this.propertyResolver = this.createPropertyResolver(propertySources);
而 createPropertyResolver(propertySources)
則只是調用一個new PropertySourcesPropertyResolver(propertySources);
validateRequiredProperties()方法最終調用的是PropertySourcesPropertyResolver
的validateRequiredProperties方法
而PropertySourcesPropertyResolver 的validateRequiredProperties方法本身沒有實現是繼承父類的 AbstractPropertyResolver
實現
最終this.getEnvironment().validateRequiredProperties()實現方法是AbstractPropertyResolver.validateRequiredProperties()
:
public void validateRequiredProperties() {MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();Iterator var2 = this.requiredProperties.iterator();while(var2.hasNext()) {String key = (String)var2.next();if (this.getProperty(key) == null) {ex.addMissingRequiredProperty(key);}}if (!ex.getMissingRequiredProperties().isEmpty()) {throw ex;}
}
從requiredProperties
中遍歷值并且判斷是否在系統或環境變量存在該值
requiredProperties:
AbstractPropertyResolver的一個屬性
private final Set<String> requiredProperties = new LinkedHashSet();
總結作用 :
Spring容器初始化的時候,會從集合requiredProperties中取出所有key,然后獲取這些key的環境變量(包括系統環境變量和進程環境變量),如果有一個key對應的環境變量為空,就會拋出異常,導致spring容器初始化失敗;
實戰中使用 :
看了AbstractPropertyResolver類的validateRequiredProperties方法源碼后,可以確定該方法能強制要求一些環境變量必須存在,否則停止spring啟動,我們只要把我們認為必要的環境變量的key存入集合requiredProperties中即可,達到此目標需要解決下面兩個問題:
- 如何將環境變量的key存入集合requiredProperties?
調用AbstractPropertyResolver類的setRequiredProperties方法,注意該方法是向集合requiredProperties中添加數據,并不會將已有數據清除; - 在什么時候執行AbstractPropertyResolver類的setRequiredProperties方法設置key?
創建一個AbstractApplicationContext的子類,重寫initPropertySources方法,在此方法中執行AbstractPropertyResolver類的setRequiredProperties;
創建一個自定義ApplicationContext 并重寫initPropertySources方法:
public void main() {CustomApplicationContext customApplicationContext = new CustomApplicationContext();customApplicationContext.refresh();}public class CustomApplicationContext extends GenericApplicationContext {@Overrideprotected void initPropertySources() {super.initPropertySources();//把"MYSQL_HOST"作為啟動的時候必須驗證的環境變量getEnvironment().setRequiredProperties("MYSQL_HOST");}}
上面寫過initPropertySources實在 prepareRefresh() 時候調用 :
obtainFreshBeanFactory()
獲取BeanFactory并刷新
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {this.refreshBeanFactory();return this.getBeanFactory();
}
- refreshBeanFactory()內容 :
if (!this.refreshed.compareAndSet(false, true)) {throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");} else {this.beanFactory.setSerializationId(this.getId());}
- getBeanFactory()
返回 GenericApplicationContext 中的 DefaultListableBeanFactory beanFactory 屬性
beanFactory 在 GenericApplicationContext 創建的時候創建的 :
public GenericApplicationContext() {this.customClassLoader = false;this.refreshed = new AtomicBoolean();this.beanFactory = new DefaultListableBeanFactory();
}
registerBeanPostProcessors(beanFactory)
SpringAOP原碼流程
@EnableAspectJAutoProxy
首先需了解@EnableAspectJAutoProxy
:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {boolean proxyTargetClass() default false;}
它通過@Import(AspectJAutoProxyRegistrar.class)
導入了一個AspectJAutoProxyRegistrar
組件:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAJAutoProxy \=attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}}}
它實現了ImportBeanDefinitionRegistrar接口,這個接口可以向IOC容器中注冊bean。 由此可以推測aop利用AspectJAutoProxyRegistrar自定義給容器中注冊bean;BeanDefinetion
進入registerAspectJAnnotationAutoProxyCreatorIfNecessary
方法,發現它給容器中注冊了一個名為org.springframework.aop.config.internalAutoProxyCreator
,實例為AnnotationAwareAspectJAutoProxyCreator
的類。
AnnotationAwareAspectJAutoProxyCreator的創建時機
查看AnnotationAwareAspectJAutoProxyCreator
的繼承關系圖
在此需要關注兩點內容:
- 關注后置處理器SmartInstantiationAwareBeanPostProcessor(在bean初始化完成前后做事情)
- 關注自動裝配BeanFactory。
注意 :SmartInstantiationAwareBeanPostProcessor
是BeanPostProcessor
的一個子接口
因此AnnotationAwareAspectJAutoProxyCreator的創建時機:
1)、傳入配置類,創建ioc容器2)、注冊配置類,調用refresh()刷新容器;3)、registerBeanPostProcessors(beanFactory);注冊bean的后置處理器來方便攔截bean的創建;1)、先獲取ioc容器已經定義了的需要創建對象的所有BeanPostProcessor2)、給容器中加別的BeanPostProcessor3)、優先注冊實現了PriorityOrdered接口的BeanPostProcessor;4)、再給容器中注冊實現了Ordered接口的BeanPostProcessor;5)、注冊沒實現優先級接口的BeanPostProcessor;6)、注冊BeanPostProcessor,實際上就是創建BeanPostProcessor對象,保存在容器中;創建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】1)、創建Bean的實例2)、populateBean;給bean的各種屬性賦值3)、initializeBean:初始化bean;1)、invokeAwareMethods():處理Aware接口的方法回調2)、applyBeanPostProcessorsBeforeInitialization():應用后置處理器的postProcessBeforeInitialization()3)、invokeInitMethods();執行自定義的初始化方法4)、applyBeanPostProcessorsAfterInitialization();執行后置處理器的postProcessAfterInitialization();4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)創建成功;--》aspectJAdvisorsBuilder7)、把BeanPostProcessor注冊到BeanFactory中;beanFactory.addBeanPostProcessor(postProcessor);
在上面步驟
獲取ioc容器已經定義了的需要創建對象的所有BeanPostProcessor
中,因為AnnotationAwareAspectJAutoProxyCreator實現了SmartInstantiationAwareBeanPostProcessor接口,而SmartInstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口,并且@EnableAspectJAutoProxy注冊了AnnotationAwareAspectJAutoProxyCreator的BeanDefinetion進容器,所以此步驟能獲取到AnnotationAwareAspectJAutoProxyCreator的BeanDefinetion
AnnotationAwareAspectJAutoProxyCreator的執行時機
AnnotationAwareAspectJAutoProxyCreator是一個后置處理器,可以猜測它在其他bean的初始化前后進行了特殊處理。我在它父類的postProcessBeforeInstantiation方法進行了斷點調試,其方法調用棧如下:
finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;創建剩下的單實例bean1)、遍歷獲取容器中所有的Bean,依次創建對象getBean(beanName);getBean->doGetBean()->getSingleton()->createBean()2)、createBean()創建bean【AnnotationAwareAspectJAutoProxyCreator在所有bean創建之前會有一個攔截,InstantiationAwareBeanPostProcessor, 會調用postProcessBeforeInstantiation()】1)、先從緩存中獲取當前bean,如果能獲取到,說明bean是之前被創建過的,直接使用,否則再創建;只要創建好的Bean都會被緩存起來2)、createBean();創建bean;AnnotationAwareAspectJAutoProxyCreator 會在任何bean創建之前先嘗試返回bean的實例【BeanPostProcessor是在Bean對象創建完成初始化前后調用的】【InstantiationAwareBeanPostProcessor是在創建Bean實例之前先嘗試用后置處理器返回對象的】1)、resolveBeanClass()加載bean的class文件2)、resolveBeforeInstantiation();解析BeforeInstantiation希望后置處理器在此能返回一個代理對象;如果能返回代理對象就使用,如果不能就繼續創建1)、后置處理器先嘗試返回對象;InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation如果返回對象就再繼續執行BeanPostProcessor#postProcessAfterInitialization,返回bean3)、doCreateBean(beanName, mbdToUse, args);真正的去創建一個bean實例1)、createBeanInstance();實例化beanpopulateBean();屬性注入initializeBean();初始化,執行各種生命周期方法和創建代理等
在步驟resolveBeforeInstantiation()
,一般自定義的bean在此都不會獲取到實例,此步驟有印象即可。
再深入解析initializeBean()
方法 :
initializeBean()
如果bean實現了相關的接口,就調用執行相關接口1)、invokeAwareMethods;執行BeanNameAware BeanClassLoaderAware BeanFactoryAware接口2)、applyBeanPostProcessorsBeforeInitialization;執行BeanPostProcessor#postProcessBeforeInitialization3)、invokeInitMethods; 執行初始化方法4)、applyBeanPostProcessorsAfterInitialization;BeanPostProcessor#postProcessAfterInitialization;創建代理
這里重點關注AnnotationAwareAspectJAutoProxyCreator類,其postProcessAfterInitialization方法在其父類AbstractAutoProxyCreator實現。
直接進入AbstractAutoProxyCreator#postProcessAfterInitialization
,代理創建入口就在此:
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);// earlyProxyReferences是一個ConcurrentHashMap,里面存放的是已經生成的代理// 里面存放的是已經生成的代理(三級緩存可能會提前生成代理),如果有不會重復生成。if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}
進入wrapIfNecessary
,這里是創建代理的關鍵方法:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}// advicedBeans表示已經判斷過的bean,false表示此Bean不需要進行AOP,直接返回if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}// 當前正在創建的Bean不用進行AOP,比如切面Bean/*如果是基礎設施類(Pointcut、Advice、Advisor 等接口的實現類),或是應該跳過的類,則不應該生成代理,此時直接返回 bean,也就是代理不能給自己再加代理 就是不套娃AspectJAwareAdvisorAutoProxyCreator#shouldSkip*/if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.// 查詢當前bean匹配的Advice,找切面的過程(判斷當前實例化的bean是否有切面,如果有則將切面返回)返回類型為 Advisor// postProcessBeforeInstantiation方法也會調用 ;AbstractAdvisorAutoProxyCreator實現Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// 如果有切面,則生成bean的代理if (specificInterceptors != DO_NOT_PROXY) {// advisedBeans記錄了某個Bean已經進行過AOP了this.advisedBeans.put(cacheKey, Boolean.TRUE);// 創建代理,把被代理對象bean的實例封裝到SingletonTargetSource中,生成當前實例化bean的代理對象// 傳入的bean是被代理實例,SingletonTargetSource持有了被代理實例的引用(一級緩存單例池中存的就是代理對象)Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());// 將代理對象返回return proxy;}// 沒有代理的情況,就是falsethis.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;
}
第一次進入shouldSkip
方法會查詢Spring容器內的所有@Aspecj相關的類,并將其相關方法注冊成Advisor,并緩存起來,以便下次直接獲取。
總結 :
通過@EnableAspectJAutoProxy注入AnnotationAwareAspectJAutoProxyCreator
,其實現了BeanFactoryAware
和SmartInstantiationAwareBeanPostProcessor
接口,間接實現了InstantiationAwareBeanPostProcessor
和BeanPostProcessor
;
在Spring容器刷新時候調用registerBeanPostProcessors
方法注冊進容器;
在Spring創建完成Bean,執行生命周期后置處理器BeanPostProcessor#postProcessAfterInitialization
時候,會調進入AnnotationAwareAspectJAutoProxyCreator
執行代理創建邏輯,并返回需要的代理。
繼續深入研究wrapIfNecessary
首先判斷當前類是否需要代理,或者已經被代理過,返回原類。
重點關注getAdvicesAndAdvisorsForBean
方法,實現在AbstractAdvisorAutoProxyCreator類:
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {// 找到候選的切面,就是尋找帶有@Aspect注解的過程,把帶有@Aspect的類封裝成Advisor返回List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray();
}
findEligibleAdvisors
方法尋找當前類匹配的Advisor,進入findEligibleAdvisors
方法 :
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {// 找到候選的切面,就是尋找帶有@Aspect注解的過程,把帶有@Aspect的類封裝成Advisor返回List<Advisor> candidateAdvisors = findCandidateAdvisors(); //如果是通過@Aspect注解開啟切面,子類AnnotationAwareAspectJAutoProxyCreator方法// 判斷候選的切面是否作用在當前beanClass上面,就是一個匹配的過程List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);// 針對有@Aspect注解的類添加一個默認的切面--->DefaultPointcutAdvisor,解決參數傳遞問題// 進入AspectJAwareAdvisorAutoProxyCreator類的extendAdvisors()方法extendAdvisors(eligibleAdvisors); // AspectJAwareAdvisorAutoProxyCreatorif (!eligibleAdvisors.isEmpty()) {// 對有@Order、@Priority注解的類進行排序eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;
}
進入AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
:
protected List<Advisor> findCandidateAdvisors() {// Add all the Spring advisors found according to superclass rules.// 先找到所有Advisor類型的Bean,調用父類resolveBeforeInstantiation方法進入的話實現類是AbstractAdvisorAutoProxyCreator#findCandidateAdvisorsList<Advisor> advisors = super.findCandidateAdvisors();// Build Advisors for all AspectJ aspects in the bean factory.// 再從所有@Aspect中解析得到Advisor對象if (this.aspectJAdvisorsBuilder != null) {// 創建候選的切面,對有@Aspect注解的類進行處理(包裝Advice和Pointcut,還有切面的排序)****advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());// 核心方法-構建Advisor}return advisors;}
注意尋找的方法是this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
,此方法就是從Spring容器中查詢所有被@Aspect標注的方法,并轉換成Advisor
:
//GSCM 2024/1/23 解析容器中@Aspect注解標注的類構建成Advisor對象public List<Advisor> buildAspectJAdvisors() {List<String> aspectNames = this.aspectBeanNames;if (aspectNames == null) {synchronized (this) {aspectNames = this.aspectBeanNames;if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();aspectNames = new ArrayList<>();// 獲取Spring容器中所有實例的beanNameString[] 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, false);if (beanType == null) {continue;}// 判斷類上是否有@Aspect注解if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);// 獲取切面的注解信息AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {// 創建獲取@Aspect注解類的實例工廠,MetadataAwareAspectInstanceFactory負責獲取有@Aspect注解的實例MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// 創建切面Advisor對象List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);// 創建切面Advisor對象// 放到緩存中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 ArrayList<>();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;}
在此行List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
代碼中,最終將@Aspect注解的類解析成為Advisor,返回的Advisor類型同一都為InstantiationModelAwarePointcutAdvisorImpl
。
進入this.advisorFactory.getAdvisors(factory)
方法:
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {// 從工廠中獲取有@Aspect注解的類的反射對象ClassClass<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();//GXXX 2023/11/21// 從工廠中獲取有@Aspect注解的類的名稱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 ArrayList<>();// 這里循環沒有@Pointcut注解的方法,掃描有@Before、@Around、@After注解的方法,并進行排序,getAdvisorMethods()->for (Method method : getAdvisorMethods(aspectClass)) { // 進入本類的getAdvisorMethods()方法// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).// 獲取Advisor*****(只要是有@Before、@After等注解的方法,它們分別和帶有@Pointcut注解的方法組合,生成各自Advisor類)// 封裝Advisor,返回的實現類為InstantiationModelAwarePointcutAdvisorImplAdvisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);// 再進入本類的getAdvisor(),根據方法生成Advisorif (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;}
這里遍歷當前class的每個方法,為每個通知方法創建Advisor
實例。
進入getAdvisor
方法 :
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());// 獲取AspectJExpressionPointcut對象,從注解中獲取表達式// candidateAdviceMethod就是有@Before、@After注解的方法AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}// 創建真正的Advisor切面類,里面有pointcut和advice***進入InstantiationModelAwarePointcutAdvisorImpl的構造方法// expressionPointcut是pointcut,candidateAdviceMethod是advicereturn new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);// 創建真正的切面類}
在此針對每個目標方法創建對應的Advisor
實例,具體創建邏輯在InstantiationModelAwarePointcutAdvisorImpl
的構造方法中:
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);//GSCM 2024/2/28 創建當前方法對應advice實例的具體方法
此方法繼續調用this.aspectJAdvisorFactory.getAdvice()
,直接看aspectJAdvisorFactory.getAdvice():
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {// 獲取有@Aspect注解的類,就是當前被@Aspect標注的classClass<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();validate(candidateAspectClass);// 找到class上面的相關切面注解,并且包裝成AspectJAnnotation對象AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);if (aspectJAnnotation == null) {return null;}.........AbstractAspectJAdvice springAdvice;// 根據方法上切面不同注解,創建相對應的的advice實例switch (aspectJAnnotation.getAnnotationType()) {case AtPointcut:if (logger.isDebugEnabled()) {logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");}return null;case AtAround:// 環繞通知,實現了MethodInterceptor接口springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;case AtBefore:// 前置通知,實現了MethodBeforeAdvice接口,沒有實現MethodInterceptor接口springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;case AtAfter:// 后置通知,實現了MethodInterceptor接口springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;case AtAfterReturning:// 結果通知,實現了AfterReturningAdvice接口,沒有實現MethodInterceptor接口springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();if (StringUtils.hasText(afterReturningAnnotation.returning())) {springAdvice.setReturningName(afterReturningAnnotation.returning());}break;case AtAfterThrowing:// 異常通知,實現了MethodInterceptor接口springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {springAdvice.setThrowingName(afterThrowingAnnotation.throwing());}break;default:throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);}// Now to configure the advice...springAdvice.setAspectName(aspectName);springAdvice.setDeclarationOrder(declarationOrder);String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);if (argNames != null) {springAdvice.setArgumentNamesFromStringArray(argNames);}springAdvice.calculateArgumentBindings();return springAdvice;}
這里就是創建了目標方法對應具體的advice
并賦值給InstantiationModelAwarePointcutAdvisorImpl的instantiatedAdvice屬性
被代理方法的執行流程
被Spring的Cglib代理的所有方法都會進入CglibAopProxy.DynamicAdvisedInterceptor#intercept方法;
//GSCM 2024/1/24 被cglib代理的對象調用首先進入此方法
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() && CglibMethodInvocation.isMethodProxyCompatible(method)) {// 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 = invokeMethod(target, method, argsToUse, methodProxy);}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);}}
}
DynamicAdvisedInterceptor有一個重要的屬性private final AdvisedSupport advised
,在創建代理的時候被賦值,里面包含被代理的原生類引用及執行鏈;
轉換前
轉換后
CglibMethodInvocation
ExposeInvocationInterceptor
AspectJAroundAdvice#invoke->調用切面層aspectJAdviceMethod.invoke
MethodBeforeAdviceInterceptor#invoke
AspectJAfterAdvice#invoke
AspectJAfterThrowingAdvice#invoke
AspectJAroundAdvice
MethodBeforeAdviceInterceptor
AfterReturningAdviceAdapter
ThrowsAdviceAdapter
AspectJAfterAdvice
AspectJMethodBeforeAdvice -> MethodBeforeAdviceInterceptor
advisor、advice、adviced各自的含義
-
advisor 通知器包含advice和pointcut
-
advice 具體的某一個消息通知
-
adviced 用來配置代理(proxyFactory)
執行流程整理 :
postProcessAfterInitialization創建代理,第一次進來會遍歷Spring容器內所有的帶有@Aspect
注解的類,遍歷其類中的每個帶有@Before、@Around、@After
的方法,并將切點對象解析出來與當前方法的Method對象,封裝成一個InstantiationModelAwarePointcutAdvisorImpl
實例,在InstantiationModelAwarePointcutAdvisorImpl中構造函數中會根據Method的信息創建一個Advice對象并引用。遍歷完成將這些類緩存起來,并且生成一個bean名稱對應Advice的緩存,下次直接從緩存中。拿到Advice后默認添加一個ExposeInvocationInterceptor在最前面。再創建一個代理工廠ProxyFactory區創建代理,代理工廠選擇Cglib還是Jdk去創建代理類,代理類保存著目標類的引用及Advisor調用鏈。
Cglib代理進入DynamicAdvisedInterceptor#intercept
,再根據Advisor獲取調用鏈進行包裝(如果需要的話),包裝成MethodInterceptor。創建一個ReflectiveMethodInvocation類調用proceed,里面保存著一個調用次數currentInterceptorIndex
,按照順序一個個調用Advisor調用鏈,并且將當前類作為參數一直傳遞下去,每次調用一個Advisor會將currentInterceptorIndex減一,直到與Advisor調用鏈數量一致,說明調用鏈已經執行完了。
再調用真實的目標對象方法,調用完成依次彈出棧。
調用棧示例,org.gabriel.springwork.boot
是自定義包 :
at org.gabriel.springwork.imported.ImportController.isSuccess(ImportController.java:16)at org.gabriel.springwork.imported.ImportController$$FastClassBySpringCGLIB$$7fcf3b6d.invoke(<generated>:-1)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)at org.gabriel.springwork.boot.config.DictAspect2.doAround(DictAspect2.java:35)at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:566)at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)at org.gabriel.springwork.imported.ImportController$$EnhancerBySpringCGLIB$$20b0886d.isSuccess(<generated>:-1)at org.gabriel.springwork.boot.GabrielSpringBoot.lambda$main$0(GabrielSpringBoot.java:31)at org.gabriel.springwork.boot.GabrielSpringBoot$$Lambda$606.1849602253.accept(Unknown Source:-1)at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)at org.gabriel.springwork.boot.GabrielSpringBoot.main(GabrielSpringBoot.java:30)
Advisor相關實現類解析
AOP原文