深入解析Spring Boot启动流程源码

164 阅读14分钟

虽然本文档基于SpringBoot1.4.0.release版本,然后SpringBoot整体的启动流程基本一致。废话不多说,现在就开发接解析吧:

一、启动原理

SpringApplication.run(主程序类)

new SpringApplication(主程序类)

• 判断是否web应用

• 加载并保存所有ApplicationContextInitializer(META-INF/spring.factories)

• 加载并保存所有ApplicationListener

• 获取到主程序类

run()

• 回调所有的SpringApplicationRunListener(META-INF/spring.factories)的starting

• 获取ApplicationArguments

• 准备环境&回调所有监听器(SpringApplicationRunListener )的environmentPrepared

• 打印banner信息

• 创建IOC容器对象

AnnotationConfigEmbeddedWebApplicationContext(web环境容器)

AnnotationConfigApplicationContext(普通环境容器)

• 准备环境

– 执行**ApplicationContextInitializer**. initialize()

– 监听器**SpringApplicationRunListener**回调contextPrepared

– 加载主配置类定义信息

– 监听器**SpringApplicationRunListener**回调contextLoaded

• 刷新启动IOC容器;

– 扫描加载所有容器中的组件

– 包括从META-INF/spring.factories中获取的所有**EnableAutoConfiguration**组件

• 回调容器中所有的ApplicationRunnerCommandLineRunner的run方法

• 监听器SpringApplicationRunListener回调finished

二、自动配置

• Spring Boot启动扫描所有jar包的META-INF/spring.factories中配置的

EnableAutoConfiguration组件

spring-boot-autoconfigure.jar\META-INF\spring.factories有启动时需要加载的

EnableAutoConfiguration组件配置

• 配置文件中使用debug=true可以观看到当前启用的自动配置的信息

• 自动配置会为容器中添加大量组件

• Spring Boot在做任何功能都需要从容器中获取这个功能的组件

• Spring Boot 总是遵循一个标准;容器中有我们自己配置的组件就用我们配置的,没有就用自动配

置默认注册进来的组件;

@SpringBootApplication
public class DemoApplication {    
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);    
    }
}

一.SpringBoot启动原理

(1).初始化(创建SpringApplication对象)

1.保存主配置类

2.判断当前是否一个web应用的环境

3.从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来

4.从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener

5.从多个配置类中找到有main方法的主配置类

开始分析

1.保存主配置类

public SpringApplication(Object... sources) {
    initialize(sources);
}

@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
    //1.保存主配置类
    if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources));
    }
    //2.判断当前是否是一个web应用
    this.webEnvironment = deduceWebEnvironment();
    //3.从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;
    //然后保存起来
    setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
    //4.从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //5.从多个配置类中找到有main方法的主配置类
    this.mainApplicationClass = deduceMainApplicationClass();
}

2.判断当前是否是一个web应用

private boolean deduceWebEnvironment() {
    for (String className : WEB_ENVIRONMENT_CLASSES) {
        // 判断Servlet和ConfigurableWebApplicationContext 是否可以被类加载器加载到
        if (!ClassUtils.isPresent(className, null)) {
            return false;
        }
    }
    return true;
}
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",                   "org.springframework.web.context.ConfigurableWebApplicationContext" };

