Spring Boot启动流程
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启动简单流程
- 启动类里面调用SpringApplication.run(xxx.class,args)方法
- 在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();
}
- 在SpringApplicaiton构造器中调用initialize(sources)方法。
- 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方法找到启动主类。 - 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. 返回上下文对象