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
中的 Initializers
和 Listeners
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.loadFactoryNames
在 SpringBoot源码(自动装配)讲过,这里就不再赘述了。
二、执行实例的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) {
// ...
}
}