3.设置ApplicationContextInitializers

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
                                                                Class<?>[] parameterTypes, 
                                                                Object... args) {
    //1.获取当前线程的类加载器
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // Use names and ensure unique to protect against duplicates
    //2.通过class和类加载器获取META-INF/spring.factories配置的所有class的名字
    Set<String> names = new LinkedHashSet<String>(
        SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //3.实例化全部属于class的类
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                                                       classLoader, args, names);
    //4.排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        //1.获取类目录下所有META-INF/spring.factories的配置URL
        Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                                 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        List<String> result = new ArrayList<String>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            // 获取对应URL资源的配置文件
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            // 获取配置中的factoryClassName的类名
            String factoryClassNames = properties.getProperty(factoryClassName);
   		   result.addAll(Arrays.asList(
            StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        return result;
    } catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
       "] factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, 
                                                   ClassLoader classLoader, Object[] args,
                                                   Set<String> names) {
    List<T> instances = new ArrayList<T>(names.size());
    for (String name : names) {
        try {
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            Assert.isAssignable(type, instanceClass);
            // 注意此时调用的是无参
            Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
            T instance = (T) BeanUtils.instantiateClass(constructor, args);
            instances.add(instance);
        } catch (Throwable ex) {
            throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}
public void setInitializers(
    Collection<? extends ApplicationContextInitializer<?>> initializers) {
    this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
    this.initializers.addAll(initializers);
}

4.设置ApplicationListeners

ApplicationContextInitializer.png ApplicationListener.png

private Class<?> deduceMainApplicationClass() {
    try {
        //获取当前栈信息
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            //获取主类信息
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    } catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

(2).运行(运行run方法)

1.获取并启动监听器

2.构造容器环境

3.打印banner

4.创建容器

5.准备容器

6.刷新容器

7.刷新容器后的扩展接口

8.回调finished()方法

public ConfigurableApplicationContext run(String... args) {
    //时间监控
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    //第一步:获取并启动监听器
    //获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //回调所有的获取SpringApplicationRunListener.starting()方法
    listeners.started();
    try {
        //封装命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
        //第二步:构造容器环境
        //创建环境完成后回调SpringApplicationRunListener.environmentPrepared()表示环境准备完成
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                                                                 applicationArguments);
        //打印banner
        Banner printedBanner = printBanner(environment);
        //第三步:创建容器
        //创建ApplicationContext;决定创建web的ioc还是普通的ioc
        context = createApplicationContext();
        //第四步:准备容器
        prepareContext(context, environment, listeners, applicationArguments,printedBanner); 
        //第五步:刷新容器
       	//刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
       	//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
        refreshContext(context);
        //第六步:刷新容器后的扩展接口
        //从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, ex);
        throw new IllegalStateException(ex);
    }
}

1.获取并启动监听器

private SpringApplicationRunListeners getRunListeners(String[] args) {
    // 构造方法的入参
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    // 创建SpringApplicationRunListeners
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
        SpringApplicationRunListener.class, types, this, args));
}
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    ...
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        // 向initialMulticaster中添加下上文监听器
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }
    ...
}

EventPushlishingRunListener.png

public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType:resolveDefaultEventType(event));
    //获取属于启动事件的监听器且调用invokeListener()方法
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    invokeListener(listener, event);
                }
            });
        } else {
            invokeListener(listener, event);
        }
    }
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            // 会执行listener.onApplicationEvent()方法
            listener.onApplicationEvent(event);
        } catch (Throwable err) {
            errorHandler.handleError(err);
        }
    } else {
        try {
            listener.onApplicationEvent(event);
        } catch (ClassCastException ex) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            LogFactory.getLog(getClass()).debug("Non-matching event type for listener: " + listener, ex);
        }
    }
}

2.构造容器环境

private ConfigurableEnvironment prepareEnvironment(
    SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments) {
    // Create and configure the environment
    // 获取ConfigurableEnvironment(不存在则创建一个)
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    /** 
     * 配置环境propertySource和profiles
     * configurePropertySources(environment, args);
	 * configureProfiles(environment, args);
	 */
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    //回调环境准备完毕时间(第二次回调listener的方法)
    listeners.environmentPrepared(environment);
    
    //判断是不是web环境实是则重新构造一个web环境
    if (isWebEnvironment(environment) && !this.webEnvironment) {
        environment = convertToStandardEnvironment(environment);
    }
    return environment;
}

3.打印banner

private Banner printBanner(ConfigurableEnvironment environment) {
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    }
    if (printBannerViaDeprecatedMethod(environment)) {
        return null;
    }
    ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
        : new DefaultResourceLoader(getClassLoader());
    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
        resourceLoader, this.banner);
    //bannerMode是Banner.Mode.CONSOLE;
    if (this.bannerMode == Mode.LOG) {
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }
    //进入打印方法
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
    //获取banner
    Banner banner = getBanner(environment, this.fallbackBanner);
    //打印
    banner.printBanner(environment, sourceClass, out);
    //返回
    return new PrintedBanner(banner, sourceClass);
}
private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private static final String[] BANNER = { "",
                                        "  .   ____          _            __ _ _",
                                        " /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\",
                                        "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
                                        " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )",
                                        "  '  |____| .__|_| |_|_| |_\\__, | / / / /",
                                        " =========|_|==============|___/=/_/_/_/" };

