在springboot种执行这一行操作的时候,SpringApplication.run(DemoApplication.class, args);运行如下代码,初始化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();
// 初始化spring里面的工厂:获取 META-INF/spring.factories 对应的资源
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// getSpringFactoriesInstances初始化监听器实例,
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 获取主函数的位置,并且得到它的class
this.mainApplicationClass = deduceMainApplicationClass();
}
在springboot配置文件中定义了启动需要使用的Run Listeners和 Application Listeners。然后由getSpringFactoriesInstance完成了对这些Listenners的实例化。
loadSpringFactories代码如下:
public static final String FACTORIES_RESOURCE_LOCATION ="META-INF/spring.factories";
private static Map<String, List<String>> loadSpringFactorie(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.ge(classLoader);
if (result != null) {
return result;
}
try {
// 获取 META-INF/spring.factories 对应的资源
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResource(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResource(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 读取文件内容
Properties properties =PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySe()) {
String factoryClassName = ((String)entry.getKey()).trim();
for (String factoryName :StringUtils.commaDelimitedListToStringArray(String) entry.getValue())) {
// 获取 factoryClassName 对应的多个valu(多个value用逗号分隔)
result.add(factoryClassName,factoryName.trim());
}
}
}
// 缓存已经读取到的内容
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to loadfactories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
然后调用SpringApplication.run方法
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();//StopWatch主要是用来统计每项任务执行时长
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 1.获取在new Application对象时创建的Listeners:
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();// 2.开启listener,并找到相应的接收者完成初始化日志和参数
try {
// 设置参数:在springboot启动时传入agrs校验和他的操作方法封装起来
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 3 .环境初始化
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 4. 创建spring的aplicationContxt容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 5. 将启动需要的参数,listeners,environment等加入容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 6.
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
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;
}
SpringApplication
中的getRunListeners
调用了
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 调用getSpringFactoriesInstances,注意传入参数是SpringApplicationRunListener.class
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 调用createSpringFactoriesInstances
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
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 {
// 将listener反射加载到内存
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
// 含有内部类
Assert.isAssignable(type, instanceClass);
// 获取构造器
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;
}
反射过程中触发EventPublishingRunListener
的构造函数,因为EventPublishingRunListener
是SpringApplicationRunListener.class
的一个子类,并且它内部有一个内部类SimpleApplicationEventMulticaster
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 将application这个启动类传入,通过启动类获取了前面从配置文件中读取出来的listeners
// 内部类将所有listeners接收到了
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
SimpleApplicationEventMulticaster的继承关系如下:
listeners.starting()
实际上是调用了EventPublishingRunListener的startings方法。
EventPublishingRunListener
中的starting
方法
@Override
public void starting() {
// 调用multicastEvent:这里发送一个事件ApplicationStartingEvent。不能够传入参数为启动类,其启动类中的参数
//发送事件由EventPublishingRunListener的内部类SimpleApplicationEventMulticaster的multicastEvent方法完成,
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
@Override
public void multicastEvent(ApplicationEvent event) {
// 调用multicastEvent
multicastEvent(event, resolveDefaultEventType(event));
}
// 将启动项目的事件发送给所有的listeners
@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);
}
}
}
读取配置文件就是在此处:
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 1.创建Environment对象:前面将environment已经被设置了servlet类型,所以这里创建的是环境对象是StandardServletEnvironment。
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境数据
// **commandLineArgs**属性从启动参数中解析, 格式"--name=value"
// 配置profiles. 有效的profile(通过**spring.profiles.active**配置) 和 通过SpringApplication.profiles()指定的额外profile
configureEnvironment(environment,applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// 2. 发布ApplicationEnvironmentPreparedEvent事件到所有的listeners上
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverte(getClassLoader())
.convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
Environment
接口提供了4种实现方式,StandardEnvironment
、StandardServletEnvironment
和MockEnvironment
、StandardReactiveWebEnvironment
,分别代表普通程序、Web程序、测试程序的环境、响应式web环境。
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
environmentPrepared
发布的时间会被onApplicationEnvironmentPreparedEvent
这个监听器接收到,然后就会加载EnvironmentPostProcessor
对象。除了上面3.1.1中的"META-INF/spring.factories"文件中的listener,还有ConfigFileApplicationListener
。
实际上ConfigFileApplicationListener
在onApplicationEnvironmentPreparedEvent
方法中,将自身添加到EnvironmentPostProcessor
对象列表中。
ConfigFileApplicationListener
监听到ApplicationEnvironmentPreparedEvent
事件之后开始读取本地配置文件
private void onApplicationEnvironmentPreparedEvent(
ApplicationEnvironmentPreparedEvent event) {
// 将自身添加到EnvironmentPostProcessor对象列表中
List<EnvironmentPostProcessor> postProcessors =loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
// 调用所有EnvironmentPostProcessor 的postProcessEnvironmen方法
for (EnvironmentPostProcessor postProcessor :postProcessors) {
postProcessor.postProcessEnvironmen(event.getEnvironment(),
event.getSpringApplication());
}
}
List<EnvironmentPostProcessor> loadPostProcessors() {
return SpringFactoriesLoader.loadFactorie(EnvironmentPostProcessor.class,
getClass().getClassLoader());
}
其中ConfigFileApplicationListener
的postProcessEnvironmen
方法就是调用addPropertySources
。
在getOrCreateEnvironment中得到的环境变量会被加入到其父类AbstractEnvironment
定义的对象MutablePropertySources
中,MutablePropertySources
对象中定义了一个属性集合:
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
在ConfigFileApplicationListener
中收到消息加入到了propertySourceList中
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
addPropertySources(environment, application.getResourceLoader());
}
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
// 加载properties和yml
new Loader(environment, resourceLoader).load();
}
如图:在new Loader(environment, resourceLoader).load();这一行执行的时候才会出现在propertySourceList
中间出现OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}
。并加载其中的内容
根据webApplicationType进行判断的,上一篇已经讲述了该变量如何赋值的过程。因为该类型为SERVLET类型。故是DEFAULT_WEB_CONTEXT_CLASS
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_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);
}
这里还是以同样的方式获取 spring.factories文件中的指定类:
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
其中SpringApplication.run方法的调用的预处理过程如下:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置容器环境,包括各种变量
context.setEnvironment(environment);
// 执行前置处理器
postProcessApplicationContext(context);
//执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
applyInitializers(context);
// 发送容器已经准备好的事件,通知各监听器
listeners.contextPrepared(context);
// 打印log
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// bean工厂注册单例对象
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 注册banner为单例对象
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 设置beanFactory是否可以被重写
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// context种添加LazyInitializationBeanFactoryPostProcessor这种类型的工厂
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
// 加载运行所需要的资源
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载我们的启动类,将启动类注入容器
load(context, sources.toArray(new Object[0]));
// 发布容器已加载事件
listeners.contextLoaded(context);
}
这里默认不执行任何逻辑,因为beanNameGenerator和resourceLoader默认为空。之所以这样做,是springBoot留给我们的扩展处理方式
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
load(context, sources.toArray(new Object[0]));
这里会将我们的启动类加载spring容器beanDefinitionMap中,为后续springBoot 自动化配置奠定基础,springBoot为我们提供的各种注解配置也与此有关。
这里参数即为我们项目启动时传递的参数:SpringApplication.run(SpringBootApplication.class, args);
由于我们指定了启动类,所以上面也就是加载启动类到容器。
通知监听器context加载成功。
listeners.contextLoaded(context);
执行到这里,springBoot相关的处理工作已经结束,接下的工作就交给了spring。refresh方法在spring整个源码体系中举足轻重,是实现 ioc 和 aop的关键。
@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.
// 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
/* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
* 设置SPEL表达式#{key}的解析器
* 设置资源编辑注册器,如PerpertyEditorSupper的支持
* 添加ApplicationContextAwareProcessor处理器
* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
*/
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
/**
* 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
*/
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
/**
* 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
* 执行对应的postProcessBeanDefinitionRegistry方法 和 postProcessBeanFactory方法
*/
invokeBeanFactoryPostProcessors(beanFactory);// 初始化bean
// Register bean processors that intercept bean creation.
/**
* 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
* 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
*/
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
/**
* 初始化上下文中的资源文件,如国际化文件的处理等
*/
initMessageSource();
// Initialize event multicaster for this context.
/**
* 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
*/
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
/**
* 给子类扩展初始化其他Bean
*/
onRefresh();
// Check for listener beans and register them.
/**
* 在所有bean中查找listener bean,然后注册到广播器中
*/
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
/**
* 设置转换器
* 注册一个默认的属性值解析器
* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
*/
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
/**
* 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
* spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行,如一直轮询kafka
* 启动所有实现了Lifecycle接口的类
* 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理,即对那种在spring启动后需要处理的一些类,这些类实现了
* ApplicationListener ,这里就是要触发这些类的执行(执行onApplicationEvent方法)另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
* 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
*/
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();
}
}
}
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
参考文献:
https://juejin.im/post/5cb7264af265da03751699b1
https://www.iteye.com/blog/tanliwei-2422300
https://blog.csdn.net/woshilijiuyi/article/details/82219585