springBoot学习笔记九

SpringBoot启动流程

1574497298469

启动原理

    public static void main(String[] args) {
        //xxx.class:主配置类,(可以传多个)
        SpringApplication.run(xxx.class, args);
    }Copy to clipboardErrorCopied
  1. 从run方法开始,创建SpringApplication,然后再调用run方法

    /**
     * ConfigurableApplicationContext(可配置的应用程序上下文)
     */
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        //调用下面的run方法
        return run(new Class[]{primarySource}, args);
    }
    
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }Copy to clipboardErrorCopied
    
  2. 创建SpringApplication

    //primarySources:主配置类
    new SpringApplication(primarySources)Copy to clipboardErrorCopied
    
        public SpringApplication(Class<?>... primarySources) {
            //调用下面构造方法
            this((ResourceLoader) null, primarySources);
        }
    
        public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.sources = new LinkedHashSet();
            this.bannerMode = Mode.CONSOLE;
            this.logStartupInfo = true;
            this.addCommandLineProperties = true;
            this.addConversionService = true;
            this.headless = true;
            this.registerShutdownHook = true;
            this.additionalProfiles = new HashSet();
            this.isCustomEnvironment = false;
            this.lazyInitialization = false;
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            //保存主配置类
            this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
            //获取当前应用的类型,是不是web应用,见2.1
            this.webApplicationType = WebApplicationType.deduceFromClasspath();
            //从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来,见2.2
            this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
            //从类路径下找到META‐INF/spring.ApplicationListener;然后保存起来,原理同上
            this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
            //从多个配置类中找到有main方法的主配置类,见下图(在调run方法的时候是可以传递多个配置类的)
            this.mainApplicationClass = this.deduceMainApplicationClass();
            //执行完毕,SpringApplication对象就创建出来了,返回到1处,调用SpringApplication对象的run方法,到3
        }Copy to clipboardErrorCopied
    

    1574503716694

    2.1 判断是不是web 应用 2.2 getSpringFactoriesInstances(ApplicationContextInitializer.class)
  3. 调用SpringApplication对象的run方法

    1574512218795

        public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            //声明IOC容器
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
            this.configureHeadlessProperty();
            //从类路径下META‐INF/spring.factories获取SpringApplicationRunListeners,原理同2中获取ApplicationContextInitializer和ApplicationListener
            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            //遍历上一步获取的所有SpringApplicationRunListener,调用其starting方法
            listeners.starting();
    
            Collection exceptionReporters;
            try {
                //封装命令行
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                //准备环境,把上面获取到的listeners传过去,见3.1
                ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
                this.configureIgnoreBeanInfo(environment);
                //打印Banner,就是控制台那个Spring字符画
                Banner printedBanner = this.printBanner(environment);
                //根据当前环境利用反射创建IOC容器
                context = this.createApplicationContext();
            //从类路径下META‐INF/spring.factories获取SpringBootExceptionReporter,原理同2中获取ApplicationContextInitializer和ApplicationListener
                exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
                //准备IOC容器,见3.3
                this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                //刷新IOC容器,可查看配置嵌入式Servlet容器原理 链接在3.4
                this.refreshContext(context);
                //这是一个空方法
                this.afterRefresh(context, applicationArguments);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
                }
                //调用所有SpringApplicationRunListener的started方法
                listeners.started(context);
                //见3.5 ,从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调ApplicationRunner先回调,CommandLineRunner再
                this.callRunners(context, applicationArguments);
            } catch (Throwable var10) {
                this.handleRunFailure(context, var10, exceptionReporters, listeners);
                throw new IllegalStateException(var10);
            }
    
            try {
                //调用所有SpringApplicationRunListener的running方法
                listeners.running(context);
                return context;
            } catch (Throwable var9) {
                this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
                throw new IllegalStateException(var9);
            }
        }Copy to clipboardErrorCopied
    

    //容器创建完成,返回步骤1处,最后返回到启动类

    3.1 3.2 3.3 3.4 3.5

几个重要的事件回调机制

配置在META-INF/spring.factories

  • ApplicationContextInitializer
  • SpringApplicationRunListener

只需要放在ioc容器中

  • ApplicationRunner
  • CommandLineRunner

测试

  1. 创建ApplicationContextInitializerSpringApplicationRunListener的实现类,并在META-INF/spring.factories文件中配置

    public class TestApplicationContextInitializer implements ApplicationContextInitializer {
    
        @Override
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            System.out.println("TestApplicationContextInitializer.initialize");
        }
    }Copy to clipboardErrorCopied
    
    public class TestSpringApplicationRunListener implements SpringApplicationRunListener {
        @Override
        public void starting() {
            System.out.println("TestSpringApplicationRunListener.starting");
        }
    
        @Override
        public void environmentPrepared(ConfigurableEnvironment environment) {
            System.out.println("TestSpringApplicationRunListener.environmentPrepared");
        }
    
        @Override
        public void contextPrepared(ConfigurableApplicationContext context) {
            System.out.println("TestSpringApplicationRunListener.contextPrepared");
        }
    
        @Override
        public void contextLoaded(ConfigurableApplicationContext context) {
            System.out.println("TestSpringApplicationRunListener.contextLoaded");
        }
    
        @Override
        public void started(ConfigurableApplicationContext context) {
            System.out.println("TestSpringApplicationRunListener.started");
        }
    
        @Override
        public void running(ConfigurableApplicationContext context) {
            System.out.println("TestSpringApplicationRunListener.running");
        }
    
        @Override
        public void failed(ConfigurableApplicationContext context, Throwable exception) {
            System.out.println("TestSpringApplicationRunListener.failed");
        }
    }Copy to clipboardErrorCopied
    
    org.springframework.context.ApplicationContextInitializer=\
    cn.clboy.springbootprocess.init.TestApplicationContextInitializer
    
    org.springframework.boot.SpringApplicationRunListener=\
    cn.clboy.springbootprocess.init.TestSpringApplicationRunListenerCopy to clipboardErrorCopied
    

    启动报错:说是没有找到带org.springframework.boot.SpringApplication和String数组类型参数的构造器,给TestSpringApplicationRunListener添加这样的构造器

    1574515721669

        public TestSpringApplicationRunListener(SpringApplication application,String[] args) {
        }Copy to clipboardErrorCopied
    
  2. 创建ApplicationRunner实现类和CommandLineRunner实现类,注入到容器中

    @Component
    public class TestApplicationRunner implements ApplicationRunner {
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            System.out.println("TestApplicationRunner.run\t--->"+args);
        }
    }Copy to clipboardErrorCopied
    
    @Component
    public class TestCommandLineRunn implements CommandLineRunner {
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("TestCommandLineRunn.runt\t--->"+ Arrays.toString(args));
        }
    }Copy to clipboardErrorCopied
    

    1574517578711

修改Banner

默认是找类路径下的banner.txt,可以在配置文件中修改

spring.banner.location=xxx.txtCopy to clipboardErrorCopied

生成banner的网站:http://patorjk.com/software/taag

1574508283758

也可以使用图片(将其像素解析转换成assii编码之后打印),默认是在类路径下找名为banner后缀为"gif", "jpg", "png"的图片

static final String[] IMAGE_EXTENSION = new String[]{"gif", "jpg", "png"};Copy to clipboardErrorCopied

也可以在配置文件中指定

spring.banner.image.location=classpath:abc.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值