SpringBoot启动流程

阶段一:SpringApplication 构造

  1. 记录 BeanDefinition 源

  2. 推断应用类型

  3. 记录 ApplicationContext 初始化器

  4. 记录监听器

  5. 推断主启动类

package com.butch.a39;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.reflect.Method;
import java.util.Set;

@Configuration
public class A39_1 {


    public static void main(String[] args) throws Exception {

        System.out.println("1. 演示获取 Bean Definition 源");
        //主要源即就是引导所在的源,存在bd 初始化的dbmap为空,来源配置类、或者xml
        SpringApplication spring = new SpringApplication(A39_1.class);
        System.out.println("2. 演示推断应用类型");
        Method deduceFromClasspath = WebApplicationType.class.getDeclaredMethod("deduceFromClasspath");
        deduceFromClasspath.setAccessible(true);
        System.out.println("\t应用类型为:"+deduceFromClasspath.invoke(null));
        //对applicationcontext容器扩展
        System.out.println("3. 演示 ApplicationContext 初始化器");
        spring.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
            @Override
            public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
                GenericApplicationContext configurableApplicationContext1 = (GenericApplicationContext) configurableApplicationContext;
                configurableApplicationContext1.registerBean("bean3",Bean3.class);
            }
        });
        System.out.println("4. 演示监听器与事件");
        spring.addListeners(new ApplicationListener<ApplicationEvent>() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("\t事件为:" + event.getClass());
            }
        });
        System.out.println("5. 演示主类推断");
        Method deduceMainApplicationClass = SpringApplication.class.getDeclaredMethod("deduceMainApplicationClass");
        deduceMainApplicationClass.setAccessible(true);
        System.out.println("\t主类是:"+deduceMainApplicationClass.invoke(spring));

        ConfigurableApplicationContext applicationContext = spring.run(args);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName = " + beanDefinitionName);
            String resourceDescription = applicationContext.getBeanFactory().getBeanDefinition(beanDefinitionName).getResourceDescription();
            System.out.println("resourceDescription = " + resourceDescription);
        }
        applicationContext.close();
    }

    static class Bean1 {

    }

    static class Bean2 {

    }

    static class Bean3 {

    }

    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }

    @Bean
    public TomcatServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }
}


阶段二:run

阶段二:执行 run 方法

  1. 得到 SpringApplicationRunListeners,名字取得不好,实际是事件发布器

    • 发布 application starting 事件1️⃣

  2. 封装启动 args

  3. 准备 Environment 添加命令行参数(*)

  4. ConfigurationPropertySources 处理(*)

    • 发布 application environment 已准备事件2️⃣

  5. 通过 EnvironmentPostProcessorApplicationListener 进行 env 后处理(*)

    • application.properties,由 StandardConfigDataLocationResolver 解析

    • spring.application.json

  6. 绑定 spring.main 到 SpringApplication 对象(*)

  7. 打印 banner(*)

  8. 创建容器

  9. 准备容器

    • 发布 application context 已初始化事件3️⃣

  10. 加载 bean 定义

    • 发布 application prepared 事件4️⃣

  11. refresh 容器

    • 发布 application started 事件5️⃣

  12. 执行 runner

    • 发布 application ready 事件6️⃣

    • 这其中有异常,发布 application failed 事件7️⃣

源码
public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
    //创建事件发布器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
    //发布springboot程序开始创建事件
        listeners.starting();

        Collection exceptionReporters;
        try {
            //第二步封装参数对象
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //第三步到第六步创建环境对象 增加配置源 统一配置格式 获取参数配置绑定参数
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            //第七步打印banner
            Banner printedBanner = this.printBanner(environment);
            //第八步创建spring容器
            context = this.createApplicationContext();
               //第九步 prepareContext 应用初始化器 发布容器创建好事件
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            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);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
1事件发布

发布容器开始启动事件

springBoot主要事件

发布 application starting 事件1️⃣

发布 application environment 已准备事件2️⃣

发布 application context 已初始化事件3️⃣

发布 application prepared 事件4️⃣

