Spring Boot学习笔记20——原理(启动&运行&自动配置)

    科技2022-07-14  127

    1. 启动配置原理(启动流程)

    1.1 创建SpringApplication对象

    可以创建一个web项目在mian方法打断点,通过debug来看springboot的启动流程

    initialize(sources); private void initialize(Object[] sources) { //1、保存主配置类 if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } //2、判断当前是否一个web应用 this.webEnvironment = deduceWebEnvironment(); //3、从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); //4、从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //5、从多个配置类中找到有main方法的主配置类 this.mainApplicationClass = deduceMainApplicationClass(); }


    1.2 运行run()方法

    准备环境(ApplicationContextInitialier和SpringApplicationRunListener配置在META-INF/spring.factories) 执行ApplicationContextInitialier.initialize()监听器SpringApplicationRunListener回调contextPrepared加载主配置类定义信息监听器SpringApplicationRunListener回调contextLoader 刷新启动IOC容器 扫描加载所有容器中的组件包括从META-INF/spring.factories中获取的所有EnableAutoConfiguration组件 回调容器中所有ApplicationRunner、CommandLineRunner的run()方法(只需放在ioc容器中)监听器SpringApplicationRunListener回调finished public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); //获取SpringApplicationRunListeners,从类路径下META-INF/spring.factories SpringApplicationRunListeners listeners = getRunListeners(args); //回调所有的获取SpringApplicationRunListener.starting()方法 listeners.starting(); try { //封装命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //创建环境完成后回调SpringApplicationRunListener.environmentPrepared():表示环境准备完成 Banner printedBanner = printBanner(environment); //创建ApplicationContext:决定创建web的ioc还是普通的ioc context = createApplicationContext(); analyzers = new FailureAnalyzers(context); //准备上下文环境;将environment保存到ioc中,而且applyInitializers(); //applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法 //回调所有的SpringApplicationRunListener的contextPrepared(); prepareContext(context, environment, listeners, applicationArguments, printedBanner); //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded(); //s刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat) //扫描,创建,加载所有组件的地方(配置类,组件,自动配置) refreshContext(context); //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调 //ApplicationRunner先回调,CommandLineRunner再回调 afterRefresh(context, applicationArguments); //所有的SpringApplicationRunListener回调finished方法 listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } //整个SpringBoot应用启动完成以后返回启动的ioc容器 return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }

    1.3 事件监听机制

    我们自己来写上面运行所需要的对象和监听器,用于代替springboot自带的

    创建listener.HelloApplicationContextInitializer public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("ApplicationContextInitializer...initialize..."+applicationContext); } } 创建listener.HelloSpringApplicationRunListener public class HelloSpringApplicationRunListener implements SpringApplicationRunListener { //必须有的构造器,不然会报错 public HelloSpringApplicationRunListener(SpringApplication application, String[] args){ } @Override public void starting() { System.out.println("SpringApplicationRunListener...starting..."); } @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..."); } }

    下面两个是放在容器中的

    创建listener.HelloApplicationRunner @Component public class HelloApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("ApplicationRunner...run...."); } } 创建listener.HelloCommandLineRunner @Component public class HelloCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("CommandLineRunner...run..."+ Arrays.asList(args)); } } 配置(模仿META-INF/spring.factories的写法),在resources下创建META-INF/spring.factories org.springframework.context.ApplicationContextInitializer=\ com.sb.listener.HelloApplicationContextInitializer org.springframework.boot.SpringApplicationRunListener=\ com.sb.listener.HelloSpringApplicationRunListener 运行

    2. 自定义starter

    这个部分主要是针对 1、我们自定义的场景需要使用到的依赖是什么? 2、如何编写自动配置?

    2.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,\ 自动装配Bean 自动装配使用配置类(@Configuration)结合Spring4提供给的条件判断注解@Conditional及Spring Boot的派生注解如@ConditionalOnClass完成配置自动装配Bean 将标注@Configuration自动配置类,放在classpath下META-INF/spring.factories文件中

    2.2 启动器(starter)

    启动器模块是一个空jar文件,仅提供辅助性依赖管理,这些依赖可能用于自动装配或其他类库

    2.2.1 命名规范
    官方命名 前缀:spring-boot-starter-,spring-boot-starter-模块名,如spring-boot-starter-web自定义命名 后缀:-spring-boot-starter,模块-spring-boot-starter,如mybatis-spring-boot-starter
    2.2.2 启动模式

    启动器只用来做依赖导入,专门来写一个自动配置模块,启动器依赖自动配置,别人只需要引入启动器(starter)

    我们来创建一个工程来进一步认识一下

    注意是空工程 创建maven模块 然后再创建一个springboot模块(什么环境都不加),略 给maven模块导入spring模块的starter依赖

    <!--启动器--> <dependencies> <!--引入自动配置模块--> <dependency> <groupId>com.starter</groupId> <artifactId>sb-starter</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>

    删除spring模块的主启动类,把依赖的单元测试和插件都删除,只留下starter依赖,这样看起来更清晰,略

    创建Hello.HelloService

    public class HelloService { HelloProperties helloProperties; public HelloProperties getHelloProperties() { return helloProperties; } public void setHelloProperties(HelloProperties helloProperties) { this.helloProperties = helloProperties; } public String sayHello(String name){ return helloProperties.getPrefix()+"-" +name + helloProperties.getSuffix(); } }

    创建Hello.HelloProperties

    @ConfigurationProperties(prefix = "tiaotiao.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; } }

    创建Hello.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; } }

    在resources目录下创建META-INF/spring.factories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.starter.Hello.HelloServiceAutoConfiguration

    将模块安装到maven仓库中(这里的maven模块是依赖springboot模块的),点击idea右边的maven进行安装

    然后在新的窗口创建新的springboot项目(方便对比),在新项目中引入自定义的starter的依赖

    <!--引入自定义的starter启动器--> <dependency> <groupId>com.sb</groupId> <artifactId>starter01</artifactId> <version>1.0-SNAPSHOT</version> </dependency>

    可以看到我们的自定义stater依赖成功导入

    创建一个控制器方法controller.HelloController

    @RestController public class HelloController { @Autowired HelloService helloService; @GetMapping("/hello") public String hello(){ return helloService.sayHello("tiaotiao"); } }

    然后在配置文件中设置一下前后缀

    tiaotiao.hello.prefix=HELLO tiaotiao.hello.suffix=WORLD

    启动项目并访问 成功~

    本次spring boot的学习暂时到这,期待雷神老师的继续更新~完结撒花 ~~~


    该SpringBoot学习笔记学习自雷神前辈,是对知识点的整理和自我认识的梳理,如有不当之处,欢迎指出

    Processed: 0.017, SQL: 8