SpringApplication 的运行过程分析: run()

来源:互联网 发布:什么手机支持双频网络 编辑:程序博客网 时间:2024/06/05 12:02

1.获取 SpringApplicationRunListener 实例

比如 EventPublishingRunListener
// 内部使用SpringFactoriesLoader 加载所有定义的 SpringApplicationRunListener并构造实例// 可以将 SpringApplicationRunListeners 理解为一组这样的实例的集合SpringApplicationRunListeners listeners = getRunListeners(args);

2.向所有 SpringApplicationRunListener 实例通知事件 ApplicationStartedEvent

listeners.starting();

3. 准备环境 Environment

    // 准备 Environment : 创建并配置 Enviroment    private ConfigurableEnvironment prepareEnvironment(            SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments) {        // Create and configure the environment        ConfigurableEnvironment environment = getOrCreateEnvironment();        configureEnvironment(environment, applicationArguments.getSourceArgs());        // 向所有 SpringApplicationRunListener 实例通知事件 ApplicationEnvironmentPreparedEvent        listeners.environmentPrepared(environment);        if (!this.webEnvironment) {            environment = new EnvironmentConverter(getClassLoader())                    .convertToStandardEnvironmentIfNecessary(environment);        }        return environment;    }    private ConfigurableEnvironment getOrCreateEnvironment() {        if (this.environment != null) {            return this.environment;        }        if (this.webEnvironment) {            // 如果是 Web 环境,创建 StandardServletEnvironment 对象            return new StandardServletEnvironment();        }        // 如果是非 Web 环境,创建 StandardEnvironment 对象        return new StandardEnvironment();    }       protected void configureEnvironment(ConfigurableEnvironment environment,            String[] args) {        configurePropertySources(environment, args);        configureProfiles(environment, args);    }   

4. 向所有 SpringApplicationRunListener 实例通知事件 ApplicationEnvironmentPreparedEvent

5. 创建 ApplicationContext

    /**     * 非web环境应用上下文的实现类     * The class name of application context that will be used by default for non-web     * environments.     */    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."            + "annotation.AnnotationConfigApplicationContext";    /**     * web环境应用上下文的实现类     * The class name of application context that will be used by default for web     * environments.     */    public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."            + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";    // 初始化过程中已经推断过当前应用是否Web应用环境,    //下面根据当前应用是否Web应用环境找到相应的ApplicationContext实现类,    //AnnotationConfigEmbeddedWebApplicationContext对应非Web环境     //或者 ConfigurableWebApplicationContext对应Web环境    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);            }        }        // 创建 ApplicationContext 实例        return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);    }

ApplicationContext对象实例化的过程只是做了一个Java对象创建的动作吗 ? 并不是那么简单,以缺省 Web应用的情况来看 :

    public AnnotationConfigEmbeddedWebApplicationContext() {        //创建一个AnnotatedBeanDefinitionReader,注解Bean类程序方式注册的便捷工具,和        //classpath Bean定义扫描器ClassPathBeanDefinitionScanner互为补充,采用同样的        //注解解决机制,但是只针对显式注册的类        //AnnotatedBeanDefinitionReader()构造方法内部会进一步调用工具类        //AnnotationConfigUtils. registerAnnotationConfigProcessors(registry)         //注册 6个BeanPostProcessor Bean定义,这也是容器中最早出现的一组Bean定义:         //1. annotation.internalConfigurationAnnotationProcessor        //2. annotation.internalAutowiredAnnotationProcessor        //3. annotation.internalRequiredAnnotationProcessor        //4. annotation.internalCommonAnnotationProcessor        //5. event.internalEventListenerProcessor        //6. event.internalEventListenerFactory        this.reader = new AnnotatedBeanDefinitionReader(this);        // Bean definition 扫描器 :         // 扫描classpath上的Bean定义并注册到 ApplicationContext 或者 BeanFactory        // Q : 什么样的会被认为是候选Bean定义 ?        // A : @Component, @Repository,@Service,@Controller等Spring注解定义的类,或者         //     Java EE 6's javax.annotation.ManagedBean,JSR-330 javax.inject.Named         //     注解定义的类        this.scanner = new ClassPathBeanDefinitionScanner(this);    }

6. 准备 ApplicationContext

    private void prepareContext(ConfigurableApplicationContext context,            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments, Banner printedBanner) {        // 关联 ApplicationContext 和 Environment                  context.setEnvironment(environment);        // 1.如果外部指定了 Bean 名称生成器,将其作为单例Bean注册到容器,        // 2.如果外部指定了资源加载器,设置 ApplicationContext 的资源加载器和相应的类加载器        postProcessApplicationContext(context);        // 执行每个 ApplicationContextInitializer 实例的初始化 initialize(context)        applyInitializers(context);        // 向所有 SpringApplicationRunListener 实例通知事件 ApplicationEnvironmentPreparedEvent        listeners.contextPrepared(context);        if (this.logStartupInfo) {            logStartupInfo(context.getParent() == null);            logStartupProfileInfo(context);        }        // Add boot specific singleton beans        context.getBeanFactory().registerSingleton("springApplicationArguments",                applicationArguments);        if (printedBanner != null) {            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);        }        // Load the sources        Set<Object> sources = getSources();        Assert.notEmpty(sources, "Sources must not be empty");        // 加载 Bean 定义, 只根据源类型将源设置到具体的 Bean定义加载器,并没有全面执行Bean定义加载.        // 这里 sources 指定的类,如果有注解@Component,则会被作为Bean定义添加到容器中,比如当前        // SpringApplication的入口类,因为有注解@SpringBootConfiguration,内含了注解@Component,        // 所以它会作为作为一个Bean被注册进容器;        load(context, sources.toArray(new Object[sources.size()]));        // 1.向所有 SpringApplicationRunListener 实例通知事件 ApplicationPreparedEvent        // 2.关联 ApplicationContext 和所有 ApplicationContextAware 的 ApplicationListener        listeners.contextLoaded(context);    }

7.刷新 ApplicationContext

((AbstractApplicationContext) applicationContext).refresh();

8.执行 ApplicationContext 刷新后任务 : 执行 Runners

....# SpringApplication.run()中的代码片段afterRefresh(context, applicationArguments);..../**     * Called after the context has been refreshed.     * @param context the application context     * @param args the application arguments     */    protected void afterRefresh(ConfigurableApplicationContext context,            ApplicationArguments args) {        callRunners(context, args);    }    private void callRunners(ApplicationContext context, ApplicationArguments args) {        List<Object> runners = new ArrayList<Object>();        // 找出所有的 ApplicationRunner Bean        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());        // 找出所有的 CommandLineRunner Bean        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());        // 排序        AnnotationAwareOrderComparator.sort(runners);        // 调用所有的 Runner        for (Object runner : new LinkedHashSet<Object>(runners)) {            if (runner instanceof ApplicationRunner) {                callRunner((ApplicationRunner) runner, args);            }            if (runner instanceof CommandLineRunner) {                callRunner((CommandLineRunner) runner, args);            }        }    }

9.向所有 SpringApplicationRunListener 实例通知事件 ApplicationReadyEvent

    // SpringApplicationRunListener 会进一步将此事件通知到 ApplicationContext 中去    // Listeners have been registered to the application context so we should    // use it at this point if we can    context.publishEvent(event);