发布 application started 事件5️⃣

发布 application ready 事件6️⃣

这其中有异常,发布 application failed 事件7️⃣

package com.butch.a39;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.boot.context.event.EventPublishingRunListener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;
//import org.springframework.boot.DefaultBootstrapContext;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class A39_2 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        //添加监听器,当有事件发布会监听到输出
        SpringApplication springApplication = new SpringApplication();
        springApplication.addListeners(new ApplicationListener() {
            @Override
            public void onApplicationEvent(ApplicationEvent applicationEvent) {
                System.out.println("applicationEvent = " + applicationEvent);
            }
        });
        //EventPublishingRunListener发布时间的接口,里面提供了springboot发布的时间类型,其实现类在factories中配置
        //通过配置文件获取其实现类
        List<String> names = SpringFactoriesLoader.loadFactoryNames(SpringApplicationRunListener.class, A39_2.class.getClassLoader());
        for (String name : names) {
            //name = org.springframework.boot.context.event.EventPublishingRunListener
            System.out.println("name = " + name);
            //通过反射获取这个实现类的对象
            Class<?> aClass = Class.forName(name);
            //有参构造器
            Constructor<?> constructor = aClass.getConstructor(SpringApplication.class, String[].class);
            EventPublishingRunListener publisher = (EventPublishingRunListener) constructor.newInstance(springApplication, args);

            //开始发布事件

            publisher.starting(); //boot程序开始启动
            publisher.environmentPrepared(new StandardEnvironment()); //环境信息准备完毕
            GenericApplicationContext context = new GenericApplicationContext();

            publisher.contextPrepared(context); //spring容器创建 并且初始化器调用之后
            publisher.contextLoaded(context); //beandMap加载完毕
            context.refresh();

            publisher.started(context); //spring容器初始化完成 refresh完成

            publisher.running(context); //boot程序启动完毕

            publisher.failed(context,new RuntimeException()); //启动出现错误

        }
    }

}

流程2 及8-12
package com.butch.a39;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.*;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;

import java.util.Arrays;
import java.util.Map;

