本篇說說SpringBoot項目啓動時的原理,是按個人理解,說的不好請諒解
1.創建好項目後有個主類,上面有@SpringBootApplication註解
package com.yizheng.api;
@SpringBootApplication
public class ApiAcceptApplication {}
在idea中按住Ctrl點擊進去,會看到下面兩個關鍵註解(其他註解沒有列出來)
@SpringBootConfiguration //該類爲配置類
@EnableAutoConfiguration //啓動自動配置
public @interface SpringBootApplication {}
從 @EnableAutoConfiguration 點進去,又有兩個關鍵的註解,這兩個註解就是SpringBoot項目啓動時自動配置的核心
//掃描主類架包及以下所有子類到容器
@AutoConfigurationPackage
//把符合條件的組件自動配置到容器
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
2. 掃描主類架包及以下所有子類到容器 @AutoConfigurationPackage
從@AutoConfigurationPackage點進去,看到@Import導入了一個Registrar.class
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
點擊 Registrar.class,看到 registerBeanDefinitions方法,猜測是把一些bean導入到容器中
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
在 registerBeanDefinitions方法處打一個端點,可以看到 getPackageName()返回的是 @SpringBootApplication 所在主類的 package 名,然後springboot把該架包和以下子包的所有組件導入到容器,和以前的SpringMVC手動掃描組件一樣,只不過在SpringBoot中變爲自動掃描了,所以我們在該 package下添加的控制器能對外提供服務
3.把符合條件的組件自動配置到容器@Import({AutoConfigurationImportSelector.class})
導入了 AutoConfigurationImportSelector.class,點進去可看到 selectImports()方法,該方法返回String數組,調試下面的代碼,看到系統自動加載了110個自動配置類,最後返回29個類是符合條件的
原理:項目根據元數據加載所有依賴jar組件的 META-INF/spring.factories 文件中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration 屬性的值,下圖右邊區域有很多很多,這些就是SpringBoot封裝好的自動配置類,搜索 WebMvcAutoConfiguration,可以點進去,看到這些代碼是以前SpringMVC時需要手動配置的,現在被SpringBoot自動寫好了
以Redis爲例,如果引用了Redis,那麼也會加載 META-INF/spring.factories 文件中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration 屬性的值,裏面一個 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
看RedisAutoConfiguration的源碼,
- 1.@Configuration 表示該類是配置類
- 2.ConditionalOnClass({RedisOperations.class}) 表示該類需要有RedisOperations
- 3.EnableConfigurationProperties({RedisProperties.class}) 表示啓動自動配置屬性,把application.properties中的屬性值映射到 RedisProperties.class 類的屬性上
- 4.還會導入一些配置類
```java
@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
裏面的代碼表示會往容器中添加一個 bean,條件是容器中沒有 redisTemplate bean存在,如果我們自己配置了 redisTemplate bean,則此bean不會添加到容器,有了此默認的bean後,只要在項目中
@Autowired
RedisTemplate redisTemplate;
就可以使用redis的功能了
以上就是SpringBoot啓動時自動配置的原理,如果我們要使用相關組件,只要添加好對應的依賴,然後在 application.properties中添加相關配置即可,如果不知道怎麼配置,可以點擊到 xxxxAutoConfiguration中查看xxxxProperties類中查看
自行擴展:可以添加自定義配置的 bean 到容器,來替代默認的配置就可以擴展了