【SpringBoot源码分析】启动加载

SpringBoot源码分析(启动加载)

启动类中,会调用 SpringApplication 的静态run方法

@SpringBootApplication
public class BasicProjectApplication {
    public static void main(String[] args) {
        SpringApplication.run(BasicProjectApplication.class, args);
    }
}
// org.springframework.boot.SpringApplication

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    // 构建 SpringApplication实例 并执行run方法
    return (new SpringApplication(primarySources)).run(args);
}

可以看到,启动类中的 SpringApplication.run ,最终会先构建 SpringApplication实例,再执行实例的run方法。

一、SpringApplication 实例化

1、SpringApplication 构造方法

// org.springframework.boot.SpringApplication

// 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.lazyInitialization = false;

    // 资源加载器
    this.resourceLoader = resourceLoader;

    // primarySources 就是 启动类
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));

    // 判断Web程序的类型(无、基于Servlet的、基于响应式编程模型的)
    this.webApplicationType = WebApplicationType.deduceFromClasspath();

    // getSpringFactoriesInstances 就是获取 META-INF/spring.factories 中对应类的实例
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

    // 推断 Spring Boot 应用程序的主类
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

META-INF/spring.factories 中的 InitializersListeners

在这里插入图片描述

2、getSpringFactoriesInstances

// org.springframework.boot.SpringApplication

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return this.getSpringFactoriesInstances(type, new Class[0]);
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = this.getClassLoader();
    // 获取 META-INF/spring.factories 中对应类的实例
    Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 构建实例
    List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 排序返回
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

SpringFactoriesLoader.loadFactoryNamesSpringBoot源码(自动装配)讲过,这里就不再赘述了。

二、执行实例的run方法

构建完 SpringApplication 实例之后,就开始调用实例的run方法了

// org.springframework.boot.SpringApplication

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    // Spring容器
    ConfigurableApplicationContext context = null;
    // 异常报告器
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
    // 配置系统属性 java.awt.headless
    this.configureHeadlessProperty();

    // 从 META-INF/spring.factories 获取 SpringBootExceptionReporter 并实例化
    // 这里是 EventPublishingRunListener
    SpringApplicationRunListeners listeners = this.getRunListeners(args);

    listeners.starting();

    Collection exceptionReporters;
    try {
        // 封装请求参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 准备Environment
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        // 配置系统属性 spring.beaninfo.ignore
        this.configureIgnoreBeanInfo(environment);
        // 打印程序启动时的横幅标语
        Banner printedBanner = this.printBanner(environment);
        // 构建Spring容器
        context = this.createApplicationContext();
        // 从 META-INF/spring.factories 获取 SpringBootExceptionReporter 并实例化
        // 这里是 FailureAnalyzers
        exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
        // 准备IoC容器
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // IoC容器的初始化
        this.refreshContext(context);
        // IoC容器初始化之后的一些操作
        this.afterRefresh(context, applicationArguments);
        stopWatch.stop();
        // 创建一个 StartupInfoLogger 对象,记录应用程序的启动信息。
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        // 调用Runner的run方法
        this.callRunners(context, applicationArguments);
    } catch (Throwable var10) {
        // 异常处理
        this.handleRunFailure(context, var10, exceptionReporters, listeners);
        throw new IllegalStateException(var10);
    }

    try {
        listeners.running(context);
        return context;
    } catch (Throwable var9) {
        // 异常处理
        this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}

1、prepareEnvironment

// org.springframework.boot.SpringApplication

// Create and configure the environment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                   ApplicationArguments applicationArguments) {
    // 1. 创建环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 2. 配置环境
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 3. 连接 -- 没太看懂这个
    ConfigurationPropertySources.attach(environment);
    // 4. 执行监听器
    listeners.environmentPrepared(environment);
    // 5. 将spring.main开头的配置信息绑定到SpringApplication类属性中
    bindToSpringApplication(environment);
    // 6. 没有设置 isCustomEnvironment 属性的情况下
    if (!this.isCustomEnvironment) {
        // 环境转换器
        environment = new EnvironmentConverter(getClassLoader())
            .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    // 7. 再次连接并返回
    ConfigurationPropertySources.attach(environment);
    return environment;
}

