Spring Boot启动流程

2019-04-09  本文已影响0人  hTangle

Spring Boot的启动函数如下所示

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

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

以上代码很容易看出哪些是关键,当然是@SpringBootApplication和application.run()分别是springboot加载配置和启动,下面详细说明这两块。
首先是SpringBootApplication.class

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}

其中@Configuration(@SpringBootConfiguration中其实用的也是@Configuration);@EnableAutoConfiguration;@ComponentScan三个是最重要的注解,@SpringBootApplication整合了三个注解使用者写起来看起来都比较简洁

@Configuration

它就是JavaConfig形式的Spring Ioc容器的配置类使用的那个@Configuration,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。

@EnableAutoConfiguration

EnableAutoConfiguration.class

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

@EnableAutoConfiguration简单的说它的作用就是借助@Import的支持,收集和注册特定场景相关的bean定义。其中,最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持很智能的自动配置:


image.png

SpringFactoriesLoader其主要功能就是从指定的配置文件META-INF/spring.factories加载配置。将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

springboot启动简单流程

  1. 启动类里面调用SpringApplication.run(xxx.class,args)方法
  2. 在SpringApplicaiton的run方法中有两个步骤,首先创建SpringApplicaiton对象,然后再调用run方法。
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }
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();
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
  1. 在SpringApplicaiton构造器中调用initialize(sources)方法。
  2. initialize方法中,
    a. 将sources转换成list加到this.sources属性中
    b. 判断是否为web环境(在类路径下是否可以加载到Servlet和ConfigurableWebApplicationContext)
    c. 加载Initializers(通过META-INF/spring.factories中键为ApplicationContextInitializer的配置进行加载),dubug发现一共
    加载了6个initializer(spring-boot-1.5.10.RELEASE.jar中4个,spring-boot-autoconfigure-1.5.10.RELEASE.jar中2个)
    d. 加载ApplicationListener(也是通过META-INF/spring.factories),debug发现共加载了10个
    e. 通过寻找main方法找到启动主类。
  3. run方法中
    a. StopWatch主要是监控启动过程,统计启动时间,检测应用是否已经启动或者停止。
    b. 加载SpringApplicationRunListener(也是通过META-INF/spring.factories),默认加载的是EventPublishingRunListener
    c. 调用RunListener.starting()方法。
    d. 根据args创建应用参数解析器ApplicationArguments;
    e. 准备环境变量:获取环境变量environment,将应用参数放入到环境变量持有对象中,监听器监听环境变量对象的变化(listener.environmentPrepared)
    f. 打印Banner信息(SpringBootBanner)
    g. 创建SpringBoot的应用上下文(AnnotationConfigEmbeddedWebApplicationContext)
    h.prepareContext上下文之前的准备
    i. refreshContext刷新上下文
    j. afterRefresh(ApplicationRunner,CommandLineRunner接口实现类的启动)
    k. 返回上下文对象
上一篇下一篇

猜你喜欢

热点阅读