SpringBoot-01丨Spring Boot 启动原理

Posted by jiefang on December 30, 2019

Spring Boot 启动原理

Springboot项目启动类:

1
2
3
4
5
6
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

SpringBootApplication注解

@SpringBootApplication注解是SpringBoot的核心注解,它其实是一个组合注解:

1
2
3
4
5
6
7
8
9
10
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
    Class<?>[] exclude() default {};
}

最重要的是:

  • @ComponentScan
  • @EnableAutoConfiguration
  • @Configuration

@Configuration

表达形式

任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类。

基于XML配置
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
       default-lazy-init="true">
    <!--bean定义-->
</beans>
基于注解
1
2
3
4
@Configuration
public class DatasourceConfiguration{
    //bean定义
}

注册bean定义

基于XML配置
1
2
3
<bean id="UserService" class="..UserServiceImpl">
     ...
</bean>
基于注解

任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。

1
2
3
4
5
6
7
@Configuration
public class MockConfiguration{
    @Bean
    public UserService userService(){
        return new UserServiceImpl();
    }
}

表达依赖注入关系

基于XML配置
1
2
3
4
5
<bean id="userService" class="..UserServiceImpl">
    <propery name ="dependencyService" ref="dependencyService" />
</bean>

<bean id="dependencyService" class="DependencyServiceImpl"></bean>
基于注解
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class MockConfiguration{
    @Bean
    public UserService userService(){
        return new UserServiceImpl();
    }
    
    @Bean
    public DependencyService dependencyService(){
        return new DependencyServiceImpl();
    }
}

@Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。

@Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean。

@ComponentScan

@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。

通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

@EnableAutoConfiguration

@EnableAutoConfiguration@EnableScheduling@EnableCaching@EnableMBeanExport等,@EnableAutoConfiguration类似,借助@Import的支持,收集和注册特定场景相关的bean定义。

  • @EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。
  • @EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器。
  • @EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。

@EnableAutoConfiguration会根据类路径中的jar依赖为项目进行自动配置,如:添加了spring-boot-starter-web依赖,会自动添加Tomcat和Spring MVC的依赖,Spring Boot会对Tomcat和Spring MVC进行自动配置。

1
2
3
4
5
6
7
8
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableAutoConfigurationImportSelector.class, Registrar.class})
public @interface EnableAutoConfiguration {
    Class<?>[] exclude() default {};
}

@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置。

image

SpringFactoriesLoader

SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public abstract class SpringFactoriesLoader {
    private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
    //配置文件
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

    public SpringFactoriesLoader() {
    }
    //加载spring.factories,实例化对象,放入List返回
    public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
        Assert.notNull(factoryClass, "'factoryClass' must not be null");
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
        if (logger.isTraceEnabled()) {
            logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
        }

        List<T> result = new ArrayList(factoryNames.size());
        Iterator var5 = factoryNames.iterator();

        while(var5.hasNext()) {
            String factoryName = (String)var5.next();
            result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
        }

        AnnotationAwareOrderComparator.sort(result);
        return result;
    }
    //加载spring.factories里的类名,放到List里返回
    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();

            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }

            return result;
        } catch (IOException var8) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
        }
    }
    //加载spring.factories的类生成Class实例,返回实例对象
    private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader) {
        try {
            Class<?> instanceClass = ClassUtils.forName(instanceClassName, classLoader);
            if (!factoryClass.isAssignableFrom(instanceClass)) {
                throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]");
            } else {
                return instanceClass.newInstance();
            }
        } catch (Throwable var4) {
            throw new IllegalArgumentException("Cannot instantiate factory class: " + factoryClass.getName(), var4);
        }
    }
}

META-INF/spring.factories

@EnableAutoConfiguration自动配置:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

SpringApplication执行流程