1)ConfigurableEnvironment

ConfigurableEnvironment是 Spring 提供的接口,并继承了多个接口

  • PropertyResolver:属性解析器,用于针对任何底层源(比如文件)解析属性的接口,定义了一系列读取,解析,判断是否包含指定属性的方法,比如可以从YML、系统参数等加载属性。
  • ConfigurablePropertyResolver:可配置的属性解析器,定义用于访问和自定义将属性值从一种类型转换为另一种类型时功能,也就是比PropertyResolver多了一个类型转换。
  • Environment:表示当前应用程序运行环境的接口。对应用程序环境的两个关键方面进行建模:properties配置文件(应用程序配置文件)和profiles(激活环境命名空间)。
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
    // 设置当前激活的 profile
    void setActiveProfiles(String... profiles);
    // 添加 profile
    void addActiveProfile(String profile);
    // 设置默认的 profile
    void setDefaultProfiles(String... profiles);
    // 获取PropertySource键值组合的集合
    MutablePropertySources getPropertySources();
    // 获取系统属性
    Map<String, Object> getSystemProperties();
    // 获取系统环境变量
    Map<String, Object> getSystemEnvironment();
    // 合并其他 ConfigurableEnvironment 
    void merge(ConfigurableEnvironment parent);
}

2)getOrCreateEnvironment

// org.springframework.boot.SpringApplication

private ConfigurableEnvironment getOrCreateEnvironment() {
    // 1. 环境已初始化,直接返回
    if (this.environment != null) {
        return this.environment;
    }
    // 2. 判断环境的类型
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
    }
}

以 StandardServletEnvironment 为例,先调用父类 AbstractEnvironment 的无参构造函数

// org.springframework.core.env.AbstractEnvironment

public AbstractEnvironment() {
    this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
    this.customizePropertySources(this.propertySources);
}

protected void customizePropertySources(MutablePropertySources propertySources) {
}

调用 StandardServletEnvironment 重写的 customizePropertySources 方法

// org.springframework.web.context.support.StandardServletEnvironment

public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
    // Servlet 上下文初始化参数属性源名称
    propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
    // Servlet 配置初始化参数属性源名称
    propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
    // JNDI 属性源名称
    if (jndiPresent && JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
        propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
    }
    // 调用父类的
    super.customizePropertySources(propertySources);
}

紧接着调用父类 StandardEnvironment 的 customizePropertySources 方法

public class StandardEnvironment extends AbstractEnvironment {
    public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
    public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

    public StandardEnvironment() {
    }

    protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
    }
}

最终这一步创建的ConfigurableEnvironment对象中,一共有4个PropertySource,其中前两个是没有放任何东西的:

在这里插入图片描述

3)configureEnvironment

// org.springframework.boot.SpringApplication

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    // 添加默认的转换器服务
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    // 配置属性
    configurePropertySources(environment, args);
    // 配置 Profile
    configureProfiles(environment, args);
}

configurePropertySources方法主要是将启动命令中的参数和run 方法中的参数封装为PropertySource

// org.springframework.boot.SpringApplication

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
    // 获取所有的属性源
    MutablePropertySources sources = environment.getPropertySources();
    if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
        sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
    }
    // 是否添加启动命令参数,默认True
    if (this.addCommandLineProperties && args.length > 0) {
        String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
        if (sources.contains(name)) {
            PropertySource<?> source = sources.get(name);
            CompositePropertySource composite = new CompositePropertySource(name);
            composite.addPropertySource(
                new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
            composite.addPropertySource(source);
            sources.replace(name, composite);
        }
        else {
            sources.addFirst(new SimpleCommandLinePropertySource(args));
        }
    }
}

4)bindToSpringApplication

bindToSpringApplication的作用是将spring.main开头的配置绑定到SpringApplication类对应的属性中。

// org.springframework.boot.SpringApplication

protected void bindToSpringApplication(ConfigurableEnvironment environment) {
    try {
        Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
    }
    catch (Exception ex) {
        throw new IllegalStateException("Cannot bind to SpringApplication", ex);
    }
}

2、configureIgnoreBeanInfo

环境创建成功后,进入到configureIgnoreBeanInfo方法