public class A39_3 {
    @SuppressWarnings("all")
    public static void main(String[] args) throws Exception {
        //增加初始化器
        //添加之后不会执行这个初始化器 当容器创建好才会的回调
        SpringApplication springApplication = new SpringApplication();
        springApplication.addInitializers(new ApplicationContextInitializer() {
            @Override
            public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
                System.out.println("执行初始化器增强...");
            }
        });


        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 2. 封装启动 args");
        //12步调用的参数包装
        DefaultApplicationArguments arguments = new DefaultApplicationArguments(args);

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 8. 创建容器");
        GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 9. 准备容器");
        //回调初始化器
        for (ApplicationContextInitializer initializer : springApplication.getInitializers()) {
            initializer.initialize(context);
        }
        //通过各种来源
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 10. 加载 bean 定义");
        //获取容器bean工厂 即读取的位置
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
        //配置类中
        AnnotatedBeanDefinitionReader reader1 = new AnnotatedBeanDefinitionReader(beanFactory);
        //xml配置中
        XmlBeanDefinitionReader reader2 = new XmlBeanDefinitionReader(beanFactory);
        //类路径下
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
        reader1.register(Config.class);
        reader2.loadBeanDefinitions(new ClassPathResource("b03.xml"));
        scanner.scan("com.butch.a39.sub");
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 11. refresh 容器");
        context.refresh();

        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println("name:" + beanDefinitionName + " 来源:" + beanFactory.getBeanDefinition(beanDefinitionName).getResourceDescription());
        }
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 12. 执行 runner");
        //runner即为实现特定接口的bean bean中有run方法 applicaitonruunner 和commandlineruuner 数据的预加载等 进行回调 ,两种runner主要是参数的获取传递不一样
        //运行时请添加运行参数 --server.port=8080 debug
        Map<String, CommandLineRunner> beansOfType = context.getBeansOfType(CommandLineRunner.class);
        for (CommandLineRunner value : beansOfType.values()) {
            value.run(args);
        }
        Map<String, ApplicationRunner> beansOfType1 = context.getBeansOfType(ApplicationRunner.class);
        for (ApplicationRunner value : beansOfType1.values()) {
            value.run(arguments);
        }

    }

    private static GenericApplicationContext createApplicationContext(WebApplicationType type) {
        GenericApplicationContext context = null;
        switch (type) {
            case SERVLET:
                context = new AnnotationConfigServletWebServerApplicationContext();
                break;
            case REACTIVE:
                context = new AnnotationConfigReactiveWebServerApplicationContext();
                break;
            case NONE:
                context = new AnnotationConfigApplicationContext();
                break;
        }
        return context;
    }


    static class Bean4 {

    }

    static class Bean5 {

    }

    static class Bean6 {

    }

    @Configuration
    static class Config {
        @Bean
        public Bean5 bean5() {
            return new Bean5();
        }

        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        @Bean
        public CommandLineRunner commandLineRunner() {
            return new CommandLineRunner() {
                @Override
                public void run(String... args) throws Exception {
                    System.out.println("commandLineRunner()..." + Arrays.toString(args));
                }
            };
        }

        @Bean
        public ApplicationRunner applicationRunner() {
            return new ApplicationRunner() {
                @Override
                public void run(ApplicationArguments args) throws Exception {
                    System.out.println("applicationRunner()..." + Arrays.toString(args.getSourceArgs()));
                    System.out.println(args.getOptionNames());
                    //参数分类
                    System.out.println(args.getOptionValues("server.port"));
                    System.out.println(args.getNonOptionArgs());
                }
            };
        }

    }
}
>>>>>>>>>>>>>>>>>>>>>>>> 2. 封装启动 args
>>>>>>>>>>>>>>>>>>>>>>>> 8. 创建容器
>>>>>>>>>>>>>>>>>>>>>>>> 9. 准备容器
执行初始化器增强...
>>>>>>>>>>>>>>>>>>>>>>>> 10. 加载 bean 定义
22:01:28.003 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [b03.xml]
22:01:28.029 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\ideaworkspace\ioc_demo\demo1\target\classes\com\butch\a39\sub\Bean7.class]
>>>>>>>>>>>>>>>>>>>>>>>> 11. refresh 容器
22:01:28.030 [main] DEBUG org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext - Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@4f7d0008
22:01:28.054 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
22:01:28.065 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory'
22:01:28.183 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
22:01:28.184 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
22:01:28.186 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
22:01:28.187 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
22:01:28.194 [main] DEBUG org.springframework.ui.context.support.UiApplicationContextUtils - Unable to locate ThemeSource with name 'themeSource': using default [org.springframework.ui.context.support.ResourceBundleThemeSource@327514f]
22:01:28.198 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'servletWebServerFactory'
22:01:28.199 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'a39_3.Config'
22:01:29.198 [main] DEBUG org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory - Code archive: D:\m2\repository\org\springframework\boot\spring-boot\2.2.5.RELEASE\spring-boot-2.2.5.RELEASE.jar
22:01:29.198 [main] DEBUG org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory - Code archive: D:\m2\repository\org\springframework\boot\spring-boot\2.2.5.RELEASE\spring-boot-2.2.5.RELEASE.jar
22:01:29.199 [main] DEBUG org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory - None of the document roots [src/main/webapp, public, static] point to a directory and will be ignored.
22:01:29.230 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
六月 03, 2024 10:01:29 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-8080"]
六月 03, 2024 10:01:29 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
六月 03, 2024 10:01:29 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.31]
六月 03, 2024 10:01:29 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring embedded WebApplicationContext
22:01:29.400 [main] DEBUG org.springframework.web.context.ContextLoader - Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
22:01:29.400 [main] INFO org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 1370 ms
22:01:29.414 [main] DEBUG org.springframework.boot.web.servlet.ServletContextInitializerBeans - Mapping filters: 
22:01:29.414 [main] DEBUG org.springframework.boot.web.servlet.ServletContextInitializerBeans - Mapping servlets: 
22:01:29.430 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean4'
22:01:29.431 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean7'
22:01:29.432 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean5'
22:01:29.433 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'commandLineRunner'
22:01:29.435 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'applicationRunner'
六月 03, 2024 10:01:29 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
22:01:29.485 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor 来源:null
name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor 来源:null
name:org.springframework.context.annotation.internalCommonAnnotationProcessor 来源:null
name:org.springframework.context.event.internalEventListenerProcessor 来源:null
name:org.springframework.context.event.internalEventListenerFactory 来源:null
name:a39_3.Config 来源:null
name:bean4 来源:class path resource [b03.xml]
name:bean7 来源:file [D:\ideaworkspace\ioc_demo\demo1\target\classes\com\butch\a39\sub\Bean7.class]
name:org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory 来源:null
name:bean5 来源:com.butch.a39.A39_3$Config
name:servletWebServerFactory 来源:com.butch.a39.A39_3$Config
name:commandLineRunner 来源:com.butch.a39.A39_3$Config
name:applicationRunner 来源:com.butch.a39.A39_3$Config
>>>>>>>>>>>>>>>>>>>>>>>> 12. 执行 runner
commandLineRunner()...[--server.port=8080, debug]
applicationRunner()...[--server.port=8080, debug]
[server.port]
[8080]
[debug]
流程3~6

