首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SpringBoot 启动配置原理

SpringBoot 启动配置原理

作者头像
OY
发布2022-03-17 17:07:42
发布2022-03-17 17:07:42
30100
代码可运行
举报
文章被收录于专栏:OY_学习记录OY_学习记录
运行总次数:0
代码可运行

springBoot 启动配置原理

  • springBoot 几个重要的事件回调机制
    • 配置在 META_INF/spring.factories
      • ApplicationContextInitializer
      • SpringApplicationRunListener
    • 只需要放在 ioc 容器中
      • ApplicationRunner
      • CommanLineRunner

启动流程

一、 创建 SpringApplication 对象(1.x 版本)

代码语言:javascript
代码运行次数:0
运行
复制
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)

代码语言:javascript
代码运行次数:0
运行
复制
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

代码语言:javascript
代码运行次数:0
运行
复制
public class HelloApplicationContextInitializer implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer...initialize..."+configurableApplicationContext);
    }
}

SpringApplicationRunListener

代码语言:javascript
代码运行次数:0
运行
复制
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)

代码语言:javascript
代码运行次数:0
运行
复制
org.springframework.context.ApplicationContextInitializer=\
com.oy.springboot.listener.HelloApplicationContextInitializer

org.springframework.boot.SpringApplicationRunListener=\
com.oy.springboot.listener.HelloSpringApplicationRunListener

只需要放在 ioc 容器中

ApplicationRunner

代码语言:javascript
代码运行次数:0
运行
复制
@Component
public class HelloApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner...run....");
    }
}

CommandLineRunner

代码语言:javascript
代码运行次数:0
运行
复制
@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.编写自动配置

代码语言:javascript
代码运行次数:0
运行
复制
@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,\
  1. 模式:
  • 启动器只用来做依赖导入:
  • 专门来写一个自动配置模块;
  • 启动器依赖自动配置;别人只需要引入启动器(starter) eg: mybatis-spring-boot-starter; 自定义启动器名-spring-boot-starter

演示步骤(参考):

  1. 项目结构

2. 先创建一个空项目,然后 oy-spring-boot-starter(用 maven 创建)和 oy-spring-boot-starter-autoconfigurer(spring Initializr 创建)

【oy-spring-boot-starter】 pom.xml 配置

代码语言:javascript
代码运行次数:0
运行
复制
<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 配置

代码语言:javascript
代码运行次数:0
运行
复制
<?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】

代码语言:javascript
代码运行次数:0
运行
复制
@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】

代码语言:javascript
代码运行次数:0
运行
复制
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】

代码语言:javascript
代码运行次数:0
运行
复制
@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】

代码语言:javascript
代码运行次数:0
运行
复制
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.oy.starter.HelloServiceAutoConfiguration

测试

  • **spring-boot-08-starter-test **项目结构

【pom.xml】

代码语言:javascript
代码运行次数:0
运行
复制
<dependency>
    <groupId>com.oy.stater</groupId>
    <artifactId>oy-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

【HelloController.java】

代码语言:javascript
代码运行次数:0
运行
复制
@RestController
public class HelloController {

    @Autowired
    HelloService helloService;

    @GetMapping("/hello")
    public String hello(){
        return helloService.sayHellAtguigu("haha");
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • springBoot 启动配置原理
    • 一、 创建 SpringApplication 对象(1.x 版本)
    • 二、 运行 run 方法(1.x 和 2.x)
    • 三、事件监听机制
  • 自定义 starter
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档