// org.springframework.boot.SpringApplication

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
    if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
        // 配置了 spring.beaninfo.ignore 属性,默认为TRUE,忽略 BeanInfo
        Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
        System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
    }
}
  • 在 Java 中,每个类都有一个对应的 BeanInfo,它描述了该类的属性、方法等信息。
  • BeanInfoFactory 是 Spring 框架中的一个接口,用于注册 BeanInfo。

spring.beaninfo.ignore = true ,忽略通过 BeanInfoFactory 注册的所有 BeanInfo,解决某些类路径扫描导致的性能问题。

3、printBanner

环境准备完成后,开始打印Banner

// org.springframework.boot.SpringApplication

private Banner printBanner(ConfigurableEnvironment environment) {
    // 关闭的话就不打印了
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    }
    // 创建资源加载器
    ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
        : new DefaultResourceLoader(getClassLoader());
    // 创建打印对象
    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
    // 根据配置模式,选择打印到日志还是控制台
    if (this.bannerMode == Mode.LOG) {
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
// org.springframework.boot.SpringApplicationBannerPrinter

// 打印到日志
Banner print(Environment environment, Class<?> sourceClass, Log logger) {
    Banner banner = getBanner(environment);
    try {
        logger.info(createStringFromBanner(banner, environment, sourceClass));
    }
    catch (UnsupportedEncodingException ex) {
        logger.warn("Failed to create String for banner", ex);
    }
    return new PrintedBanner(banner, sourceClass);
}

// 打印到控制台
Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
    Banner banner = getBanner(environment);
    banner.printBanner(environment, sourceClass, out);
    return new PrintedBanner(banner, sourceClass);
}

// 从环境中获取 Banner 对象
private Banner getBanner(Environment environment) {
    Banners banners = new Banners();
    // 从 spring.banner.image.location 配置中,查询图片
    // 没有配置,则查询 banner.gif、banner.jpg、banner.png
    // 都没有返回NULL
    banners.addIfNotNull(getImageBanner(environment));
    // 获取 spring.banner.location 配置,默认是banner.txt
    banners.addIfNotNull(getTextBanner(environment));
    if (banners.hasAtLeastOneBanner()) {
        return banners;
    }
    if (this.fallbackBanner != null) {
        return this.fallbackBanner;
    }
    // DEFAULT_BANNER =  new SpringBootBanner()
    return DEFAULT_BANNER;
}

默认的 SpringBootBanner 如下图所示

在这里插入图片描述

4、createApplicationContext

// org.springframework.boot.SpringApplication

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:
                    // AnnotationConfigServletWebServerApplicationContext
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    // AnnotationConfigReactiveWebServerApplicationContext
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    // AnnotationConfigApplicationContext
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
        }
    }

    // 构建IoC容器
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

可以看到,三种 ApplicationContext 都是 GenericApplicationContext 的子类

在这里插入图片描述

在实例化ApplicationContext之前,会先进行父类 GenericApplicationContext 的初始化

// org.springframework.context.support.GenericApplicationContext

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

5、prepareContext

// org.springframework.boot.SpringApplication

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners, 
                            ApplicationArguments applicationArguments, Banner printedBanner) {
    // 将环境变量设置到上下文中
    context.setEnvironment(environment);
    // 注册BeanNameGenerator、设置ResourceLoader、ConversionService
    postProcessApplicationContext(context);
    // 执行初始化
    applyInitializers(context);
    // 执行监听器
    listeners.contextPrepared(context);
    // 打印启动日志
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // 获取BeanFactory(DefaultListableBeanFactory)
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    // 注册 springApplicationArguments Bean
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        // 注册 springBootBanner Bean
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof DefaultListableBeanFactory) {
        // 是否允许允许 Bean 定义覆盖,默认false
        ((DefaultListableBeanFactory) beanFactory)
        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.lazyInitialization) {
        // 添加 LazyInitializationBeanFactoryPostProcessor
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }
    // 这里只有一个source,就是启动类
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    // 加载启动类
    load(context, sources.toArray(new Object[0]));
    // 执行监听器
    listeners.contextLoaded(context);
}

1)setEnvironment

setEnvironment方法中会将环境对象设置给 上下文 及 读取器 和 扫描器:

// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

@Override
public void setEnvironment(ConfigurableEnvironment environment) {
    // 设置context的environment
    super.setEnvironment(environment);
    // 设置reader的environment
    this.reader.setEnvironment(environment);
    // 设置scanner的environment
    this.scanner.setEnvironment(environment);
}
// org.springframework.context.support.AbstractApplicationContext

/** Environment used by this context. */
@Nullable
private ConfigurableEnvironment environment;

@Override
public void setEnvironment(ConfigurableEnvironment environment) {
    this.environment = environment;
}

2)applyInitializers

// org.springframework.boot.SpringApplication

@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
    // 排序后遍历初始化器集合
    for (ApplicationContextInitializer initializer : getInitializers()) {
        // 检查是否可以被调用
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                ApplicationContextInitializer.class);
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        // 执行每个初始化器 可以对上下文进行操作
        initializer.initialize(context);
    }
}

我们回顾下初始化器:

在这里插入图片描述

public class ConfigurationWarningsApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        // 添加 ConfigurationWarningsPostProcessor 后置处理器
        context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
    }
}
public class ContextIdApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 创建一个ContextId对象,并将其注册到BeanFactory中
        ContextId contextId = getContextId(applicationContext);
        applicationContext.setId(contextId.getId());
        applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId);
    }
}
public class DelegatingApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        // 加载context.initializer.classes配置的初始化器
        ConfigurableEnvironment environment = context.getEnvironment();
        List<Class<?>> initializerClasses = getInitializerClasses(environment);
        // 应用初始化器
        if (!initializerClasses.isEmpty()) {
            applyInitializerClasses(context, initializerClasses);
        }
    }
}
public class ServerPortInfoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, ApplicationListener<WebServerInitializedEvent> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 自己本身是实现监听器接口的
        applicationContext.addApplicationListener(this);
    }

    // 本身也是一个监听器,监听的事件为WebServerInitializedEvent
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        String propertyName = "local." + getName(event.getApplicationContext()) + ".port";
        // 将端口设置到环境中,然后方便通过 @Value 或 Environment 获取本地端口号:
        setPortProperty(event.getApplicationContext(), propertyName, event.getWebServer().getPort());
    }
}
class SharedMetadataReaderFactoryContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 添加 CachingMetadataReaderFactoryPostProcessor
        applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
    }
}
public class ConditionEvaluationReportLoggingListener implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        // 添加监听器
        applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
        if (applicationContext instanceof GenericApplicationContext) {
            // 尽早获取report,以防上下文加载失败
            this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
        }
    }
}

3)load

这里sources只有一个,就是启动类

// org.springframework.boot.SpringApplication

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    // 构建 BeanDefinition 加载器(包含sources、reader、scanner)
    BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    // 设置 beanName生成器
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    // 设置 资源加载器
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    // 设置 environment
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    // 执行加载
    loader.load();
}
// org.springframework.boot.BeanDefinitionLoader

int load() {
    int count = 0;
    for (Object source : this.sources) {
        count += load(source);
    }
    return count;
}

private int load(Object source) {
    Assert.notNull(source, "Source must not be null");
    if (source instanceof Class<?>) {
        return load((Class<?>) source);
    }
    if (source instanceof Resource) {
        return load((Resource) source);
    }
    if (source instanceof Package) {
        return load((Package) source);
    }
    if (source instanceof CharSequence) {
        return load((CharSequence) source);
    }
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

private int load(Class<?> source) {
    // ...
    
    // 启动类本身是个@Component
    if (isEligible(source)) {
        // 调用AnnotatedBeanDefinitionReader 注册启动类去注册当前启动类
        this.annotatedReader.register(source);
        return 1;
    }
    return 0;
}

6、refreshContext

在执行 SpringApplication 实例的run方法时,通过refreshContext方法进行IoC容器的初始化

// org.springframework.boot.SpringApplication

private void refreshContext(ConfigurableApplicationContext context) {
    // refresh context
    refresh((ApplicationContext) context);
    // 注册关闭钩子
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        } catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}

@Deprecated
protected void refresh(ApplicationContext applicationContext) {
    Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
    refresh((ConfigurableApplicationContext) applicationContext);
}

