SpringBoot启动流程分析原理(二)

本次开始查看run()方法之后做了哪些事情

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        // 计时器开始
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        // 配置Headless模式,是在缺少显示屏、键盘或者鼠标时的系统配置
        // 默认为true
        this.configureHeadlessProperty();
        // 获取所有的监听器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        // 启动监听器
        listeners.starting();<br />

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //准备环境            
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            // 配置忽略的bean
            this.configureIgnoreBeanInfo(environment);
            // 打印banner
            Banner printedBanner = this.printBanner(environment);
            // 创建容器
            context = this.createApplicationContext();
            //异常处理相关            
            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);
            // 执行runner
            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);
        }
    }

一、获取所有的监听器

 private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }
 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

这段代码我们比较熟悉了,上一篇咱么详细介绍过,它的主要作用就是去 META-INFO/spring.properties 中加载配置 SpringApplicationRunListener 的监听器如下:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=
org.springframework.boot.context.event.EventPublishingRunListener

这里只有一个事件发布监听器类,拿到了EventPublishingRunListener启动事件发布监听器,下一步就是开始启动了listeners.starting()

 public void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }

启动的时候,又创建一个ApplicationStartingEvent对象,其实就是监听应用十七栋事件。
其中initialMulticaster是一个SimpleApplicationEventMulticaster

   public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        Iterator var4 = this.getApplicationListeners(event, type).iterator();

        while(var4.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }

    }

二、准备环境

  ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
  private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        //这里因为加了web的依赖,所以是一个servert容器
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        //配置环境 
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        // 环境准备完成
        listeners.environmentPrepared((ConfigurableEnvironment)environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }

        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }

由于我们添加了web的依赖getOrCreateEnvironment()返回的是一个标准的servlet的环境。
2.1配置环境

    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            //嵌入式的转换器
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService)conversionService);
        }
        //配置属性资源文件
        this.configurePropertySources(environment, args);
        // 配置文件
        this.configureProfiles(environment, args);
    }

应用嵌入的转换器ApplicationConversionService

    public static void configure(FormatterRegistry registry) {
        DefaultConversionService.addDefaultConverters(registry);
        DefaultFormattingConversionService.addDefaultFormatters(registry);
        addApplicationFormatters(registry);
        addApplicationConverters(registry);
    }
// 格式转换
  public static void addApplicationFormatters(FormatterRegistry registry) {
        registry.addFormatter(new CharArrayFormatter());
        registry.addFormatter(new InetAddressFormatter());
        registry.addFormatter(new IsoOffsetFormatter());
    }
// 类型转换
 public static void addApplicationConverters(ConverterRegistry registry) {
        addDelimitedStringConverters(registry);
        registry.addConverter(new StringToDurationConverter());
        registry.addConverter(new DurationToStringConverter());
        registry.addConverter(new NumberToDurationConverter());
        registry.addConverter(new DurationToNumberConverter());
        registry.addConverter(new StringToDataSizeConverter());
        registry.addConverter(new NumberToDataSizeConverter());
        registry.addConverterFactory(new StringToEnumIgnoringCaseConverterFactory());
    }

2.1环境准备完成

同上面的启动监听事件,这次的环境准备也是同样的代码

    public void environmentPrepared(ConfigurableEnvironment environment) {
        Iterator var2 = this.listeners.iterator();

        while(var2.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
            listener.environmentPrepared(environment);
        }

    }

//创建一个应用环境准备事件对象
  public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }

进去以后和代码和ApplicationStartingEvent事件对象一样。不过这里是7个监听对象

3.配置忽略的bean

this.configureIgnoreBeanInfo(environment);

4、打印banner

SpringBoot启动时的默认图标

 Banner printedBanner = this.printBanner(environment);

这个是可以自定义的,也可以是图层或者文本文件中的图形

5、创建容器
紧接着,开始创建容器

 context = this.createApplicationContext();


我们的环境是servelt,通过反射的方式创建对象,并且实例化AnnotationConfigServletWebServerApplicationContext对象
6、异常错误处理

   exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);

其实还是去META-INFO/spring.factories配置文件中加载SpringBootExceptionReporter类

# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=org.springframework.boot.diagnostics.FailureAnalyzers

7、准备应用上下文

 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        // 设置环境参数
        context.setEnvironment(environment);
        设置后处理应用上下文
        this.postProcessApplicationContext(context);
        把从spring.properties中加载的org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,进行初始化操作
        this.applyInitializers(context);
        //EventPublishingRunLIstener发布应用上下文事件
        listeners.contextPrepared(context);
        //打印启动日志
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //注册一个字是springApplicationArguments单例的bean
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            //注册一个字是springBootBanner单例的bean,
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }

        if (beanFactory instanceof DefaultListableBeanFactory) {
            //覆盖同名的bean
            ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        //Load the sources 获取所有资源
        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //创建BeanDefinitionLoader加载器加载注册所有的资源
        this.load(context, sources.toArray(new Object[0]));
         //同之前,发布应用上下文加载事件
        listeners.contextLoaded(context);
    }

8、刷新应用上下文