SpringBoot的启动逻辑在SpringApplication这个类中,通过构造一个SpringApplication并调用run方法启动SpringBoot应用程序。SpringBoot启动后的主要流程:

  1. 设置webApplicationType(web应用类型);

    webApplicationType是启动流程中一个比较重要的属性,SpringBoot根据它的类型来创建Environment对象和应用上下文对象(ApplicationContext)

  2. 准备应用上下文环境(Environment);

    根据上一步推断的webApplicationType创建不同类型的Environment,并且将用户的profile文件读取到Environment中

  3. 读取profile;
  4. 创建并配置应用上下文对象(ApplicationContext)

    根据webApplicationType创建不同实现的ApplicationContext

  5. 刷新应用上下文对象(refresh)

    AbstractApplicationContext抽象类定义了上下文对象初始化核心流程,SpringBoot以BeanFactoryPostProcessor的方式实现包扫描、自动配置,将Bean预先加载成BeanDefinition后并实例化

  6. 后续处理

    发布应用已启动事件并且调用容器中的Runner

源码

SpringApplication构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    //启动
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    //静态方法
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }
    //实例方法
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }
    //SpringApplication构造方法
    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.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        //设置应用类型
        this.webApplicationType =
        WebApplicationType.deduceFromClasspath();
        //查找并加载所有可用的ApplicationContextInitializer
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //查找并加载所有可用的ApplicationListener
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        //推断并设置main方法的定义类
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

SpringApplication.run(String… args)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        //查找并加载SpringApplicationRunListener调用starting()方法
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //根据webApplicationType创建不同类型的Environment,并且将用户的profile文件读取到Environment中
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            //判断是否打印banner
            Banner printedBanner = this.printBanner(environment);
            //根据webApplicationType创建不同实现的ApplicationContext
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            //遍历SpringApplicationRunListener,调用contextPrepared()的方法
            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);
            }
            //遍历执行SpringApplicationRunListener的started()方法
            listeners.started(context);
            //查找当前ApplicationContext中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);
        }
    }

一、设置应用类型

WebApplicationType.deduceFromClasspath()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
            return REACTIVE;
        } else {
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;
            for(int var2 = 0; var2 < var1; ++var2) {
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                    return NONE;
                }
            }
            return SERVLET;
        }
    }

SpringBoot将应用程序分为三种类型:

  • Reactive:Spring团队推出的Reactor编程模型的非阻塞异步Web编程框架WebFlux
  • Servlet:基于J2EE Servlet API的编程模型,运行在Servlet容器上
  • None:非Web应用程序 通过类路径中是否存在WebFlux中的Dispatcherhandler,SpringMVC中的DispatcherServlet、Servlet、ConfigurableWebApplicationContext来推断Web应用程序类型

二、准备应用上下文环境

SpringApplication.prepareEnvironment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        //创建环境对象
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        //配置环境对象;主要是根据命令行参数配置profile
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        //发布应用环境已准备事件
        listeners.environmentPrepared((ConfigurableEnvironment)environment);
        //绑定spring.main属性到SpringApplication对象中
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            //如果用户设置的spring.main.web-application-type和spring推断的类型不一致,则使用用户设置的类型,创建对应的环境对象
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }
        //添加一个名为configurationProperties的PropertySource
        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }
  1. 创建Environment对象

    在getOrCreateEnvironment方法中,会根据之前推断的webApplicationType(web程序类型)创建不同了实现的Environment对象

  2. 配置Environment对象
    • 应用程序如果有命令行参数,则在Environment中添加一个与这个命令行参数相关的PropertySource
    • 根据命令行参数中spring.profiles.active属性配置Environment对象中的activeProfile
  3. 发布ApplicationEnvironmentPreparedEvent(应用环境已准备)事件

    SpringApplication发布完这个事件后,一个类型为ConfigFileApplicationListener的监听器会监听这个事件,它会去读取用户设置的profile文件(读取profile的详细流程在下一步中)

  4. 将Environment中的spring.main属性绑定到SpringAppilcation对象中

    在执行到这一步时,Environment中已经包含了用户设置的profile文件属性

  5. 转换Environment对象的类型

    在上一步中,如果用户使用spring.main.web-application-type属性手动设置了应用程序的webApplicationType并且用户设置的类型与SpringApplication推断出来的不一致,则SpringApplication会将环境对象转换成用户设置的webApplicationType相关的类型。

