前文SpringBoot源码学习系列——构造流程分析对SpringApplication
的实例化流程进行了介绍,完成了基本配置文件的加载及初始化,本文对其run
方法进行介绍,看看Spring Boot是如何启动运行的。
run方法核心流程
可以看到,SpringApplication#run
方法返回值为ConfigurableApplicationContext
类型的对象,ConfigurableApplicationContext
接口继承了ApplicationContext
接口。
public ConfigurableApplicationContext run(String... args) {
// 创建StopWatch对象,统计run方法启动时长
// 通过StopWatch#start和StopWatch#stop可以便捷的统计代码块运行时长
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 定义容器及异常信息集合
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置java.awt.headless属性,默认为true
// Headless模式是系统的一种配置模式。在系统可能缺少显示设备、
// 键盘或鼠标这些外设的情况下可以使用该模式。
// 当java程序本身不需要显示awt界面,例如命令行程序,后端程序时使用
// 提高效率、兼容性
configureHeadlessProperty();
// 获取SpringApplicationRunListener数组,封装于SpringApplicationRunListeners的listeners属性中
SpringApplicationRunListeners listeners = getRunListeners(args);
// 遍历listeners 中每个元素SpringApplicationRunListener,启动监听器
listeners.starting();
try {
// 创建默认的ApplicationArguments对象,封装了参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 加载属性配置
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印Banner
Banner printedBanner = printBanner(environment);
// 创建ApplicationContext容器
context = createApplicationContext();
// 异常处理相关
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 初始化容器
refreshContext(context);
// 初始化后执行
afterRefresh(context, applicationArguments);
stopWatch.stop();
// 启动日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 通知监听器,容器started
listeners.started(context);
// 调用ApplicationRunner和CommandLineRunner的run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 通知监听器,容器running
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
此节我们对大致流程进行简要描述,下文对各步骤进行详细分析。
SpringApplicationRunListener监听器
监听器的配置及加载流程
如下为SpringApplicationRunListeners
的源码,存在一个成员变量listeners
,并提供了一系列针对listeners
中SpringApplicationRunListener
监听器进行遍历处理的方法。
getRunListeners
方法
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 通过SpringApplicationRunListeners的构造方法完成listeners加载
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
getSpringFactoriesInstances
方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 通过SpringFactoriesLoader.loadFactoryNames获取
// spring.factories文件中的SpringApplicationRunListener属性值
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 实例化监听器
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
createSpringFactoriesInstances
方法
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
// 检查类型
Assert.isAssignable(type, instanceClass);
// 获取有参构造器,参数为Class<?>[] parameterTypes
// 参数数组内容为Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 因此,SpringApplicationRunListener的实现类应有默认构造方法,
// 参数依次为SpringApplication.class, String[].class
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
// 进行初始化
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
SpringApplicationRunListener源码解析
如下,可以看到run方法各个阶段的时间监听处理方法
public interface SpringApplicationRunListener {
/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
* 执行run方法,立即调用
*/
default void starting() {
}
/**
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
* environment准备完成,ApplicationContext创建前
*/
default void environmentPrepared(ConfigurableEnvironment environment) {
}
/**
* Called once the {@link ApplicationContext} has been created and prepared, but
* before sources have been loaded.
* @param context the application context
* ApplicationContext构建完成,资源加载前
*/
default void contextPrepared(ConfigurableApplicationContext context) {
}
/**
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
* ApplicationContext加载完成,刷新前
*/
default void contextLoaded(ConfigurableApplicationContext context) {
}
/**
* The context has been refreshed and the application has started but
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
* ApplicationRunners} have not been called.
* @param context the application context.
* @since 2.0.0
* ApplicationContext刷新启动完成,CommandLineRunner和ApplicationRunner执行前
*/
default void started(ConfigurableApplicationContext context) {
}
/**
* Called immediately before the run method finishes, when the application context has
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
* {@link ApplicationRunner ApplicationRunners} have been called.
* @param context the application context.
* @since 2.0.0
* 所有准备工作就绪,run方法执行完成前
*/
default void running(ConfigurableApplicationContext context) {
}
/**
* Called when a failure occurs when running the application.
* @param context the application context or {@code null} if a failure occurred before
* the context was created
* @param exception the failure
* @since 2.0.0
* 程序报错
*/
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
EventPublishingRunListener类
EventPublishingRunListener
是SpringBoot中SpringApplicationRunListener
的唯一实现类。
如下,程序执行到某些步骤,调用EventPublishingRunListener
的某方法,封装生成事件对象,然后通过initialMulticaster
的multicastEvent
方法或ConfigurableApplicationContext
的publishEvent
方法完成事件发布。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
// 构造方法中进行参数初始化,创建了SimpleApplicationEventMulticaster事件广播器
// 并将监听器依次添加进事件广播器
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
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));
}
// 该步中完成context的初始化,该步骤之后的方法都通过context的publishEvent进行事件发布
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
// 将监听器添加到上下文context中
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
private static class LoggingErrorHandler implements ErrorHandler {
private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
初始化ApplicationArguments
监听器启动后,进行ApplicationArguments
对象初始化,ApplicationArguments
对象是mian方法中的参数的封装,将参数封装成了Source
对象。
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
初始化ConfigurableEnvironment
通过DefaultApplicationArguments
完成ApplicationArguments
的初始化后,进行ConfigurableEnvironment
的初始化:
首先看一下ConfigurableEnvironment
,该接口继承自Environment
和ConfigurablePropertyResolver
接口,均继承自PropertyResolver
。ConfigurableEnvironment
接口提供了当前运行环境的公开接口,如配置文件Profiles中系统属性和变量的设置、添加、读取、合并等功能接口。
下面简单看下prepareEnvironment
方法,下文对各步骤进行详细说明:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 获取或创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// 配置listener环境
listeners.environmentPrepared(environment);
// 绑定环境到SpringApplication
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
获取或创建环境
private ConfigurableEnvironment getOrCreateEnvironment() {
// 环境不为null,直接返回
if (this.environment != null) {
return this.environment;
}
// 环境为null,根据SpringApplication初始化阶段推断的webApplicationType创建对应环境
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
配置环境
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
判断是否设置数据转换服务
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
// 配置PropertySources
configurePropertySources(environment, args);
// 配置Profiles
configureProfiles(environment, args);
}
下面进行逐步解析:
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
// 获取属性资源信息,以StandardServletEnvironment为例,属性资源如下:
// new StubPropertySource("servletConfigInitParams")
// new StubPropertySource("servletContextInitParams")
// new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())
// new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment())
MutablePropertySources sources = environment.getPropertySources();
// 存在默认属性资源,则添加到PropertySources最后
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;
// 默认属性资源包含命令行属性,通过CompositePropertySource进行组合
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));
}
}
}
完成上面所述PropertySources
配置后,进行Profiles
配置:
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
// 设置哪些配置文件处于激活状态,对应spring.profiles.active的属性值
Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
忽略信息配置
获取环境中spring.beaninfo.ignore的属性值,设置到系统参数中,默认true,该配置项用于决定是否跳过BeanInfo类的扫描。true表示不需要jdk去缓存BeanInfo信息,spring自己缓存。spring在创建bean的时候会利用jdk的一些工具来解析一个类的相关信息,jdk在解析一个类的信息的时候会进行缓存,这里就是禁止了jdk的缓存。
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());
}
}
到此就完成了Environment的基本处理。
打印banner
默认使用SpringBootBanner
private Banner printBanner(ConfigurableEnvironment environment) {
// 判断Banner打印开关
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);
}
Spring应用上下文创建
下面我们分析下createApplicationContext
方法,该方法完成Spring应用上下文的创建
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);
}
}
// 通过Spring提供的BeanUtils进行实例化
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
可以看到,该方法中通过枚举类型进行判断,根据前面推断得到的web应用类型创建不同的上下文容器。
Spring应用上下文准备
下面首先看下prepareContext
方法的源码吗,以listeners.contextPrepared(context);
为界,以上为准备阶段,以下为加载阶段:
// 参数为前面创建的上下文对象context、环境environment、监听器listener、封装的参数对象applicationArguments、banner对象
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置上下文的配置环境
context.setEnvironment(environment);
// 应用上下文后置处理
postProcessApplicationContext(context);
// 初始化上下文
applyInitializers(context);
// 通知监听器context准备完成,以上为上下文准备,以下为上下文加载
listeners.contextPrepared(context);
// 打印日志,启动profile
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 获得ConfigurableListableBeanFactory,注册单例对象
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
// 注册printedBanner对象
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
// 设置是否允许覆盖注册
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 添加懒加载后置处理器
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
// 获取配置源,添加到context
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 通知监听器context加载完成
listeners.contextLoaded(context);
}
应用上下文准备阶段
从上面源码可知,准备阶段包含三步:设置环境environment
,后置处理器和ApplicationContextInitializer
初始化上下文。
- 设置环境
environment
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
// 设置environment
super.setEnvironment(environment);
// 设置environment的reader和scanner属性的conditionEvaluator属性
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
- 后置处理
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 如果beanNameGenerator不为null,按默认名org.springframework.context.annotation.internalConfigurationBeanNameGenerator注册单例对象,bean名称生成策略
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// resourceLoader不为空,根据不同类型进行设置
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
// 设置转换服务
if (this.addConversionService) {
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
applyInitializers
进行上下文初始化
protected void applyInitializers(ConfigurableApplicationContext context) {
// 获取ApplicationContextInitializer集合,遍历进行初始化context
// 此处getInitializers对initializers的值进行了排序去重,initializers即前面SpringApplication初始化阶段设置的值
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
// 判断initializer 和 context 类型是否匹配
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// 初始化context
initializer.initialize(context);
}
}
应用上下文加载阶段
上下文加载阶段包含以下几步:日志打印及profile设置、设置是否允许覆盖注册、获取配置源、加载配置源到context、通知监听器context加载完成。
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 获取ConfigurableListableBeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册applicationArguments单例对象
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 注册printedBanner单例对象
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 设置覆盖注册,即是否允许名称相同的bean的覆盖,springboot中默认false
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 开启了懒加载,则需设置后置处理器
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
// 获取配置源集合
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 将配置源信息加载到context
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
// 设置primarySources,primarySources是SpringApplication的构造函数参数,一般为主类
if (!CollectionUtils.isEmpty(this.primarySources)) {
allSources.addAll(this.primarySources);
}
// // 设置sources,通过setResources方法设置的值
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
// 返回不可修改的集合
return Collections.unmodifiableSet(allSources);
}
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 通过BeanDefinitionLoader加载配置资源
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
loader.load()
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());
}
从上面load
方法可以看出,BeanDefinitionLoader
加载支持的范围包括Class、Resource、Package、CharSequence,sources来源包括primarySources和setResources两种,分别对应Class和CharSequence。
Spring应用上下文刷新
private void refreshContext(ConfigurableApplicationContext context) {
// 核心方法
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
@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.
// 通知子类刷新内部bean factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 为context准备bean factory
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 运行context的子类第bean factory进行后置处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用context中注册为bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册bean处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化信息源
initMessageSource();
// Initialize event multicaster for this context.
// 初始化事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 初始化其他子类特殊的bean
onRefresh();
// Check for listener beans and register them.
// 检查并注册事件监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 发布事件,该方法之后,spring应用上下文正式开启
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 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();
}
}
}
refreshContext
完成后,Spring应用上下文完成启动,继续执行afterRefresh
,其默认实现为空。
调用AppllicationRunner和CommandLineRunner
下面继续看下callRunners
方法:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
// 将ApplicationRunner和CommandLineRunner类型的bean添加到runner列表中,并排序(@Order注解或者实现Ordered接口控制顺序)
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
// 遍历runner依次调用callRunner方法
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
通过实现ApplicationRunner
或CommandLineRunner
接口并重写run()
方法,实现应用初始化时的一些自定义操作执行,如初始化某参数或组件等。