SpringBoot启动过程

]SpringBoot启动过程分析,首先打开SpringBoot的启用入口Main类:

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

可以看到main方法里面只有一行核心启用类:SpringApplication.run(ApplicationMain.class, args);这个是关键,在改行打上断点,debug模式启动该main类。点击下一步进入SpringApplication的源码对应的run方法:

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return (new SpringApplication(sources)).run(args);
}

初始化SpringApplication

SpringApplication实例化之前会调用构造方法进行初始化:

public SpringApplication(Object… sources) {
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.initialize(sources);
}

而SpringApplication构造方法的核心是:this.initialize(sources);初始化方法,SpringApplication通过调用该方法来初始化。

private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

1.deduceWebEnvironment方法是用来判断当前应用的环境,该方法通过获取这两个类来判断当前环境是否是web环境,如果能获得这两个类说明是web环境,否则不是。

javax.servlet.Servlet
org.springframework.web.context.ConfigurableWebApplicationContext

2.getSpringFactoriesInstances方法主要用来从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化,然后调用setInitializers方法设置到SpringApplication的initializers属性中。这个过程就是找出所有的应用程序初始化器。

private Collection<? extends T> getSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, Object… args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Set names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

public static List loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();

    try {
       //从spring.factories文件中找出key为ApplicationContextInitializer的类
        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);
    }
}

当前的初始化器有如下几个:

在这里插入图片描述\3.同理调用getSpringFactoriesInstances从spring.factories文件中找出key为ApplicationListener的类并实例化,然后调用setListeners方法设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器。
当前的事件监听器有如下几个:
在这里插入图片描述
4.调用deduceMainApplicationClass方法找出main类,就是这里的ApplicationMain类。

运行SpringApplication

初始化SpringApplication完成之后,调用run方法运行:

public ConfigurableApplicationContext run(String… args) {
//计时器,统计任务的执行时间
StopWatch stopWatch = new StopWatch();
//开始执行
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
this.configureHeadlessProperty();
// 获取SpringApplicationRunListeners启动事件监听器,这里只有一个EventPublishingRunListener
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
listeners.starting();

    try {
        // 构造一个应用程序参数持有类
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 准备并配置环境
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
         // 打印banner图形
        Banner printedBanner = this.printBanner(environment);
        // 创建Spring容器
        context = this.createApplicationContext();
        new FailureAnalyzers(context);
        // 配置Spring容器
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 容器上下文刷新
        this.refreshContext(context);
        // 容器创建完成之后调用afterRefresh方法
        this.afterRefresh(context, applicationArguments);
        // 调用监听器,广播Spring启动结束的事件
        listeners.finished(context, (Throwable)null);
        // 停止计时器
        stopWatch.stop();
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }

        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
        throw new IllegalStateException(var9);
    }
}

SpringApplicationRunListeners

1.获取启动事件监听器,可以看看该方法:

SpringApplicationRunListeners listeners = this.getRunListeners(args);

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

同样的通过调用getSpringFactoriesInstances方法去META-INF/spring.factories文件中拿到SpringApplicationRunListener监听器,当前的SpringApplicationRunListener事件监听器只有一个EventPublishingRunListener广播事件监听器:
在这里插入图片描述
SpringApplicationRunListeners内部持有SpringApplicationRunListener集合和1个Log日志类。用于SpringApplicationRunListener监听器的批量执行。

SpringApplicationRunListener用于监听SpringApplication的run方法的执行,它定义了5个步骤:

starting:run方法执行的时候立马执行,对应的事件类型是ApplicationStartedEvent
environmentPrepared:ApplicationContext创建之前并且环境信息准备好的时候调用,对应的事件类型是ApplicationEnvironmentPreparedEvent
contextPrepared:ApplicationContext创建好并且在source加载之前调用一次,没有具体的对应事件
contextLoaded:ApplicationContext创建并加载之后并在refresh之前调用,对应的事件类型是ApplicationPreparedEvent
finished:run方法结束之前调用,对应事件的类型是ApplicationReadyEvent或ApplicationFailedEvent
SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener,详见获取SpringApplicationRunListeners。它把监听的过程封装成了SpringApplicationEvent事件并让内部属性ApplicationEventMulticaster接口的实现类SimpleApplicationEventMulticaster广播出去,广播出去的事件对象会被SpringApplication中的listeners属性进行处理。

