9.springboot自動配置原始碼
阿新 • • 發佈:2022-05-11
springboot自動載入的原始碼解析:
1.springboot的啟動類程式碼如下: //使用@SpringBootApplication標籤標明當前類是springboot的啟動類 @SpringBootApplication public class MainApplication { public static void main(String[] args) { System.out.println("啟動springboot專案..."); ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); System.out.println("啟動成功!"); } } 2.仔細研究@SpringBootApplication註解: ... 1.@SpringBootConfiguration 2.@EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { ... //該屬性可以設定掃描哪個包:例如@SpringBootApplication(scanBasePackages = "cn.com") String[] scanBasePackages() default {}; } 3.詳解1.@SpringBootConfiguration註解:發現其底層也是@Configuration註解,該註解的作用:告訴springboot當前是配置類,可以配合@bean往容器中載入元件 ... @Configuration public @interface SpringBootConfiguration { ... } 例如直接在啟動類中使用@bean註冊元件: @SpringBootApplication public class MainApplication { public static void main(String[] args) { System.out.println("啟動springboot專案..."); ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); System.out.println("啟動成功!"); } //此方法是可行的,但是一般是使用專門的配置類進行註冊 @Bean public Car getCar() { System.out.println("car的建立方法!"); return new Car("寶馬", "14萬"); } } 4.詳解2註解:@EnableAutoConfiguration自動配置,這是springboot的核心: 4.1.@EnableAutoConfiguration原始碼 .... @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { ... } 4.1.2研究其下面註解:@AutoConfigurationPackage的內容 //往容器中匯入Registrar類 @Import({Registrar.class}) public @interface AutoConfigurationPackage { ... } Registrar類的詳情如下: static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { //註冊元件 public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])); } }
按需開啟自動配置項:4.1.3 @Import({AutoConfigurationImportSelector.class})程式碼研究(自動匯入各種選擇器) AutoConfigurationImportSelector類程式碼: public String[] selectImports(AnnotationMetadata annotationMetadata) { ... AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata); ... } 下續程式碼: protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { ... List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); ... } 下續程式碼: 最終發現:所有的選擇器匯入的bean都在spring-boot-autoconfigure.jar/META-INF/spring.factories中配置:約有127項 Enumeration urls = classLoader.getResources("META-INF/spring.factories");
注意,注意,注意..... 自動配置的類後面都是XXXAutoConfiguration雖然127個場景所有的自動配置會在springboot啟動時全部載入, 最終會進行按需配置,容器中不會存在127個所有的元件,會按需配置: 例子: 例如aop類中:如果專案中有Advice.class這個類,會進行aop bean的註冊,但是專案並沒有匯入Advice的包,自然不會有該類,也不會配置該場景的啟動器 //條件選擇器:當容器中有這個類時執行下述方法 @ConditionalOnClass({Advice.class}) static class AspectJAutoProxyingConfiguration { } 例如:amqp類中: //條件選擇器:當容器中存在RabbitTemplate這個類時,會執行下述方法 @ConditionalOnClass({RabbitTemplate.class, Channel.class}) @EnableConfigurationProperties({RabbitProperties.class}) @Import({RabbitAnnotationDrivenConfiguration.class}) public class RabbitAutoConfiguration { }
每個場景的自動配置類都會將配置關聯到一個配置類上(使用@EnableConfigurationProperties(類名)標籤去關聯springboot的配置檔案和這個類)
示例如下:
1.HttpEncodingAutoConfiguration自動配置類
//1.標明當前類是springboot配置類
@Configuration(
proxyBeanMethods = false
)
//2.當前自動配置類和ServerProperties類進行繫結
@EnableConfigurationProperties({ServerProperties.class})
//3.當前應用是傳統的servlet的web工程
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//4.專案是否存在CharacterEncodingFilter類
@ConditionalOnClass({CharacterEncodingFilter.class})
//5.條件判斷註解:springboot的配置檔案中是否存在erver.servlet.encoding為字首的標籤,matchIfMissing=true,即使不存都生效
@ConditionalOnProperty(
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
...
}
2.繫結的ServerProperties類程式碼如下:
@ConfigurationProperties(
//指定配置檔案的字首為:server
prefix = "server",
ignoreUnknownFields = true
)
public class ServerProperties {
...
private Integer port;
private InetAddress address;
...
}
3.在springboot的配置檔案中:application.properties中的繫結配置為:
server.port=80080
原理總結:
在繫結的配置類中,各屬性有自己預設的值,但當需要更改時,在application.properties中進行配置,@ConfigurationProperties標籤
會將其繫結到配置類上的具體屬性,達到修改預設值的效果!