protected void refresh(ConfigurableApplicationContext applicationContext) {
    // IoC容器的初始化
    applicationContext.refresh();
}

然后,就到我们熟悉的 refresh() 方法了,总共有12大步骤(这里就不展开了)

// org.springframework.context.support.AbstractApplicationContext

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        } 

        catch (BeansException ex) {
            // logger...

            // 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、内置Tomcat原理

我们看到 refresh() 方法12大步骤中的 onRefresh() 方法,默认是空实现

// org.springframework.context.support.AbstractApplicationContext

protected void onRefresh() throws BeansException {
    // For subclasses: do nothing by default.
}

ServletWebServerApplicationContext 重写了onRefresh方法

// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext

@Override
protected void onRefresh() {
    super.onRefresh();
    try {
        // tomcat容器就是在这里创建并启动的
        createWebServer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}

private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = getServletContext();
    if (webServer == null && servletContext == null) {
        // 工厂模式 默认获取的是 TomcatServletWebServerFactory
        ServletWebServerFactory factory = getWebServerFactory();
        // 获取 TomcatWebServer,创建 Tomcat 并启动
        this.webServer = factory.getWebServer(getSelfInitializer());
        getBeanFactory().registerSingleton("webServerGracefulShutdown",
                                           new WebServerGracefulShutdownLifecycle(this.webServer));
        getBeanFactory().registerSingleton("webServerStartStop",
                                           new WebServerStartStopLifecycle(this, this.webServer));
    }
    else if (servletContext != null) {
        try {
            getSelfInitializer().onStartup(servletContext);
        }
        catch (ServletException ex) {
            throw new ApplicationContextException("Cannot initialize servlet context", ex);
        }
    }
    // 加载 Servlet 属性源
    initPropertySources();
}
// org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
    if (this.disableMBeanRegistry) {
        Registry.disableRegistry();
    }
    // 创建Tomcat
    Tomcat tomcat = new Tomcat();
    File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    Connector connector = new Connector(this.protocol);
    connector.setThrowOnFailure(true);
    tomcat.getService().addConnector(connector);
    customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    configureEngine(tomcat.getEngine());
    for (Connector additionalConnector : this.additionalTomcatConnectors) {
        tomcat.getService().addConnector(additionalConnector);
    }
    prepareContext(tomcat.getHost(), initializers);
    // 启动Tomcat
    return getTomcatWebServer(tomcat);
}

protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
    return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}

public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    // 自启动
    this.autoStart = autoStart;
    this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
    // 初始化
    initialize();
}

private void initialize() throws WebServerException {
    logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
    synchronized (this.monitor) {
        try {
            // ...
            
            this.tomcat.start();	// 启动Tomcat
            
            // ...
        } 
        // ...
    }
}

8、callRunners

// org.springframework.boot.SpringApplication

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    // 添加 ApplicationRunner 和 CommandLineRunner 接口的实现类
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    // 排序
    AnnotationAwareOrderComparator.sort(runners);
    // 循环调用Runner重写的run方法
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}
@FunctionalInterface
public interface ApplicationRunner {
	void run(ApplicationArguments args) throws Exception;
}
@FunctionalInterface
public interface CommandLineRunner {
	void run(String... args) throws Exception;
}

三、SpringApplicationRunListener

在执行SpringApplication的run方法时,可以看到很多listeners的执行,执行时机与顺序如下图所示:

在这里插入图片描述

1、SpringApplicationRunListener

public interface SpringApplicationRunListener {

	/**
	 * 在run方法首次启动时立即调用。可以用于非常早期的初始化。
	 */
	default void starting() {}

	/**
	 * Environment 准备好之后、ApplicationContext 创建之前 调用
	 */
	default void environmentPrepared(ConfigurableEnvironment environment) {}

	/**
	 * ApplicationContext 创建并准备好之后,source 加载之前 调用
	 */
	default void contextPrepared(ConfigurableApplicationContext context) {}

	/**
	 * prepareContext 之后,refreshContext 之前 调用
	 */
	default void contextLoaded(ConfigurableApplicationContext context) {}

