1 前言
SpringBoot的启动,实际也就是启动了一个定制化的Spring容器。也就是创建了一个ConfigurableApplicationContext对象(AbstractApplicationContext的子类),然后执行refresh()方法。对于Spring的启动过程,可参考Spring加载过程及核心类,这里只简单分析一下SpringBoot如何初始化和启动。为节省篇幅,代码仅抽取主要片段。
文中代码版本是2.1.10.RELEASE。
SpringBoot可以用下面代码的方式启动:
public static void main(String[] args){
SpringApplication app = new SpringApplication(MainApp.class);
ApplicationContext ctx = app.run(args);
}
- 创建SpringApplication对象;
- 执行SpringApplication.run(String... args)。
2 创建SpringApplication对象
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 查找并设置ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 查找并设置监听器 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断启动类
this.mainApplicationClass = deduceMainApplicationClass();
}
2.1 判断应用类型
SpringBoot有三种应用类型:
public enum WebApplicationType {
NONE, // 非web应用
SERVLET, // servlet web应用
REACTIVE // reactive web应用
}
使用ClassUtils.isPresent判断哪些类可以加载到,进而判断是哪种类型的应用:
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
其中:
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
2.2 设置ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
通过方法getSpringFactoriesInstances(Class<T> type)获取org.springframework.context.ApplicationContextInitializer的实例的集合。
2.3 设置ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
通过方法getSpringFactoriesInstances(Class<T> type)获取org.springframework.context.ApplicationListener的实例的集合。
2.4 getSpringFactoriesInstances
- 1 执行
SpringFactoriesLoader.loadFactoryNames读取文件META-INF/spring.factories中指定的接口的实现类的类名; - 2 执行
createSpringFactoriesInstances实例化这些指定的类。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// 获取实现了type接口的类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 实例化获取到的类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames调用SpringFactoriesLoader.loadSpringFactories,获取到接口的实现类的类名:
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
其中:String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
2.5 META-INF/spring.factories
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
3 执行SpringApplication.run(String... args):
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 声明ConfigurableApplicationContext
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
/* 获取SpringApplicationRunListener实例集合,
并执行SpringApplicationRunListener.starting()方法。
*/
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 实例化 ConfigurableApplicationContext
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
/* 1 执行ApplicationContextInitializer.initialize
2 注册所有的BeanDefinition
3 执行SpringApplicationRunListener.contextPrepared/contextLoaded
*/
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 执行refresh
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 执行所有的SpringApplicationRunListener.started方法
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//执行所有的SpringApplicationRunListener.running方法
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
3.1 getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
仍然是调用getSpringFactoriesInstances从META-INF/spring.factories中获取SpringApplicationRunListener的实现类并实例化。
3.2 createApplicationContext
createApplicationContext创建ConfigurableApplicationContext:
3.2.1 获取ConfigurableApplicationContext的实现类
根据在初始化时,获取到的WebApplicationType判断:
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
其中:
DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework. boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext"
这三个类都是org.springframework.context.ConfigurableApplicationContext的实现类。
3.2.2 实例化ConfigurableApplicationContext的实现类
(ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass)
通过org.springframework.beans.BeanUtils实例化获取到的ConfigurableApplicationContext的实现类。
3.3 prepareContext
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 执行前面设置的ApplicationContextInitializer集合的initialize方法
applyInitializers(context);
// 执行所有的SpringApplicationRunListener.contextPrepared方法
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 注册所有的BeanDefinition
load(context, sources.toArray(new Object[0]));
// 执行所有的SpringApplicationRunListener.contextLoaded方法
listeners.contextLoaded(context);
}
3.3.1 load(ApplicationContext context, Object[] sources)
protected void load(ApplicationContext context, Object[] sources){....}主要执行了:
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);loader.load();
createBeanDefinitionLoader方法中创建并返回了一个BeanDefinitionLoader对象:
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = new XmlBeanDefinitionReader(registry);
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
//ClassPathBeanDefinitionScanner.scan方法扫描basePackage下的类,并生成相关beanDefinition。
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
参数sources是前面SpringApplication.run中通过getAllSources()获取后传过来的;
创建BeanDefinitionLoader对象,主要是创建了AnnotatedBeanDefinitionReader,XmlBeanDefinitionReader等对象,用来注册BeanDefinition。
BeanDefinitionLoader.load:
根据不同的source类型,执行不同的BeanDefinition注册:
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());
}
3.4 refreshContext
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
refresh(ApplicationContext)中,最终调用了AbstractApplicationContext.refresh():
// 调用了AbstractApplicationContext.refresh()
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
4 总结
- 1 使用
ClassUtils.isPresent来判断应用类型WebApplicationType; - 2 在
META-INF/spring.factories中定义各接口的实现类; - 3 调用
getSpringFactoriesInstances通过META-INF/spring.factories读取到实现类后实例化; - 4 通过
WebApplicationType判断ConfigurableApplicationContext的实现类,并调用BeanUtils实例化; - 5
ClassPathBeanDefinitionScanner.scan方法扫描basePackage下的类,并生成相关beanDefinition; - 6 执行
ConfigurableApplicationContext.refresh()刷新Spring环境; - 7 通过
AnnotatedBeanDefinitionReader,XmlBeanDefinitionReader等对象注册BeanDefinition。