前言
继 Spring源码解读(十三)Boot启动类——SpringApplication构造方法 后,继续分析SpringApplication.run方法。
程序入口
启动方法中增加一些boot的新特性处理,但是对于spring核心部分依旧使用的AbstractApplicationContext.refresh方法。
public ConfigurableApplicationContext run(String... args) {
// 计时器记录启动耗时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 配置系统属性 java.awt.headless
configureHeadlessProperty();
// 创建spring运行监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布spring启动事件
listeners.starting();
try {
// 应用的启动参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 加载环境配置
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置spring.beaninfo.ignore信息
configureIgnoreBeanInfo(environment);
// 打印启动banner
Banner printedBanner = printBanner(environment);
// 创建ConfigurableApplicationContext类型的应用上下文对象
context = createApplicationContext();
// 加载SpringBootExceptionReporter
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 将context进行封装,将上面得到的environment、listeners、applicationArguments、printedBanner都注册到context中
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文对象,实际上调用的就是AbstractApplicationContext.refresh
refreshContext(context);
// 刷新后执行的逻辑,目前是空方法,留给子类扩展
afterRefresh(context, applicationArguments);
// 停止计时器
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 发布启动完成事件
listeners.started(context);
// 通知ApplicationRunner和CommandLineRunner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
创建Spring运行监听器
/**
* 创建Spring运行监听器,
* SpringApplicationRunListeners用来监听SpringApplication的run方法
* @param args
* @return
*/
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
保存应用启动参数
使用DefaultApplicationAgrument对象记录启动时传入的args
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
加载环境配置
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 创建ConfigurableEnvironment对象,根据web应用的类型返回不同的子类
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 对environment进行配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 为environment添加附加属性
ConfigurationPropertySources.attach(environment);
// 监听器发布环境参数加载事件
listeners.environmentPrepared(environment);
// 将环境参数绑定的spring应用中
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
// 对非自定义的环境进行转换
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
// 为environment添加附加属性
ConfigurationPropertySources.attach(environment);
return environment;
}
对environment进行配置
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
// 设置 conversionService
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
// 设置属性源
configurePropertySources(environment, args);
// 设置引用的配置文件
configureProfiles(environment, args);
}
设置属性源和引用配置文件
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));
}
// 添加来自启动参数的属性
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));
}
}
}
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
配置spring.beaninfo.ignore信息
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
}
}
创建ApplicationContext对象
根据不同的应用类型实例化不同的bean
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
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);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
加载SpringBootExceptionReporter
从META-INF/spring.factories文件中加载和实例化给定类型的工厂,在上篇 Spring源码解读(十三)Boot启动类——SpringApplication构造方法 已经分析过了。
对context进行封装
这一步是准备Context环境,主要分为6个步骤。
- 统一ApplicationContext和Application使用environment
- ApplicationContext后置处理
- context初始化
- 发布准备context事件
- 为beanfactory添加必要的bean
- 发布context加载成功事件
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 为context设置env属性
context.setEnvironment(environment);
// ApplicationContext后置处理
postProcessApplicationContext(context);
// 初始化context
applyInitializers(context);
// 发布context准备完成事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 为beanFactory添加系统必要的单例类
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// applicationArguments 启动参数
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
// 懒加载模式设置懒加载bean后置处理器
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 为context加载必要的配置,如beanName生成策略,env等
load(context, sources.toArray(new Object[0]));
// 发布context加载成功事件
listeners.contextLoaded(context);
}
为context设置环境参数
ConfigurableApplicationContext的几个实现类中对setEnvironment的处理都是一样的。最终都通过执行到了父类ClassPathScanningCandidateComponentProvider和AnnotatedBeanDefinitionReader的setEnvironment,在 Spring源码解读(十二)通过包路径扫描Bean——ClassPathBeanDefinitionScanner 已经分析过了。
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
ApplicationContext后置处理
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
// 想beanFactory注册beanName生成器,并指定生成器的beanName
// CONFIGURATION_BEAN_NAME_GENERATOR = "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
// 对GenericApplicationContext的上下文环境设置 资源加载器
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
// 对DefaultResourceLoader的上下文环境设置 ClassLoader
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
// 设置类型转换service
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
执行spring初始化器
执行org.springframework.context.ApplicationContextInitializer的子类的逻辑,这里涉及到很多个实现类,先不展开。
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);
}
}
为context加载必要的配置
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
// 设置beanName生成器
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
// 设置资源加载器
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
// 设置环境参数
loader.setEnvironment(this.environment);
}
loader.load();
}
刷新Context
执行的就是AbstractApplicationContext的refresh方法,具体分析在 Spring源码解读(一)启动流程分析——AbstractApplicationContext
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
refresh(context);
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
刷新Context后的处理
这是一个空方法,留给子类扩展
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}
通知ApplicationRunner和CommandLineRunner
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}