三、读取profile

在创建Environment对象前,SpringAppilcation已经将当前类路径jar包下所有spring.factories文件中的ApplicationListener加载并实例化完毕。
ApplicationListener:Spring Framework中的监听器接口,用来监听应用程序发布的事件

监听器列表中有一个类型为ConfigFileApplicationListener的监听器,当监听到ApplicationEnvironmentPreparedEvent事件时,它会从所有spring.factories中加载EnvironmentPostProcessor(环境后处理器)并执行他们的postProcessEnvironment方法(这个监听器本身也是一个环境后处理器,所以它也会执行自身的postProcessEnvironment方法,在这个方法中加载了用户设置的profile并以PropertySource的形式添加到Environment中)。

ConfigFileApplicationListener最终会构造一个Loader的内部类并调用Loader.load()方法加载profile;在Loader的构造函数中,会去加载所有spring.factories中的PropertySourceLoader,SpringBoot提供了两个PropertySourceLoader:

  • PropertiesPropertySourceLoader(用来加载properties、xml文件)
  • YamlPropertySourceLoader(用来加载yml、yaml文件)

SpringAppilcation.load(ApplicationContext context, Object[] sources)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }

        BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.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();
    }
    public int load() {
        int count = 0;
        Object[] var2 = this.sources;
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Object source = var2[var4];
            count += this.load(source);
        }
        return count;
    }
    private int load(Object source) {
        Assert.notNull(source, "Source must not be null");
        if (source instanceof Class) {
            return this.load((Class)source);
        } else if (source instanceof Resource) {
            return this.load((Resource)source);
        } else if (source instanceof Package) {
            return this.load((Package)source);
        } else if (source instanceof CharSequence) {
            return this.load((CharSequence)source);
        } else {
            throw new IllegalArgumentException("Invalid source type " + source.getClass());
        }
    }    

Loader.load()加载profile的流程:

  • 配置文件目录
  • 配置文件名称
  • 文件扩展名

profile属性生效的规则:

  • 同名的profile:根据文件后缀优先级 properties > xml > yml > yaml;
  • 被引用的profile:例一个profile中同时有spring.profiles.active和spring.profiles.include属性,则active的优先级 > include的优先级;
  • 默认的profile优先级别最低;
  • 如果把默认的profile当做第一级profile,在第一级profile中引用的profile(使用spring.profiles.active或者spring.profiles.include引用)当做下一级的profile,则下一级的profile(可能多个)优先级高于前一级的profile(一个),多个profile整体的优先级为第一级的profile优先级;例:
    • application.yml内容:
    • spring.profiles.active=p1,p2
    • spring.profiles.include=p3,p4

    • application-p1.yml内容:
    • spring.profiles.include=p5

则p2 > p1 > p4 > p3 > default 其中p5 > p1,结果是p2 > p5 > p1 > p4 > p3 > default

四、创建并配置应用上下文对象

ApplicationContext是Spring Framework中最核心的接口,用来表示一个应用的上下文;功能包括事件发布、国际化等,同时它也是一个BeanFactory。

SpringApplication通过webApplicationType的类型来创建不同的ApplicationContext,以SERVLET类型的webApplicationType为例,SpringApplication会创建类型为AnnotationConfigServletWebServerApplicationContext的上下文对象;

SpringApplication在prepareContext方法中对上下文对象进行预配置,主要做了:

  • 执行所有ApplicationContextInitializer的initialize方法

    这些ApplicationContextInitializer是在SpringApplication中的构造函数中加载的(通过读取spring.factories加载)

  • 发布ApplicationContextInitializedEvent(上下文已初始化)事件
  • 发布ApplicationPreparedEvent(上下文已准备)事件

五、刷新应用上下文