private static final String SPRING_BOOT = " :: Spring Boot :: ";
private Banner getBanner(Environment environment, Banner definedBanner) {
    Banners banners = new Banners();
    banners.addIfNotNull(getImageBanner(environment));
    banners.addIfNotNull(getTextBanner(environment));
    if (banners.hasAtLeastOneBanner()) {
        return banners;
    }
    if (this.fallbackBanner != null) {
        return this.fallbackBanner;
    }
    return DEFAULT_BANNER;
}

打印banner

public void printBanner(Environment environment, Class<?> sourceClass,
                        PrintStream printStream) {
    //打印banner图
    for (String line : BANNER) {
        printStream.println(line);
    }
    //获取SpringApplication对应坐在包的版本
    String version = SpringBootVersion.getVersion();
    //构造对应的版本号
    version = (version == null ? "" : " (v" + version + ")");
    String padding = "";
    while (padding.length() < STRAP_LINE_SIZE
           - (version.length() + SPRING_BOOT.length())) {
        padding += " ";
    }
	//打印版本
    printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
    					AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version));
    //打印空行
    printStream.println();
}

4.创建容器

// 默认的容器
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
    + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
// WEB容器
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            //判断创建WEB容器还是默认的容器
            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);
}

5.准备容器

private void prepareContext(ConfigurableApplicationContext context,
                            ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners,
                            ApplicationArguments applicationArguments, 
                            Banner printedBanner) {
    //1.准备上下文环境;将environment保存到ioc中
    context.setEnvironment(environment);
    //2.postProcessApplicationContext() 用来支持自定义扩展的(默认什么都不执行)
    postProcessApplicationContext(context);
    //3.applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法;
    applyInitializers(context);
    //4.回调所有的SpringApplicationRunListener的contextPrepared();
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);
    }
     //5.调用registerSingleton()方法注册命令参数和Banner
    context.getBeanFactory().registerSingleton("springApplicationArguments",applicationArguments);
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }
    Set<Object> sources = getSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    //6.load() 会将启动类加载spring容器beanDefinitionMap中(注意这边可以多个)
    load(context, sources.toArray(new Object[sources.size()]));
    //7.prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
    listeners.contextLoaded(context);
}

执行postProcessApplicationContext

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    // beanNameGenerator为空
    if (this.beanNameGenerator != null) {
        context.getBeanFactory().registerSingleton(
            AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
            this.beanNameGenerator);
    }
    // resourceLoader为空
    if (this.resourceLoader != null) {
        if (context instanceof GenericApplicationContext) {
            ((GenericApplicationContext) context)
            .setResourceLoader(this.resourceLoader);
        }
        if (context instanceof DefaultResourceLoader) {
            ((DefaultResourceLoader) context)
            .setClassLoader(this.resourceLoader.getClassLoader());
        }
    }
}

load()

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug(
            "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    //通过来源类+容器 初始化一个BeanDefinitionLoader
    BeanDefinitionLoader loader = createBeanDefinitionLoader(
        getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    //加载来源类
    loader.load();
}

加载来源类

private int load(Class<?> source) {
    //不进去
    if (isGroovyPresent()) {
        // Any GroovyLoaders added in beans{} DSL can contribute beans here
        if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            GroovyBeanDefinitionSource loader = 
                BeanUtils.instantiateClass(source,GroovyBeanDefinitionSource.class);
            load(loader);
        }
    }
    //是否有Component注解
    if (isComponent(source)) {
        this.annotatedReader.register(source);
        return 1;
    }
    return 0;
}

6.刷新容器

