spring boot源码学习笔记(二)

注明:以下内容基于spring-boot-1.4.2,starter为spring-boot-starter-web。

继实例化SpringApplication以后,变量的初始化工作已经完成,紧接着就是调用run方法完成整个启动过程。run方法包含的代码行数不多,但是包含的逻辑并不少。

* from org.springframework.boot.SpringApplication
/**
     * 运行spring程序,创建并且刷新一个新的ApplicationContext.
     * @param 应用参数(通常来自于java的main函数
     * @return 一个运行的ApplicationContext
     */
    public ConfigurableApplicationContext run(String... args) {
        // 步骤1:开始计时
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        //步骤2:配置Headless
        configureHeadlessProperty();
        //步骤3:获取活动的监听器
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //步骤4:启动监听器
        listeners.started();
        try {
            //步骤5:初始化应用参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            //步骤6:准备运行环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            //步骤7:打印启动头
            Banner printedBanner = printBanner(environment);
            //步骤8:创建应用上下文ApplicationContext
            context = createApplicationContext();
            //步骤9:注册异常分析器
            analyzers = new FailureAnalyzers(context);
            //步骤10:初始化ApplicationContext
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            //步骤11:刷新ApplicationContext
            refreshContext(context);
            //步骤12:后续ApplicationContext操作
            afterRefresh(context, applicationArguments);
            //步骤13:监听器处理
            listeners.finished(context, null);
            //步骤14:结束计时并打印信息
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }

这里涉及到一个重要的类,就是ApplicationContext,按照官方的解释这个是提供应用配置信息的核心接口,在程序运行期间它是只读的,但是如果实现支持的话可以被重新加载。这个类提供的功能包括:     1.访问应用组建的bean工程方法,继承自
org.springframework.beans.factory.ListableBeanFactory;
    2.用通用的方式加载文件资源,继承自
org.springframework.core.io.ResourceLoader接口;
    3.向注册的监听器发布事件,继承自
ApplicationEventPublisher接口;
    4.解析消息,支持国际化,继承自
MessageSource接口;
    5.context具备多级继承关系,意味这每个servlet都可以优先使用自己的派生context的功能,然后才是全局的公共的context。


下面就run方法中的每一步进行详细解析:


a. 步骤1:开始计时 这里使用到了计时工具类
org.springframework.util.StopWatch。相比直接使用
System.currentTimeMillis()获取时间戳,使用工具类的方式显得更加优雅,并且也为多次计时和多纬度计时提供了可能。在自己的代码里,也可以尝试使用这个工具类

* from org.springframework.util.StopWatch
   /**
     * 开始一项未命名的任务。需要先调用start方法才能调用stop结束方法。
     */
    public void start() throws IllegalStateException {
        start("");
    }

    /**
     * 开始一项命名过的任务。需要先调用start方法才能调用stop结束方法。
     */
    public void start(String taskName) throws IllegalStateException {
        //已经开始了任务,不需要再次调用该方法
        if (this.running) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        }
        this.running = true;
        this.currentTaskName = taskName;
        //记录当前时间戳
        this.startTimeMillis = System.currentTimeMillis();
    }

b.步骤2:配置Headless
配置系统变量
java.awt.hea
dless,
在该模式下,系统缺少显示设备、键盘或鼠标,依靠系统的计算能力模拟这些特性。


c.步骤3:获取活动的监听器
和初始化时获取监听器一样,这里使用getSpringFactoriesInstances方法获取SpringApplicationRunListener子类的实例,即活动监听器的实例。

* from org.springframework.boot.SpringApplication
private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }

同样,需要加载的活动监听器的类名在spring.factories中配置,key使用父类的声明,即
org.springframework.boot.SpringApplicationRunListener。

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

在获取EventPublishingRunListener实例后,再通过SpringApplicationRunListeners构造函数,将logger和实例填充到SpringApplicationRunListeners对象中。

d.步骤4:启动监听器 SpringApplicationRunListeners可以看作SpringApplicationRunListener子类实例的集合,统一对实例进行操作,比如start启动时。

* from org.springframework.boot.SpringApplicationRunListeners
    public void started() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.started();
        }
    }

在配置中仅包含一项活动监听器,即
EventPublishingRunListener,因此只涉及到一次调用。

* from org.springframework.boot.context.event.EventPublishingRunListener

    //构造函数,在这里将SpringApplication中初始化过的多个ApplicationListener进行注册
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

   //广播事件
    public void started() {
        this.initialMulticaster
                .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
    }


