zoukankan      html  css  js  c++  java
  • springboot 启动配置原理【转】【补】

    创建应用

    几个重要的事件回调机制  , 配置在META-INF/spring.factories

    ApplicationContextInitializer

    SpringApplicationRunListener

     

    只需要放在ioc容器中

    ApplicationRunner

    CommandLineRunner

     

    一、创建SpringApplication对象

    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;然后保存起来 , 
        //比如spring-boot-autoconfigure-1.5.14.RELEASE.jar包的类路径下的/META-INF/spring.factories就有org.springframework.context.ApplicationContextInitializer=xxx,xxx
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //从类路径下找到META-INF/spring.factories配置的所有ApplicationListener, 
        //比如spring-boot-autoconfigure-1.5.14.RELEASE.jar包的类路径下的/META-INF/spring.factories就有org.springframework.context.ApplicationListener=xxx,xxx
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //从多个配置类中找到有main方法的主配置类
        this.mainApplicationClass = deduceMainApplicationClass();
    }

    ApplicationContextInitializer.class一开始有以下几个类从/META-INF/spring.factories被加载

    ApplicationListener.class一开始有以下几个类从/META-INF/spring.factories被加载

     

    二、运行run方法

     new SpringApplication(sources).run(args)

    public ConfigurableApplicationContext run(String... args) {
       StopWatch stopWatch = new StopWatch();
       stopWatch.start();
       ConfigurableApplicationContext context = null;
       FailureAnalyzers analyzers = null;
       configureHeadlessProperty();
        
        //从类路径下找到META-INF/spring.factories配置的所有SpringApplicationRunListeners, 
        //比如spring-boot-autoconfigure-1.5.14.RELEASE.jar包的类路径下的/META-INF/spring.factories就有org.springframework.context.SpringApplicationRunListeners=xxx,xxx
       SpringApplicationRunListeners listeners = getRunListeners(args);//内部方法是 getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
        //回调所有的获取SpringApplicationRunListener.starting()方法
       listeners.starting();
       try {
           //封装命令行参数
          ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
          //准备环境, 配置profile,logger,peroertySources等等
          ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
          //创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
           
           //日志中打印springBoot的Banner(log)
          Banner printedBanner = printBanner(environment);
           
           //创建ApplicationContext;决定创建web的ioc还是普通的ioc ,方法内部使用BeanUtils.instantiate(contextClass)反射来创建
          context = createApplicationContext();
           
           //出现异常后, 在本方法最后做异常分析报告用的
          analyzers = new FailureAnalyzers(context);
           
         
          prepareContext(context, environment, listeners, applicationArguments,printedBanner);
                   ///{
                //context.setEnvironment(environment);    准备上下文环境;将environment保存到ioc即context中
                   //applyInitializers(context);    回调之前保存的所有的ApplicationContextInitializer的initialize()方法
                   //listeners.contextPrepared(context);    回调所有的SpringApplicationRunListener的contextPrepared();
                   //context.getBeanFactory().registerSingleton("springApplicationArguments",applicationArguments); 注册命令行参数对象
                   //listeners.contextLoaded(context);    回调所有的SpringApplicationRunListener的contextLoaded(),表示环境准备好了
                   //}
           
           
           //刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版中有说明
           //扫描,创建,加载所有组件,包括自动(配置)类,@Bean组件等等
          refreshContext(context);
                   //{....
                   //finishBeanFactoryInitialization(beanFactory); //初始化所有非延迟加载的单实例bean
                   //...}
           //从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);
       }
    }

    3、自定义事件监听器

    配置在META-INF/spring.factories

    ApplicationContextInitializer

    ApplicationContextInitializer本身是个接口, 里面的泛型C用于监听ConfigurableApplicationContext

    public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
        void initialize(C var1);
    }
     
    public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {
            System.err.println("MyApplicationContextInitializer " + applicationContext);
        }
    }

     

    SpringApplicationRunListener

    必须有的构造器 , 不然会无法初始该类型的监听器

    public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    
        /**
         * 必须有的构造器 , 不然会无法初始该类型的监听器
         */
        public MySpringApplicationRunListener(SpringApplication application, String[] args){
    
        }
    
        @Override
        public void starting() {
            System.err.println("MySpringApplicationRunListener starting");
        }
    
        @Override
        public void environmentPrepared(ConfigurableEnvironment environment) {
            //可以获取环境变量
            Object os_name = environment.getSystemProperties().get("os.name");
            System.err.println("MySpringApplicationRunListener environmentPrepared , os_name : "+ os_name);
        }
    
        @Override
        public void contextPrepared(ConfigurableApplicationContext context) {
            System.err.println("MySpringApplicationRunListener contextPrepared");
        }
    
        @Override
        public void contextLoaded(ConfigurableApplicationContext context) {
            System.err.println("MySpringApplicationRunListener contextLoaded");
        }
    
        @Override
        public void finished(ConfigurableApplicationContext context, Throwable exception) {
            System.err.println("MySpringApplicationRunListener finished");
        }
    }

     

    注意:ApplicationContextInitializer , SpringApplicationRunListener 都需要配置在(META-INF/spring.factories)

    #具体可参考该文件配置 spring-boot-autoconfigure-1.5.14.RELEASE.jar!META-INFspring.factories
    
    #initializer , 代表换行衔接下一行;,分隔多个class类
    org.springframework.context.ApplicationContextInitializer=
    com.example.demo.config.listener.MyApplicationContextInitializer
    
    #listener
    org.springframework.context.SpringApplicationRunListener=
    com.example.demo.config.listener.MySpringApplicationRunListener

    ApplicationRunner

    @Component
    public class MyApplicationRunner implements ApplicationRunner {
        @Override
        public void run(ApplicationArguments args) throws Exception {
            System.out.println("ApplicationRunner...run...."+ Arrays.asList(args));
        }
    }

    CommandLineRunner

    @Component
    public class MyCommandLineRunner implements CommandLineRunner {
        @Override
        public void run(String... args) throws Exception {
            System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
        }
    }

    注意: ApplicationRunner , CommandLineRunner 只需要放在ioc容器中 , 即使用@Component注解

     

    自定义Starter 

  • 相关阅读:
    网站安全编程 黑客入侵 脚本黑客 高级语法入侵 C/C++ C# PHP JSP 编程
    【算法导论】贪心算法,递归算法,动态规划算法总结
    cocoa2dx tiled map添加tile翻转功能
    8月30日上海ORACLE大会演讲PPT下载
    【算法导论】双调欧几里得旅行商问题
    Codeforces Round #501 (Div. 3) B. Obtaining the String (思维,字符串)
    Codeforces Round #498 (Div. 3) D. Two Strings Swaps (思维)
    Educational Codeforces Round 89 (Rated for Div. 2) B. Shuffle (数学,区间)
    洛谷 P1379 八数码难题 (BFS)
    Educational Codeforces Round 89 (Rated for Div. 2) A. Shovels and Swords (贪心)
  • 原文地址:https://www.cnblogs.com/whatlonelytear/p/9023114.html
Copyright © 2011-2022 走看看