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自動配置開始沾點兒邊了
下面,重點來了,核心中的核心
終於寫完了,累死我了