刷新后,进入spring的源码

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            //准备刷新上下文
            this.prepareRefresh();
            // 通知子类刷新内部工厂
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            // 准备Bean工厂
            this.prepareBeanFactory(beanFactory);

            try {
                // 运行在上下文子类中对bean工厂进行后处理
                this.postProcessBeanFactory(beanFactory);
                // 调用上下文中注册为bean的工厂处理器
                this.invokeBeanFactoryPostProcessors(beanFactory);
                // 注册后置处理器
                this.registerBeanPostProcessors(beanFactory);
                // 初始化信息源
                this.initMessageSource();
                // 初始化上下文事件发布器
                this.initApplicationEventMulticaster();
                // 初始化其他自定义bean
                this.onRefresh();
                // 注册其他自定义bean
                this.registerListeners();
                // 完成bean工厂初始化
                this.finishBeanFactoryInitialization(beanFactory);
                // 完成刷新,清缓存,初始化生命周期,事件发布
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
                //销毁bean
                this.destroyBeans();
                // 重置active标志
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                // 重置Spring核心中的常见内省缓存
                this.resetCommonCaches();
            }

        }
    }

刷新的代码比较深,也是在这个时候创建了Tomcat对象,这也是SpringBoot一键启动web工程的关键

    @Override
    protected void onRefresh() {
        super.onRefresh();
        try {
            // 创建web服务
            createWebServer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start web server", ex);
        }
    }
private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        if (webServer == null && servletContext == null) {
            ServletWebServerFactory factory = getWebServerFactory();
            //获取到tomcat
            this.webServer = factory.getWebServer(getSelfInitializer());
        }
        else if (servletContext != null) {
            try {
                getSelfInitializer().onStartup(servletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context",
                        ex);
            }
        }
        initPropertySources();
    }

创建了tomcat对象,并设置参数

@Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
        File baseDir = (this.baseDirectory != null) ? this.baseDirectory
                : createTempDir("tomcat");
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        Connector connector = new Connector(this.protocol);
        tomcat.getService().addConnector(connector);
        customizeConnector(connector);
        tomcat.setConnector(connector);
        tomcat.getHost().setAutoDeploy(false);
        configureEngine(tomcat.getEngine());
        for (Connector additionalConnector : this.additionalTomcatConnectors) {
            tomcat.getService().addConnector(additionalConnector);
        }
        prepareContext(tomcat.getHost(), initializers);
        // 返回tomcatWebServer服务
        return getTomcatWebServer(tomcat);
    }

启动tomcat

public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
        Assert.notNull(tomcat, "Tomcat Server must not be null");
        this.tomcat = tomcat;
        this.autoStart = autoStart;
        initialize();
    }

    private void initialize() throws WebServerException {
        logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
        synchronized (this.monitor) {
            try {
                addInstanceIdToEngineName();

                Context context = findContext();
                context.addLifecycleListener((event) -> {
                    if (context.equals(event.getSource())
                            && Lifecycle.START_EVENT.equals(event.getType())) {
                        // 删除服务连接器,以便在服务启动时不会发生协议绑定
                        removeServiceConnectors();
                    }
                });

                // 启动服务器以触发初始化侦听器
                this.tomcat.start();

                // 我们可以直接在主线程中重新抛出失败异常
                rethrowDeferredStartupExceptions();

                try {
                    ContextBindings.bindClassLoader(context, context.getNamingToken(),
                            getClass().getClassLoader());
                }
                catch (NamingException ex) {
                    // 未启用命名。继续
                }

                // 与Jetty不同,所有Tomcat线程都是守护进程线程。我们创建一个阻塞的非守护进程来停止立即关闭
                startDaemonAwaitThread();
            }
            catch (Exception ex) {
                stopSilently();
                throw new WebServerException("Unable to start embedded Tomcat", ex);
            }
        }
    }

9、刷新后处理

afterRefresh()是一个空实现,留着后期扩展

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
    // TODO
}

10、发布监听应用启动事件

@Override
    public void started(ConfigurableApplicationContext context) {
        context.publishEvent(
                new ApplicationStartedEvent(this.application, this.args, context));
    }

这里是调用context.publishEvent()方法,发布应用启动事件ApplicationStartedEvent
11、执行runner
获取所有的ApplicationRunner和CommandLineRunner来初始化一些参数
callRunners()是一个回调函数

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        Iterator var4 = (new LinkedHashSet(runners)).iterator();

        while(var4.hasNext()) {
            Object runner = var4.next();
            if (runner instanceof ApplicationRunner) {
                this.callRunner((ApplicationRunner)runner, args);
            }

            if (runner instanceof CommandLineRunner) {
                this.callRunner((CommandLineRunner)runner, args);
            }
        }

    }

12、发布上下文准备完成的事件

 listeners.running(context);
    @Override
    public void running(ConfigurableApplicationContext context) {
        context.publishEvent(
                new ApplicationReadyEvent(this.application, this.args, context));
    }
前面有很多类似的代码,不同的是这里上下文准备完成之后发布了一个ApplicationReadyEvent事件,声明一下应用上下文准备完成

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注