一、啟動(dòng)流程
- 創(chuàng)建SpringApplication對(duì)象
public class SpringApplication {
public SpringApplication(Class... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 保存主配置類
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 判斷當(dāng)前是否一個(gè)web應(yīng)用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer拄轻;然后保存起來桨啃。
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 從類路徑下找到META-INF/spring.factories配置的所有ApplicationListener
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//從多個(gè)配置類中找到有main方法的主配置類
this.mainApplicationClass = this.deduceMainApplicationClass();
}
- 運(yùn)行run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 獲取SpringApplicationRunListener; 從類路徑下META-INF/spring.factories獲取
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 回調(diào)所有的獲取SpringApplicationRunListener.starting()方法
listeners.starting();
Collection exceptionReporters;
try {
// 封裝命令行參數(shù)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 準(zhǔn)備環(huán)境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 創(chuàng)建環(huán)境完成后回調(diào)SpringApplicationRunListener.environmentPrepared();表示環(huán)境準(zhǔn)備完成
Banner printedBanner = this.printBanner(environment);
// 創(chuàng)建ApplicationContext忍燥;決定創(chuàng)建web的IOC還是普通的IOC
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 準(zhǔn)備上下文環(huán)境墓卦;將environment保存到IOC中,而且applyInitializers();
// 而且applyInitializers():回調(diào)之前保存的所有ApplicationContextInitializer的initialize方法
// 回調(diào)所有的SpringApplicationRunListener的contextPrepared();
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// prepareContext運(yùn)行完成以后回調(diào)所有的SpringApplicationRunListener的contextLoaded();
// 掃描容器睛榄;IOC容器初始化(如果是web應(yīng)用還會(huì)創(chuàng)建嵌入的Tomcat)荣茫;
// 掃描,創(chuàng)建场靴,加載所有組件的地方(配置類啡莉,組件,自動(dòng)配置)
this.refreshContext(context);
// 從IOC容器中獲取所有的ApplicationRunner和CommandLineRunner進(jìn)行回調(diào)
// ApplicationRunner先回調(diào)旨剥,CommandLineRunner再回調(diào)
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
// 整個(gè)SpringBoot應(yīng)用啟動(dòng)完成以后返回啟動(dòng)的IOC容器
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
- 事件監(jiān)聽機(jī)制
需要配置在META-INF/spring.factories中的事件監(jiān)聽器咧欣。
ApplicationContextInitializer
public class CustomApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("ApplicationContextInitializer.....initialize");
}
}
SpringApplicationRunListener
public class CustomSrpingApplicationRunListener implements SpringApplicationRunListener {
// 必須有的構(gòu)造器
public CustomSrpingApplicationRunListener(SpringApplication application,String[] args){
}
@Override
public void starting() {
System.out.println("SpringApplicationRunListener...starting....");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object o = environment.getSystemEnvironment().get("os.name");
System.out.println("SpringApplicationRunListener...environmentPrepared...."+o);
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener..contextPrepared");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener..contextLoaded");
}
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener..started");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener..running");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener..failed");
}
}
配置(META-INF/spring.factories)
org.springframework.context.ApplicationContextInitializer=com.desperado.demo.CustomApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=com.desperado.demo.CustomSrpingApplicationRunListener
只需要放在IOC容器中的監(jiān)聽器。
ApplicationRunner
@Component
public class CustomApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("ApplicationRunner ... run....");
}
}
CommandLineRunner
@Component
public class CustomCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("commandLineRunner ... run ...");
}
}
二轨帜、自定義starter
要使用到的注解
@Configuration 指定類是一個(gè)配置類
@ConditionalOnXXX 在指定條件成立的情況下自動(dòng)配置生效魄咕、
@AutoConfigureAfter 在特定自動(dòng)裝配class之后(指定自動(dòng)配置類的順序)
@AutoConfigureBefore 在特定自動(dòng)裝配class之前(指定自動(dòng)配置類的順序)
@AutoConfigureOrder 指定順序
@Bean 給容器中添加組件
@ConfigurationPropertie 結(jié)合相關(guān)xxxProperties類來綁定相關(guān)的配置。
@EnableConfigurationProperties 讓xxxProperties生效加入到容器中阵谚。加載方式
自動(dòng)配置類要能加載,將需要啟動(dòng)就加載的自動(dòng)配置類烟具,配置在META-INF/spring.factories文件中梢什。啟動(dòng)器模式
啟動(dòng)器只用來做依賴導(dǎo)入,專門寫一個(gè)自動(dòng)配置模塊朝聋。啟動(dòng)器依賴自動(dòng)配置嗡午,使用時(shí)只需要引入啟動(dòng)器(starter)。啟動(dòng)器規(guī)則
啟動(dòng)器就是個(gè)空jar文件冀痕,僅提供輔助性依賴管理荔睹,這些依賴可能用于自動(dòng)裝配或者其他庫。
命名規(guī)范:
- 推薦使用以下命名規(guī)范
- 官方命名空間
?- 前綴:spring-boot-starter-
?- 模式:spring-boot-starter-模塊名
- 自定義命名空間
? - 后綴:-spring-boot-starter
? - 模式:模塊名-spring-boot-starter
- 編寫一個(gè)啟動(dòng)器模塊
1). 啟動(dòng)器模塊
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.desperado.starter</groupId>
<artifactId>desperado-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 啟動(dòng)器 -->
<dependencies>
<!-- 引入自動(dòng)配置模塊 -->
<dependency>
<groupId>com.desperado.starter</groupId>
<artifactId>desperado-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
2). 自動(dòng)配置模塊
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.desperado.starter</groupId>
<artifactId>desperado-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<!-- 引入spring-boot-starter言蛇;所有starter的基本配置 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
3). 編寫配置文件類
@ConfigurationProperties(prefix = "desperado.custom")
public class CustomProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
4). 進(jìn)行配置文件的處理
public class CustomService {
CustomProperties customProperties;
public CustomProperties getCustomProperties(){
return customProperties;
}
public void setCustomProperties(CustomProperties customProperties){
this.customProperties = customProperties;
}
public String sayHello(String name){
return customProperties.getPrefix()+"-"+name+customProperties.getSuffix();
}
}
5). 編寫自動(dòng)配置類
@ConditionalOnWebApplication
@EnableConfigurationProperties(CustomProperties.class)
public class CustomServiceAutoConfiguration {
@Autowired
CustomProperties customProperties;
@Bean
public CustomService customService(){
CustomService customService = new CustomService();
customService.setCustomProperties(customProperties);
return customService;
}
}