该步骤是和Spring启动流程有关清查Spring启动原理,这里不做过多解释

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        /**
		 * 刷新上下文环境
		 * 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验
		 * 如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,
		 * 重写initPropertySources方法就好了
		 */
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        /**
		* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
		* 设置SPEL表达式#{key}的解析器
		* 设置资源编辑注册器,如PerpertyEditorSupper的支持
		* 添加ApplicationContextAwareProcessor处理器
		* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
		* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory)
		* 则会将beanFactory的实例注入进去
		*/
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            /** 
             * 激活各种BeanFactory处理器包括:
             * 1.BeanDefinitionRegistryBeanFactoryPostProcessor
             * 2.普通的BeanFactoryPostProcessor执行对应的postProcessBeanDefinitionRegistry方法
             * 3.postProcessBeanFactory方法
             */
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            /**
             * 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor 不是BeanFactoryPostProcessor
             * 注意两者的区别 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
             */
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 初始化上下文中的资源文件,如国际化文件的处理等
            initMessageSource();

            // Initialize event multicaster for this context.
            // 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 给子类扩展初始化其他Bean
            onRefresh();

            // Check for listener beans and register them.
            // 在所有bean中查找listener bean,然后注册到广播器中
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            /**
						 * 设置转换器
					 	 * 注册一个默认的属性值解析器
						 * 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
             * 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
						 */
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            /**
            * 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor
            * 含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
            * spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行
            * 启动所有实现了Lifecycle接口的类
            * 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理
            * 即对那种在spring启动后需要处理的一些类,这些类实现了
            * ApplicationListener<ContextRefreshedEvent> ,
            * 这里就是要触发这些类的执行(执行onApplicationEvent方法)
            * spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、
            * ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
            * 完成初始化
            * 通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
            */
            finishRefresh();
        } catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
            }
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            // Reset 'active' flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        } finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

7.刷新容器后的扩展接口

protected void afterRefresh(ConfigurableApplicationContext context,
                            ApplicationArguments args) {
    callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<Object>();
    //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    //默认两个都没有
    for (Object runner : new LinkedHashSet<Object>(runners)) {
        //ApplicationRunner先回调,CommandLineRunner再回调
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

8.回调finished()方法

二.事件监听机制

SpringBoot事件监听分为两种运行时监听器,上下文监听器

SpringBoot整体框架就是通过该监听器org.springframework.boot.SpringApplicationRunListeners,来触发上下文监听器。通过上下文监听器来完成整体逻辑,比如加载配置文件,加载配置类,初始化日志环境等。

1) 运行时监听器

SpringApplicationRunListener

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

2) 上下文监听器

ApplicationListener

# spring-boot Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener

# spring-boot-autoconfigure Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

监听器图.png

DelegatingApplicationContextInitializer 啥也不做
ContextIdApplicationContextInitializer  设置容器的ID为"应用名字:profile.active"
ConfigurationWarningsApplicationContextInitializer
初始化器使用环境属性context.initializer.classes指定的初始化器(initializers)进行初始化工作,如果没有指定则什么都不做
DelegatingApplicationContextInitializer使用环境属性context.initializer.classes指定的初始化器(initializers)进行初始化工作,如果没有指定则什么都不做
ContextIdApplicationContextInitializer设置Spring应用上下文的ID,会参照环境属性:
spring.application.name
spring.application.index
spring.profiles.active
如果这些属性都没有,ID使用"application"。
ConfigurationWarningsApplicationContextInitializer对于一般配置错误在日志中作出警告
ServerPortInfoApplicationContextInitializer将内置servlet容器实际使用的监听端口写入到Environment环境属性中。这样属性"local.server.port"就可以直接通过@Value注入到测试中,或者通过环境属性Environment获取。
SharedMetadataReaderFactoryContextInitializer创建一个SpringBoot和ConfigurationClassPostProcessor共用的CachingMetadataReaderFactory对象,实现类使用ConcurrentReferenceCachingMetadataReaderFactory
AutoConfigurationReportLoggingInitializer写入日志。除非出现问题,否则会在级别记录报告,在这种情况下,它们是使用级别的。ConditionEvaluationReportDEBUGINFO此初始化程序不应在多个应用程序上下文实例之间共享。

三.自动装配