这里是ApplicationContext真正开始初始化容器和创建bean的阶段,其中bean的整个生命周期可以从这一步骤看出来;Spring Framework中的所有ApplicationContext实现都直接或间接继承自AbstracttApplicationContext,它的refresh方法描述了整个上下文的初始化逻辑。

源码:

SpringAppilcation.refreshContext(ConfigurableApplicationContext context)

1
2
3
4
5
6
7
8
9
    private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }
    }

SpringAppilcation.refresh(ApplicationContext applicationContext)

1
2
3
4
    protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext)applicationContext).refresh();
    }

AbstractApplicationContext.refresh()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            //准备更新上下文时的预备工作
            this.prepareRefresh();
            //获取上下文的内部BeanFactory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //对BeanFactory做些预备工作
            this.prepareBeanFactory(beanFactory);

            try {
                //对BeanFactory进行预处理
                this.postProcessBeanFactory(beanFactory);
                //执行容器中的BeanFactoryPostProcessor
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册BeanPostProcessor
                this.registerBeanPostProcessors(beanFactory);
                //初始化MessageSource(国际化相关)
                this.initMessageSource();
                //初始化容器事件广播器(用来发布事件)
                this.initApplicationEventMulticaster();
                //初始化一些特殊的Bean
                this.onRefresh();
                //将所有监听器注册到前两步创建的事件广播器中
                this.registerListeners();
                //结束BeanFactory的初始化工作
                this.finishBeanFactoryInitialization(beanFactory);
                //上下文刷新完毕
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

流程:

  1. 准备更新上下文时的预备工作:
    • 初始化PropertySource
    • 验证Enrivonment中必要的属性
  2. 获取上下文的内部BeanFactory:内部BeanFactory的实现类是DefaultListableBeanFactory
  3. 对BeanFactory做些预备工作:
    • 设置BeanFactory的Bean类加载器、Bean表达式解析器、属性编辑器注册表
    • 添加类型为ApplicationContextAwareProcessor、ApplicationListenerDetector的BeanPostProcessor
    • 让BeanFactory在自动装配时忽略一些接口类型
    • 注册可解析的依赖(自动装配时碰到这些类型直接注入,包括BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext)
    • 在BeanFactory中注册一些单例对象,包括environment、systemProperties、systemEnvironment
  4. 对BeanFactory进行预处理:
    • 添加一个WebApplicationContextServletContextAwareProcessor的BeanPostProcessor
    • 使BeanFactory自动装配时忽略ServletContextAware接口
    • 在BeanFactory中注册request、session两种scope
    • 注册可解析的依赖(自动装配时碰到这些类型可以注解注入,包括ServletRequest、ServletResponse、HttpSession、WebRequest)
  5. 执行容器中的BeanFactoryPostProcessor执行到这时容器已经注册了三个BeanFactoryPostProcessor,分别为:
    • SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor:ApplicationContexttInitializer初始化时注册
    • ConfigurationWarningsApplicationContextInitializer#ConfigurationWarningsPostProcessor:ApplicationContexttInitializer初始化时注册
    • ConfigFileApplicationListener$PropertySourceOrderingPostProcessor

      ApplicationPreparedEvent事件发布时由ConfigFileApplicationListener注册 BeanDefinitionRegistryPostProcessor是一种特殊的BeanFactoryPostProcessor,可以对BeanDefinition的注册表进行预处理

      1. 在BeanFactory中找到已注册的BeanFactoryPostProcessor,执行其中类型为BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
      2. 循环从BeanFactory中获取BeanDefinitionRegistryPostProcessor,从BeanDefinition注册表中获取,和上一步的来源不一样;有一个ConfigurationClassPostProcessor,ApplicationContext的构造函数中注册的
        ConfigurationClassPostProcessor会执行SpringBoot的自动装配功能,将spring.factories中类型为EnableAutoConfiguration的类读取成BeanDefinition并过滤掉不满足条件的然后注册到BeanFactory中。
        这一步骤会不断从BeanFactory中获取没有执行的BeanDefinitionRegistryPostProcessor并执行(可能用户会里面注册同类型的处理器)直到没有找到新的BeanDefinitionRegistryPostProcessor 包扫描、自动装配的功能都在ConfigurationClassPostProcessor中完成,执行完这一步后,所有Bean都会加载成BeanDefinition放入容器中
      3. 执行他们的postProcessBeanFactory方法对BeanFactory进行后处理
  6. 注册BeanPostProcessor

    BeanPostProcessor:Bean生命周期的钩子,允许用户对实例化后的Bean进行操作

    • 从BeanFactory中获取所有BeanPostProcessor;
    • 在BeanFactory中注册一个类型为BeanPostProcessorChecker的BeanPostProcessor;
    • 将所有BeanPostProcessor按照实现了PriorityOrdered、Ordered、没有实现排序接口的顺序注册所有BeanPostProcessor到BeanFactory;
    • 在BeanFactory中注册一个类型为ApplicationListenerDetector的BeanPostProcessor;
  7. 初始化MessageSource(国际化相关)
  8. 初始化容器事件广播器(用来发布事件)
  9. 初始化一些特殊的Bean,主要做了:
    • 初始化ThemeSource(跟国际化相关的接口)
    • 创建WebServer
  10. 将所有监听器注册到前两步创建的事件广播器中
  11. 结束BeanFactory的初始化工作(这一步主要用来将所有的单例BeanDefinition实例化)
    • 从BeanFactory中获取所有的BeanDefinition的beanName并遍历;
    • 对Bean执行所有已注册的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法(如果这个方法返回了一个Bean,Spring不会对这个Bean的属性进行注入,并且这个Bean的生命周期也会缺少几个步骤) PS:只要其中有一个方法的返回值不为null,则会立即返回这个Bean,这个Bean的生命周期和正常的Bean不同(Spring对这个类型的BeanPostProcessor的注释是让它有机会能返回一个代理对象);
    • 实例化bean;
    • 对Bean执行所有MergedBeanDefinitionPostProcessor.prostProcessMergedBeanDefinition(用来修改BeanDefinition的信息);
    • 对Bean属性进行填充;
      • 获取BeanFactory中所有InstantiationAwareBeanPostProcessor,对Bean执行postProcessAfterInstantiation方法(通常,这个方法应该返回true,如果返回false,后续的postProcessAfterInstantiation方法就不会执行了);
      • 同上,获取所有InstantiationAwareBeanPostProcessor,对每一个InstantiationAwareBeanPostProcessor分两次调用;
        • postProcessProperties,如果返回null,则继续调用下一步
        • postProcessPropertyValues(返回的PropertyValues是最终使用的PropertyValues。如果这一步返回null,则不会执行后面的InstantiationAwareBeanPostProcessor)
        • 如果上一步返回的PropertyValues有属性,则将属性应用到bean上
    • 对实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware的接口进行接口调用;
    • 对Bean执行BeanPostProcessor.postProcessBeforeInitialization方法;
    • 对实现了InitializingBean的Bean调用接口方法,然后调用init-method(可以是@PostConstruct标注的方法);
    • 对Bean执行PostProcessor.postProcessAfterInitialization方法;
    • 如果Bean是一个SmartInitializingSingleton,则调用Bean的afterSingletonsInstantiated方法
  12. finishRefresh
    • 初始LifecycleProcessor(生命周期处理器),向BeanFactory注册一个DefaultLifecycleProcessor;
    • 调用LifecycleProcessor的onrefresh方法(找到所有已注册的SmartLifecycle,根据isRunning和isAutoStartup的条件判断,执行SmartLifecycle的start方法);
    • 在ServletWebServerApplicationContetxt中,启动了WebServer并发布了ServletWebServerInitializedEvent事件;

六、后续处理

  • 发布应用程序已启动(ApplicationStartedEvent)事件;
  • 在BeanFactory中获取所有ApplicationRunner和CommandLineRunner并调用他们的run方法;