	/**
	 * refreshContext 之后,ApplicationRunner 和 CommandLineRunner call之前 调用
	 */
	default void started(ConfigurableApplicationContext context) {}

	/**
	 * run方法结束之前 调用
	 */
	default void running(ConfigurableApplicationContext context) {}

	/**
	 * 在运行应用程序时发生故障时 调用
	 */
	default void failed(ConfigurableApplicationContext context, Throwable exception) {}

}

2、SpringApplicationRunListeners

SpringApplicationRunListeners 对象 维护了 SpringApplicationRunListener 集合

  • 所有方法都是 SpringApplicationRunListener 对应方法的循环调用。
class SpringApplicationRunListeners {

    private final Log log;

    private final List<SpringApplicationRunListener> listeners;

    SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList<>(listeners);
    }

    void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }

    void environmentPrepared(ConfigurableEnvironment environment) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.environmentPrepared(environment);
        }
    }

    void contextPrepared(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.contextPrepared(context);
        }
    }

    void contextLoaded(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.contextLoaded(context);
        }
    }

    void started(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.started(context);
        }
    }

    void running(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.running(context);
        }
    }

    void failed(ConfigurableApplicationContext context, Throwable exception) {
        for (SpringApplicationRunListener listener : this.listeners) {
            callFailedListener(listener, context, exception);
        }
    }

    private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception) {
        try {
            listener.failed(context, exception);
        }
        catch (Throwable ex) {
            if (exception == null) {
                ReflectionUtils.rethrowRuntimeException(ex);
            }
            if (this.log.isDebugEnabled()) {
                this.log.error("Error handling failed", ex);
            }
            else {
                String message = ex.getMessage();
                message = (message != null) ? message : "no error message";
                this.log.warn("Error handling failed (" + message + ")");
            }
        }
    }

}

3、listeners 的创建

// org.springframework.boot.SpringApplication

public ConfigurableApplicationContext run(String... args) {
    // ...
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    // ...
}

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(
        logger,
        // 构建 SpringApplicationRunListener 集合
        getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // 从 META-INF/spring.factories 获取 SpringApplicationRunListener
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 创建 SpringApplicationRunListener 对象集合
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

下面看一下 META-INF/spring.factories 中的 SpringApplicationRunListener

在这里插入图片描述

可以看到,只有一个 EventPublishingRunListener

4、EventPublishingRunListener

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

    private final SpringApplication application;

    private final String[] args;

    private final SimpleApplicationEventMulticaster initialMulticaster;

    /**
     * @param application SpringApplication
     * @param args 启动参数
     */
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        // 初始化一个默认的事件广播器
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        // 这里会把 SpringApplication 的监听器集合都放进广播器里
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public void starting() {
        // 通过默认的广播器来广播事件
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        // 通过默认的广播器来广播事件
        this.initialMulticaster
            .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        // 通过默认的广播器来广播事件
        this.initialMulticaster
            .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        for (ApplicationListener<?> listener : this.application.getListeners()) {
            if (listener instanceof ApplicationContextAware) {
                ((ApplicationContextAware) listener).setApplicationContext(context);
            }
            context.addApplicationListener(listener);
        }
        // 通过默认的广播器来广播事件
        this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        // 这里就不一样了,这个是依托于Spring上下文中的广播器来广播的
        context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        // 这里就不一样了,这个是依托于Spring上下文中的广播器来广播的
        context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
    }
}

5、SimpleApplicationEventMulticaster

// org.springframework.context.event.SimpleApplicationEventMulticaster

@Override
public void multicastEvent(ApplicationEvent event) {
    // 广播事件
    multicastEvent(event, resolveDefaultEventType(event));
}

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 获取是否配置了线程池
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        // 线程池异步执行
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        // 同步执行
        else {
            invokeListener(listener, event);
        }
    }
}

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            // 调用监听器
            doInvokeListener(listener, event);
        } catch (Throwable err) {
            errorHandler.handleError(err);
        }
    } else {
        // 调用监听器
        doInvokeListener(listener, event);
    }
}

@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        // 执行监听器的 onApplicationEvent 方法
        listener.onApplicationEvent(event);
    } catch (ClassCastException ex) {
        // ...
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

scj1022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值