EnableAutoConfiguration

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
    Class<?>[] exclude() default {};

    /**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
    String[] excludeName() default {};
}

EnableAutoConfigurationImportSelector@EnableAutoConfiguration所@Import的DeferredImportSelector实现类,由于DeferredImportSelector作为ImportSelector的子接口,所以组件自动装配逻辑在selectImports(AnnotationMetadata)方法中实现:

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {}
	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}
@Override
public String[] selectImports(AnnotationMetadata metadata) {
    if (!isEnabled(metadata)) { return NO_IMPORTS; }
    try {
        // 1.获取主类的EnableAutoConfiguration的属性
        AnnotationAttributes attributes = getAttributes(metadata);
        // 2.获取META-INF/spring.factories中的EnableAutoConfiguration的类名
        List<String> configurations = getCandidateConfigurations(metadata,attributes);
        // 3.去重
        configurations = removeDuplicates(configurations);
        // 4.获取exculusion的EnableAutoConfiguration类
        Set<String> exclusions = getExclusions(metadata, attributes);
        // 5.排除exculusion的EnableAutoConfiguration类
        configurations.removeAll(exclusions);
        // 6.排序
        configurations = sort(configurations);
        // 7.记录日志
        recordWithConditionEvaluationReport(configurations, exclusions);
        return configurations.toArray(new String[configurations.size()]);
    } catch (IOException ex) {
        throw new IllegalStateException(ex);
    }
}

2.获取META-INF/spring.factories中的EnableAutoConfiguration的类名

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
                                                  AnnotationAttributes attributes) {
    // 获取META-INF/spring.factories目录下EnableAutoConfiguration的类
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    Assert.notEmpty(configurations,
                    "No auto configuration classes found in META-INF/spring.factories. If you "
                    + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

4.获取exculusion的EnableAutoConfiguration类

protected Set<String> getExclusions(AnnotationMetadata metadata,
                                    AnnotationAttributes attributes) {
    Set<String> excluded = new LinkedHashSet<String>();
    // 获取exclude属性下类的列表
    excluded.addAll(asList(attributes, "exclude"));
    // 获取excludeName属性下类的列表
    excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
    // 获取配置文件中的exclusions
    excluded.addAll(getExcludeAutoConfigurationsProperty());
    return excluded;
}
private List<String> getExcludeAutoConfigurationsProperty() {
    // 是否是配置化的环境
    if (getEnvironment() instanceof ConfigurableEnvironment) {
        Excludes excludes = new Excludes();
        // 以spring.autoconfigure.作为前缀初始化RelaxedDataBinder
        RelaxedDataBinder binder = new RelaxedDataBinder(excludes,"spring.autoconfigure.");
        // 绑定excludes的excludes属性
        binder.bind(new PropertySourcesPropertyValues(
            ((ConfigurableEnvironment) getEnvironment()).getPropertySources()));
        return excludes.getExclude();
    }
    RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(getEnvironment(),
                                                                   "spring.autoconfigure.");
    String[] exclude = resolver.getProperty("exclude", String[].class);
    return (Arrays.asList(exclude == null ? new String[0] : exclude));
}

7.记录confgurations和exclusions

private void recordWithConditionEvaluationReport(List<String> configurations,
                                                 Collection<String> exclusions) throws IOException {
    ConditionEvaluationReport report = ConditionEvaluationReport
        .get(getBeanFactory());
    // 记录confgurations
    report.recordEvaluationCandidates(configurations);
    // 记录exclusions
    report.recordExclusions(exclusions);
}

四:ConditionOnXXX源码解析

@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)该注解表示,如果存在它修饰的类的bean,则不需要再创建这个bean;可以给该注解传入参数例如@ConditionOnMissingBean(name = "example"),这个表示如果name为“example”的bean存在,这该注解修饰的代码块不执行。
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)
@ConditionalOnProperty(当有配置信息时生效)
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
                                        AnnotatedTypeMetadata metadata) {
    // 1.获取当前类中的ConditionalOnProperty的属性
    List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
        metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
    // 2.比对ConditionalOnProperty的属性和配置中的值
    List<ConditionOutcome> noMatchOutcomes = findNoMatchOutcomes(
        allAnnotationAttributes, context.getEnvironment());
    if (noMatchOutcomes.isEmpty()) {
        return ConditionOutcome.match();
    }
    return ConditionOutcome.noMatch(getCompositeMessage(noMatchOutcomes));
}