springBoot 启动配置原理
- springBoot 几个重要的事件回调机制
- 配置在META_INF/spring.factories
- ApplicationContextInitializer
- SpringApplicationRunListener
- 只需要放在ioc容器中
- ApplicationRunner
- CommanLineRunner
- 配置在META_INF/spring.factories
启动流程:
一、 创建SpringApplication对象(1.x版本)
initialize(sources);
private void initialize(Object[] sources) {
// 保存主配置类
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
// 判断当前是否一个web应用
this.webEnvironment = deduceWebEnvironment();
// 从类的路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
二、 运行run方法(1.x 和 2.x)
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 获取SpringApplicationRunListeners; 从类路径下META-INF/spring.factories
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 回调所有的获取SpringApplicationApplicationRunListener.starting()方法
listeners.starting();
Collection exceptionReporters;
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
Banner printedBanner = this.printBanner(environment);
// 创建ApplicationContext; 决定创建web的ioc还是普通的ioc
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 准备上下文环境;将environment保存到ioc中;而且applyInitalizers();
// applyInitalizers(): 回调之前保存的所有的ApplicationContextInitalizer的initze的方法
// 回调所有的SpringApplicationRunListener的contextPrepared()
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// propareContext运行完成之后回调所有的SpringApplicationRunLitsener的contextLocaded();
// 刷新容器; ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);
// 扫描,创建,加载所有组件的地方
this.refreshContext(context);
// 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
// 所有的Application先回调,CommandLineRunner在回调
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 所有的SpringApplicationRunListener回调started方法
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
// 整个SpringBoot应用启动完成以后返回启动的ioc容器
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
三、事件监听机制
配置在META-INF/spring.factories
ApplicationContextInitalizer
public class HelloApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("ApplicationContextInitializer...initialize..."+configurableApplicationContext);
}
}
SpringApplicationRunListener
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
// 必须要有构造器
public HelloSpringApplicationRunListener(SpringApplication application, String[] args){
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object o = environment.getSystemProperties().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...starting...");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener...finished...");
}
}
配置(META-INFO/spring.factories)
org.springframework.context.ApplicationContextInitializer=\
com.oy.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.oy.springboot.listener.HelloSpringApplicationRunListener
只需要放在ioc容器中
ApplicationRunner
@Component
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run....");
}
}
CommandLineRunner
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
}
}
测试:
自定义starter
starter:
1.编写自动配置
@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter // 指定自动配置类的顺序
@Bean // 给容器中添加组件
@ConfigurationPropertie // 结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties // 让xxxProperties生效加入到容器中
自动配置类要能加载
将需要启动就能加载的自动配置类,配置在META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
- 模式:
-
启动器只用来做依赖导入:
-
专门来写一个自动配置模块;
-
启动器依赖自动配置;别人只需要引入启动器(starter)
eg: mybatis-spring-boot-starter; 自定义启动器名-spring-boot-starter
演示步骤(参考):
- 项目结构
-
先创建一个空项目,然后oy-spring-boot-starter(用maven创建)和 oy-spring-boot-starter-autoconfigurer(spring Initializr创建)
【oy-spring-boot-starter】 pom.xml配置
<dependencies>
<dependency>
<groupId>com.oy.starter</groupId>
<artifactId>oy-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependencies>
【oy-spring-boot-starter-autoconfigurer】 pom.xml配置
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.oy.starter</groupId>
<artifactId>oy-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>oy-spring-boot-starter-autoconfigurer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
【HelloProperties】
@ConfigurationProperties(prefix = "oy.hello")
public class HelloProperties {
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;
}
}
【HelloService】
public class HelloService {
HelloProperties helloProperties;
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
public String sayHellAtguigu(String name){
return helloProperties.getPrefix()+"-" +name + helloProperties.getSuffix();
}
【HelloServiceAutoConfiguration】
@Configuration
@ConditionalOnWebApplication // Web应用才生效
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
@Autowired
HelloProperties helloProperties;
@Bean
public HelloService helloService(){
HelloService service = new HelloService();
service.setHelloProperties(helloProperties);
return service;
}
}
【spring.factories】
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.oy.starter.HelloServiceAutoConfiguration
测试:
- **spring-boot-08-starter-test **项目结构
【pom.xml】
<dependency>
<groupId>com.oy.stater</groupId>
<artifactId>oy-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
【HelloController.java】
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String hello(){
return helloService.sayHellAtguigu("haha");
}
}
ter
oy-spring-boot-starter
1.0-SNAPSHOT
【HelloController.java】
~~~java
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String hello(){
return helloService.sayHellAtguigu("haha");
}
}