所以说SpringApplicationRunListener和ApplicationListener之间的关系是通过ApplicationEventMulticaster广播出去的SpringApplicationEvent所联系起来的

2.启动事件监听器

通过listeners.starting()可以启动事件监听器SpringApplicationRunListener ,SpringApplicationRunListener 是一个启动事件监听器接口:

public interface SpringApplicationRunListener {
void starting();

void environmentPrepared(ConfigurableEnvironment var1);

void contextPrepared(ConfigurableApplicationContext var1);

void contextLoaded(ConfigurableApplicationContext var1);

void finished(ConfigurableApplicationContext var1, Throwable var2);

}

SpringApplicationRunListener 接口的具体实现就是EventPublishingRunListener类,我们主要来看一下它的startting方法,该方法会封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听。

public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}

配置并准备环境

private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建应用程序的环境信息。如果是web程序,创建StandardServletEnvironment;否则,创建StandardEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境信息。比如profile,命令行参数
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 广播出ApplicationEnvironmentPreparedEvent事件给相应的监听器执行
listeners.environmentPrepared(environment);
// 环境信息的校对
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}

判断环境,如果是web程序,创建StandardServletEnvironment;否则,创建StandardEnvironment。

private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
} else {
return (ConfigurableEnvironment)(this.webEnvironment ? new StandardServletEnvironment() : new StandardEnvironment());
}
}

创建Spring容器上下文

protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 判断是否是web应用,
// 如果是则创建AnnotationConfigEmbeddedWebApplicationContext,否则创建AnnotationConfigApplicationContext
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);
}

配置Spring容器上下文

private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置Spring容器上下文的环境信息
context.setEnvironment(environment);
// Spring容器创建之后做一些额外的事
postProcessApplicationContext(context);
// SpringApplication的初始化器开始工作
applyInitializers(context);
// 遍历调用SpringApplicationRunListener的contextPrepared方法。目前只是将这个事件广播器注册到Spring容器中
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}

// 把应用程序参数持有类注册到Spring容器中,并且是一个单例
context.getBeanFactory().registerSingleton("springApplicationArguments",
        applicationArguments);
if (printedBanner != null) {
    context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}

// 加载sources,sources是main方法所在的类
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 将sources加载到应用上下文中。最终调用的是AnnotatedBeanDefinitionReader.registerBean方法
load(context, sources.toArray(new Object[sources.size()]));
// 广播出ApplicationPreparedEvent事件给相应的监听器执行
// 执行EventPublishingRunListener.contextLoaded方法
listeners.contextLoaded(context);

}

Spring容器创建之后回调方法postProcessApplicationContext

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 如果SpringApplication设置了实例命名生成器,则注册到Spring容器中
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// 如果SpringApplication设置了资源加载器,设置到Spring容器中
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}

初始化器开始工作

protected void applyInitializers(ConfigurableApplicationContext context) {
// 遍历每个初始化器,调用对应的initialize方法
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, “Unable to call initializer.”);
initializer.initialize(context);
}
}

Spring容器创建完成之后会调用afterRefresh方法

ApplicationRunner、CommandLineRunner类都是在在afterRefresh方法中调用的,也就是说在Spring容器创建之后执行的。

protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}

private void callRunners(ApplicationContext context, ApplicationArguments args) {
List runners = new ArrayList();
// 找出Spring容器中ApplicationRunner接口的实现类
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 找出Spring容器中CommandLineRunner接口的实现类
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 对runners进行排序
AnnotationAwareOrderComparator.sort(runners);
// 遍历runners依次执行
for (Object runner : new LinkedHashSet(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值