Spring Boot 自動配置 原始碼分析

廢物大師兄發表於2021-03-14

Spring Boot 最大的特點(亮點)就是自動配置 AutoConfiguration

下面,先說一下 @EnableAutoConfiguration ,然後再看原始碼,到底自動配置是怎麼配置的

1.  @EnableAutoConfiguration

@SpringBootApplication是一個複合註解,本節我們重點關注 @EnableAutoConfiguration

自動配置類是常規的Spring @Configuration bean。它們使用SpringFactoriesLoader機制定位。通常,自動配置bean是@Conditional Bean(最經常使用@ConditionalOnClass和@ConditionalOnMissingBean註解)

在@EnableAutoConfiguration註解上有一個@Import註解

@Import這個註解表明要匯入的一個或多個元件類,通常是@Configuration類。

@Import註解提供與Spring XML中的<import />元素等效的功能。允許匯入@Configuration類,ImportSelector和ImportBeanDefinitionRegistrar實現以及常規元件類。

根據匯入的@Configuration類的AnnotationMetadata,返回AutoConfigurationImportSelector.AutoConfigurationEntry。

方法的引數AnnotationMetadata代表配置類上的註解後設資料,方法的返回值是應該被匯入的自動配置類

首先,獲取配置類上的註解的屬性

又是熟悉的方法:SpringFactoriesLoader.loadFactoryNames() 

在所有 META-INF/spring.factories 檔案中查詢 org.springframework.boot.autoconfigure.EnableAutoConfiguration

然後,去重

然後,再排除一些,根據註解屬性中明確指定的exclude

刪除所有需要排除的

然後,過濾掉一些不需要的

根據對所有的需要自動配置的類應用那三個過濾器

最終剩下的就是真正需要匯入的,或者說真正需要自動配置的

在眾多需要自動配置的類中,我們挑一個熟悉的來看一下,就挑org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

看這注解,當classpath中有RedisOperations時才會自動配置該類,當有RedisConnectionFactory且沒有redisTemplate時才會建立一個redisTemplate,同理,有RedisConnectionFactory且沒有stringRedisTemplate時才會建立一個stringRedisTemplate

回顧一下

1、在所有 META-INF/spring.factories 檔案中查詢 org.springframework.boot.autoconfigure.EnableAutoConfiguration,返回一個List<String>

2、對上一步返回的List去重

3、根據註解exclude屬性排除List中的一些元素

4、根據AutoConfigurationImportFilter過濾掉一些不需要自動配置的元素

5、講過以上四步,List中剩下的元素就是最終需要自動配置的元素(類)

至此,只是篩選出了哪些類需要自動配置,但還沒有真正裝配(例項化),真正例項化Bean是在Spring Boot啟動時重新整理ApplicationContext時做的

註解只是個標記,是給反射用的,有註解必然有處理它的類

接下來,分析原始碼,看看究竟什麼時候開始真正自動裝配

2.  Spring Boot 自動配置原始碼分析

又來到了熟悉的SpringApplication.run()方法這裡,這一次,重點看其中的三步:createApplicationContext()、prepareContext() 和 refreshContext()

首先看createApplicationContext()

看看AnnotationConfigServletWebServerApplicationContext有多複雜

建立了兩個BeanDefinition分別是AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner,它們都是用來查詢並載入Bean定義的,只是方式不同而已

下面重點看一下AnnotatedBeanDefinitionReader

(PS:其實,這裡註冊了很多BeanPostProcessor,有處理Autowired的AutowiredAnnotationBeanPostProcessor,由於本節主要講自動配置的,所以我們重點關注ConfigurationClassPostProcessor)

先做個筆記:

1、ApplicationContext 是 AnnotationConfigServletWebServerApplicationContext

2、構造了一個AnnotatedBeanDefinitionReader,大家要明白BeanDefinitionReader是用來載入Bean定義的

3、把這個AnnotatedBeanDefinitionReader註冊(關聯)到該ApplicationContext

4、在構造AnnotatedBeanDefinitionReader的時候註冊了很多Processors

可見AnnotatedBeanDefinitionReader真的是相當相當重要,而重中之重是org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors()

我們單獨把這段拿出來再看一下

如果沒有這個BeanDefinition的時候就新增一個

CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 對應的是 ConfigurationClassPostProcessor

先記住這一點,後面會用到

接下來,看prepareContext()

 

重點看SharedMetadataReaderFactoryContextInitializer

好,記住這一點,此處新增了一個BeanFactoryPostProcessor,它是一個CachingMetadataReaderFactoryPostProcessor

最後,再來看refreshContext()

呼叫是Spring的refresh()

 

重點看 invokeBeanFactoryPostProcessors 呼叫所有已註冊的BeanPostProcessor

這裡,呼叫getBeanFactoryPostProcessors()返回的BeanFactoryPostProcessors中有CachingMetadataReaderFactoryPostProcessor

好,記住這一點

繼續看PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()

好,看CachingMetadataReaderFactoryPostProcessor#postProcessBeanDefinitionRegistry()

又看到了熟悉的AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME,我們知道它是ConfigurationClassPostProcessor

回到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()繼續往下看

得到ConfigurationClassPostProcessor

接下來,呼叫postProcessBeanDefinitionRegistry

方法太長,就不截全圖了,總之就是找到配置類,開始解析配置類了,只看重點

到這裡終於和我們前面講的@EnableAutoConfiguration自動配置開始沾點兒邊了

下面,重點來了,核心中的核心

終於寫完了,累死我了

 

相關文章