* from org.springframework.context.event.SimpleApplicationEventMulticaster

//广播事件的实现,向所有注册监听器广播事件,而这个时间就是传入的ApplicationStartedEvent。如果监听器未监听这个事件,那可以直接忽略。
@Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            //如果指定executor,可以使用单独线程来触发时间,通知监听器
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

这是很典型的java
监听器模式,也是观察者模式的另一种形式。每一项监听器处理的内容将在后续文章中进一步展开。到此,初始化过程中加载的监听器也派上用场了。并不是所有监听器都会处理启动事件,在各自的事件处理方法中都各有选择。


e.步骤5:初始化应用参数
这里就是将main函数带入的参数填充到
org.springframework.boot.
DefaultApplicationArguments中。

* from org.springframework.boot.DefaultApplicationArguments
    public DefaultApplicationArguments(String[] args) {
        Assert.notNull(args, "Args must not be null");
        this.source = new Source(args);
        this.args = args;
    }

f.步骤6:准备运行环境

* from org.springframework.boot.SpringApplication
    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // 创建运行环境,因初始化过程中确认了是web工程,即webEnvironment为true,因此此处创建的是StandardServletEnvironment实例。
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // 配置运行环境,包括main函数带入的配置项和项目配置文件带入的配置项
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        // 广播ApplicationEnvironmentPreparedEvent事件,通知注册的监听器做出相应处理
        listeners.environmentPrepared(environment);
        //再次确认满足web环境的要求,lib中包含了org.springframework.web.context.ConfigurableWebEnvironment。
        if (isWebEnvironment(environment) && !this.webEnvironment) {
            environment = convertToStandardEnvironment(environment);
        }
        // 环境准备结束
        return environment;
    }

g.步骤7:打印启动头


默认打印标识性头图等信息,当然如果你想个性化,也可以做到,可以自定义image头,也可以定义text头。

* from org.springframework.boot.SpringBootBanner

    private static final String[] BANNER = { "",
            "  .   ____          _            __ _ _",
            " /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\",
            "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
            " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )",
            "  '  |____| .__|_| |_|_| |_\\__, | / / / /",
            " =========|_|==============|___/=/_/_/_/" };

h.步骤8:创建应用上下文ApplicationContext


web应用和非web应用分别有默认的实现类,web对应
org.springframework.
boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext,非web对应
javax.servlet.Servlet
.springframework.web.context.ConfigurableWebApplicationContext.

* from org.springframework.boot.SpringApplication
    /**
     * 用于创建ApplicationContext的策略方法。优先考虑显示指定的上下文类,如果没有指定,则使用默认的。
     * @return 应用上下文 (还没有刷新)
     */
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                contextClass = Class.forName(this.webEnvironment
                        ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, "
                                + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        //实例化并返回
        return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
    }

i.步骤9:注册异常分析器
异常分析器的加载和初始化器、注册监听器相同,都是在spring.factories文件中配置,通过反射机制实例化并加载进来。

FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
        Assert.notNull(context, "Context must not be null");
        this.classLoader = (classLoader == null ? context.getClassLoader() : classLoader);
        //加载分析器
        this.analyzers = loadFailureAnalyzers(this.classLoader);
        //将context中的属性注入到分析器中
        prepareFailureAnalyzers(this.analyzers, context);
    }

    private List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
        // 获取配置文件中的配置项,key是org.springframework.boot.diagnostics.FailureAnalyzer
        List<String> analyzerNames = SpringFactoriesLoader
                .loadFactoryNames(FailureAnalyzer.class, classLoader);
        List<FailureAnalyzer> analyzers = new ArrayList<FailureAnalyzer>();
        for (String analyzerName : analyzerNames) {
            try {
                // 实例化
                Constructor<?> constructor = ClassUtils.forName(analyzerName, classLoader)
                        .getDeclaredConstructor();
                ReflectionUtils.makeAccessible(constructor);
                analyzers.add((FailureAnalyzer) constructor.newInstance());
            }
            catch (Throwable ex) {
                log.trace("Failed to load " + analyzerName, ex);
            }
        }
        // 排序
        AnnotationAwareOrderComparator.sort(analyzers);
        return analyzers;
    }

 j.步骤10:初始化ApplicationContext
    后续步骤10-步骤12都是对应用上下文进行操作,从准备,刷新到后续处理,过程很长,需要详细描述。


 k.步骤13:监听器处理
    结束监听器监听


 l.步骤14:结束计时并打印信息
    计时结束并打印时间信息。

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/xac07/article/details/79498169
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