SpringBoot自動配置註解原理解析

1. SpringBoot啓動主程序類:

1 @SpringBootApplication
2 public class DemoApplication {
3     public static void main(String[] args) {
4 
5         SpringApplication.run(DemoApplication.class, args);
6     }
7 }

 

每次咱們直接直接啓動這個啓動類,SpringBoot就啓動成功了,而且幫咱們配置了好多自動配置類。redis

其中最重要是 @SpringBootApplication 這個註解,咱們點進去看一下。spring

 

2. SpringBootApplication註解:

 1 @Target(ElementType.TYPE)
 2 @Retention(RetentionPolicy.RUNTIME)
 3 @Documented
 4 @Inherited
 5 @SpringBootConfiguration
 6 @EnableAutoConfiguration
 7 @ComponentScan(excludeFilters = {
 8         @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
 9         @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
10 public @interface SpringBootApplication {

 

  三個比較重要的註解:

  • @SpringBootConfiguration : Spring Boot的配置類,標註在某個類上,表示這是一個Spring Boot的配置類app

  • @EnableAutoConfiguration: 開啓自動配置類,SpringBoot的精華所在。框架

  • @ComponentScan包掃描ide

  之前咱們須要配置的東西,Spring Boot幫咱們自動配置;@EnableAutoConfiguration告訴SpringBoot開啓自動配置功能;這樣自動配置才能生效;工具

3. EnableAutoConfiguration註解:

1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @Inherited
5 @AutoConfigurationPackage
6 @Import(AutoConfigurationImportSelector.class)
7 public @interface EnableAutoConfiguration {

 

兩個比較重要的註解:

  • @AutoConfigurationPackage:自動配置包學習

  • @Import: 導入自動配置的組件this

 

4. AutoConfigurationPackage註解:

1     static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
2 
3         @Override
4         public void registerBeanDefinitions(AnnotationMetadata metadata,
5                 BeanDefinitionRegistry registry) {
6             register(registry, new PackageImport(metadata).getPackageName());
7         }

 

它實際上是註冊了一個Bean的定義。spa

new PackageImport(metadata).getPackageName(),它其實返回了當前主程序類的 同級以及子級     的包組件。3d

 

 

以上圖爲例,DemoApplication是和demo包同級,可是demo2這個類是DemoApplication的父級,和example包同級

也就是說,DemoApplication啓動加載的Bean中,並不會加載demo2,這也就是爲何,咱們要把DemoApplication放在項目的最高級中。

 

5. Import(AutoConfigurationImportSelector.class)註解:

 

能夠從圖中看出  AutoConfigurationImportSelector 繼承了 DeferredImportSelector 繼承了 ImportSelector

ImportSelector有一個方法爲:selectImports。

 

 1 @Override
 2     public String[] selectImports(AnnotationMetadata annotationMetadata) {
 3         if (!isEnabled(annotationMetadata)) {
 4             return NO_IMPORTS;
 5         }
 6         AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
 7                 .loadMetadata(this.beanClassLoader);
 8         AnnotationAttributes attributes = getAttributes(annotationMetadata);
 9         List<String> configurations = getCandidateConfigurations(annotationMetadata,
10                 attributes);
11         configurations = removeDuplicates(configurations);
12         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
13         checkExcludedClasses(configurations, exclusions);
14         configurations.removeAll(exclusions);
15         configurations = filter(configurations, autoConfigurationMetadata);
16         fireAutoConfigurationImportEvents(configurations, exclusions);
17         return StringUtils.toStringArray(configurations);
18     }

 

能夠看到第九行,它實際上是去加載  public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";外部文件。這個外部文件,有不少自動配置的類。以下:

 

 

6. 如何自定義本身的Bean:

咱們以RedisTemplate爲例:

 1 @Configuration
 2 @ConditionalOnClass(RedisOperations.class)
 3 @EnableConfigurationProperties(RedisProperties.class)
 4 @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
 5 public class RedisAutoConfiguration {
 6 
 7     @Bean
 8     @ConditionalOnMissingBean(name = "redisTemplate")
 9     public RedisTemplate<Object, Object> redisTemplate(
10             RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
11         RedisTemplate<Object, Object> template = new RedisTemplate<>();
12         template.setConnectionFactory(redisConnectionFactory);
13         return template;
14     }
15 
16     @Bean
17     @ConditionalOnMissingBean
18     public StringRedisTemplate stringRedisTemplate(
19             RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
20         StringRedisTemplate template = new StringRedisTemplate();
21         template.setConnectionFactory(redisConnectionFactory);
22         return template;
23     }
24 
25 }

 

咱們每次在Spring中使用Redis,都會使用到RedisTemplate這個工具類,可是他默認給咱們返回的這個工具類,可能不是很符合咱們的要求。好比:咱們想要開啓事務,或者想要改變它默認的序列化。

這時候該如何去作呢?

根據前面的分析,只要咱們在容器中放入一個RedisTemplate Bean便可。

 

 1 @Bean("redisTemplate")
 2     public RedisTemplate<Object, Object> myRedisTemplate(
 3             RedisConnectionFactory redisConnectionFactory) {
 4         RedisTemplate<Object, Object> template = new RedisTemplate<>();
 5         template.setConnectionFactory(redisConnectionFactory);
 6         // 修改序列化爲Jackson
 7         template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
 8         // 開啓事務
 9         template.setEnableTransactionSupport(true);
10         return template;
11     }

 

咱們本身定義咱們的RedisTemplate模板,修改序列化,開啓事務等操做。

咱們將咱們本身的Bean加入到IoC容器中之後,他就會默認的覆蓋掉原來的RedisTemplate,達到定製的效果。

 

咱們在以Kafka爲例:

假設咱們想要消費的對象不是字符串,而是一個對象呢?好比Person對象,或者其餘Object類呢?

1:咱們首先去查找KafkaAutoConfiguration(xxxAutoConfiguration),看看是否有關於Serializer屬性的配置

2:假設沒有咱們就去KafkaProperties文件查找是否有Serializer的配置

 

 

 

而後直接在application.properties修改默認序列化就好,連Bean都不須要本身重寫。

 相似這種,可使用Spring提供的Json序列化,也能夠自動使用第三方框架提供的序列化,好比Avro, Protobuff等

1 spring.kafka.producer.key-serializer=org.springframework.kafka.support.serializer.JsonSerializer
2 spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
3 spring.kafka.consumer.key-deserializer=com.example.common.MyJson
4 spring.kafka.consumer.value-deserializer=com.example.common.MyJson

 

後記:

  •    不少時候咱們剛開始看一個知識點,不懂迷茫的時候,真的不要慌,可能說明你暫時的知識儲備還不夠理解。
  •    等你通過不斷的學習,不斷的深刻之後
  •    忽然有一天,你會忽然的醒悟
  •    哇!原來他講的是這個意思
  •    可能咱們不理解,咱們能夠去嘗試去看兩遍,三遍,甚至更多遍,忽然會有一個時刻,你會醒悟過來的
  •    且行且珍惜,共勉
相關文章
相關標籤/搜索