和环境对象有关,系统变量,yaml综合

来源分为系统属性和系统变量

流程3添加命令行参数
package org.springframework.boot;

import org.springframework.core.env.PropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePropertySource;

import java.io.IOException;

public class Step3 {

    public static void main(String[] args) throws IOException {
        StandardEnvironment env = new StandardEnvironment(); // 系统环境变量, properties, yaml
        //添加其他来源 配置文件
        env.getPropertySources().addLast(new ResourcePropertySource(new ClassPathResource("application.properties")));
        //命令行来源 优先级最高 在program argments添加--server.port=8081
        env.getPropertySources().addFirst(new SimpleCommandLinePropertySource(args));
        for (PropertySource<?> propertySource : env.getPropertySources()) {
            //name='systemProperties' 优先找这个系统属性
            //name='systemEnvironment' 然后找系统环境变量
            System.out.println("propertySource = " + propertySource);
        }
        //这个只存在于系统变量
        //在系统属性添加-DJAVA_HOME=123
        System.out.println("env.getProperty(\"JAVA_HOME\") = " + env.getProperty("JAVA_HOME"));
        System.out.println("env.getProperty(\"server.prot\") = " + env.getProperty("server.port"));



    }
}
流程4统一配置的格式
package org.springframework.boot;

import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePropertySource;

import java.io.IOException;

public class Step4 {

    public static void main(String[] args) throws IOException {
        StandardEnvironment env = new StandardEnvironment(); // 系统环境变量, properties, yaml
        //加载特定源
        env.getPropertySources().addLast(
                new ResourcePropertySource("step4", new ClassPathResource("application.properties"))
        );

        for (PropertySource<?> propertySource : env.getPropertySources()) {
            System.out.println("propertySource = " + propertySource);
        }
        //统一加载方式
        ConfigurationPropertySources.attach(env);

        System.out.println(env.getProperty("user.first-name"));
        System.out.println(env.getProperty("user.middle-name"));
        System.out.println(env.getProperty("user.last-name"));

    }
}
流程5evironment后处理器增强

通过后置处理器增加更多的配置源

package org.springframework.boot;

import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;
import org.springframework.boot.context.event.EventPublishingRunListener;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.EnvironmentPostProcessorApplicationListener;
import org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor;
import org.springframework.boot.logging.DeferredLog;
import org.springframework.boot.logging.DeferredLogs;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.test.context.support.DefaultBootstrapContext;

import java.io.IOException;

public class Step5 {

    public static void main(String[] args) throws IOException {
        SpringApplication app = new SpringApplication();
        //添加 环境增强监听器
        app.addListeners(new EnvironmentPostProcessorApplicationListener());

        //获取EnvironmentPostProcessor所有的实现
        /*List<String> names = SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, Step5.class.getClassLoader());
        for (String name : names) {
            System.out.println(name);
        }*/

        //发布事件
        EventPublishingRunListener publisher = new EventPublishingRunListener(app, args);

        ApplicationEnvironment env = new ApplicationEnvironment();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强前");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }
        //发布环境准备完毕事件
        publisher.environmentPrepared(new DefaultBootstrapContext(), env);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }

    }

    private static void test1() {
        SpringApplication app = new SpringApplication();
        ApplicationEnvironment env = new ApplicationEnvironment();

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强前");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }
        //该后置处理器在2.4之后版本才有 会加载出application.properties
        ConfigDataEnvironmentPostProcessor postProcessor1 = new ConfigDataEnvironmentPostProcessor(new DeferredLogs(), new DefaultBootstrapContext());
        postProcessor1.postProcessEnvironment(env, app);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }
        //返回一个随机的值
        RandomValuePropertySourceEnvironmentPostProcessor postProcessor2 = new RandomValuePropertySourceEnvironmentPostProcessor(new DeferredLog());
        postProcessor2.postProcessEnvironment(env, app);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }
        System.out.println(env.getProperty("server.port"));
        System.out.println(env.getProperty("random.int"));
        System.out.println(env.getProperty("random.int"));
        System.out.println(env.getProperty("random.int"));
        System.out.println(env.getProperty("random.uuid"));
        System.out.println(env.getProperty("random.uuid"));
        System.out.println(env.getProperty("random.uuid"));
    }
}

流程6binder配置绑定spring.main
package org.springframework.boot;

import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePropertySource;

import java.io.IOException;

public class step6 {

    // 绑定 spring.main 前缀的 key value 至 SpringApplication, 请通过 debug 查看
    public static void main(String[] args) throws IOException {
        SpringApplication application = new SpringApplication();
        ApplicationEnvironment env = new ApplicationEnvironment();
        env.getPropertySources().addLast(new ResourcePropertySource("step4", new ClassPathResource("step4.properties")));
        env.getPropertySources().addLast(new ResourcePropertySource("step6", new ClassPathResource("step6.properties")));

//        User user = Binder.get(env).bind("user", User.class).get();
//        System.out.println(user);

//        User user = new User();
//        Binder.get(env).bind("user", Bindable.ofInstance(user));
//        System.out.println(user);

        System.out.println(application);
        Binder.get(env).bind("spring.main", Bindable.ofInstance(application));
        System.out.println(application);
    }

    static class User {
        private String firstName;
        private String middleName;
        private String lastName;
        public String getFirstName() {
            return firstName;
        }
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
        public String getMiddleName() {
            return middleName;
        }
        public void setMiddleName(String middleName) {
            this.middleName = middleName;
        }
        public String getLastName() {
            return lastName;
        }
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
        @Override
        public String toString() {
            return "User{" +
                    "firstName='" + firstName + '\'' +
                    ", middleName='" + middleName + '\'' +
                    ", lastName='" + lastName + '\'' +
                    '}';
        }
    }
}
流程7输出banner
package org.springframework.boot;

import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;

import java.util.HashMap;
import java.util.Map;

class Step7 {
    public static void main(String[] args) {
        //默认banner
        StandardEnvironment env = new StandardEnvironment();
        SpringApplicationBannerPrinter printer = new SpringApplicationBannerPrinter(
                new DefaultResourceLoader(),
                new SpringBootBanner()
        );
        // 测试文字 banner
        Map<String,Object> map = new HashMap<>();
        Map<String,Object> map1 = new HashMap<>();
//        map.put("spring.banner.location","banner1.txt");
        map1.put("spring.banner.location","banner2.png");
        env.getPropertySources().addLast(new MapPropertySource("custom",map));
        // 测试图片 banner
        env.getPropertySources().addLast(new MapPropertySource("custom", map1));
        // 版本号的获取
        System.out.println(SpringBootVersion.getVersion());
        printer.print(env, Step7.lass, System.out);
    }
}

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值