看了很多关于spring boot 的源码分析,感觉都只在关注面试题, 关键注解,但是这样并无法达到对其启动的深刻理解,只是死板的记忆,,过了几天又忘了 ,所以我在看完之后打算把他记下来,以供以后复习使用。重点是一定要自己点一遍
文章目录
一. 核心注解SpringBootApplication
@SpringBootConfiguration – 配置类 就是@Configuration
@EnableAutoConfiguration – 核心注解,通过@import + @Configuration + @Bean 导入第三方jar
@ComponentScan – 包扫描,默认扫当前启动类所在包一下的所有注解 ,将其加入IOC
二. 启动类SpringApplication.run()
new SpringApplication(primarySources).run(args);
启动类Run方法可以分为两部分
new SpringApplication(primarySources)
run(args);方法
1. 第一部分 入口类 new SpringApplication(primarySources)
primarySources == HelloworldApplication.class 启动类 类型
@SpringBootApplication
public class HelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}
}
进入启动类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//把HelloWorldMainApplication.class设置为属性存储起来
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//设置应用类型是Standard还是Web
this.webApplicationType = deduceWebApplicationType();
//引导程序,初始化
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
//设置初始化器(Initializer),最后会调用这些初始化器
setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
//设置监听器(Listener)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
重点 分析三句:
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
1.1 getBootstrapRegistryInitializersFromSpringFactories()
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
getSpringFactoriesInstances(Bootstrapper.class).stream()
.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
.forEach(initializers::add);
initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
return initializers;
}
核心方法: getSpringFactoriesInstances()
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
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));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames()
通过classloader 的双亲委派机制加载所有jar中的META-INF/spring.factories文件
并将其读取存入cache中以便下次取用。
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
//从类路径的META-INF/spring.factories中加载所有默认的自动配置类
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
其中存储的是spring 启动中重要的类及其对应子类
在启动中接下来药用到的就是ApplicationContextInitializer 和 ApplicationListener , 最重要的还有EnableAutoConfiguration , 可以看到他又130个子类(后面再说)
当他初始化好之后,会进行一个过滤
loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
获取当前传入class的配置,当前是Bootstrapper.class , 但是在配置文件中并没有他的配置。所以instance最终为0
最后返回到最外层getBootstrapRegistryInitializersFromSpringFactories
此时bootstrapRegistryInitializers还没有值(size为0)
1.2 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
同样的逻辑,这次会取出所有ApplicationContextInitializer.class的子类
随后通过createSpringFactoriesInstances , 为所有的子类创建一个空的实例
1.3 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
同ApplicationContextInitializer , 创建所需的Listener
1.4 deduceMainApplicationClass()设置应用类型
这里主要是通过类加载器判断REACTIVE相关的Class是否存在,如果不存在,则web环境即为SERVLET类型。这里设置好web环境类型,在后面会根据类型初始化对应环境。
由于Web应用中spring-webmvc中存在DispatcherServlet这个类,也就是我们以前SpringMvc的核心Servlet,通过类加载能加载DispatcherServlet这个类,那么我们的应用类型自然就是WebApplicationType.SERVLET
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
// 相关常量
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.reactive.DispatcherHandler";
private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.servlet.DispatcherServlet";
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
1.5 小结
至此,主要的类初始化成功 ,主要用到的方法就是 getSpringFactoriesInstances() ,第一次调用的时候通过classLoder 的 双亲委派机制 找到当前环境所有jar 中的META-INF/spring.factories , 其中会包括spring boot自己的所需的类和第三方jar中META-INF/spring.factories 包含的所需类。
在读取到所有类限定全路径名之后,通过产生的properties文件寻找ApplicationContextInitializer 以及ApplicationListener 的所有子类,进行一个instance实例的创建,至此new SpringApplication()主要过的功能结束。
2. 第二部分run(args);方法
废话不说,先上代码
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 第一步:获取并启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 第二步:根据SpringApplicationRunListeners以及参数来准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
configureIgnoreBeanInfo(environment);
// 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
Banner printedBanner = printBanner(environment);
// 第三步:创建Spring容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 第四步:Spring容器前置处理
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
// 第五步:刷新容器
refreshContext(context);
// 第六步:Spring容器后置处理
afterRefresh(context, applicationArguments);
// 第七步:发出结束执行的事件
listeners.started(context);
// 第八步:执行Runners
this.callRunners(context, applicationArguments);
stopWatch.stop();
// 返回容器
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
}
一共有8步
第一步:获取并启动监听器
第二步:根据SpringApplicationRunListeners以及参数来准备环境
第三步:创建Spring容器
第四步:Spring容器前置处理
第五步:刷新容器
第六步:Spring容器后置处理
第七步:发出结束执行的事件
第八步:执行Runners
再一步一步分析
第一步:获取并启动监听器
获取监听器
getRunListeners方法:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
这里仍然利用了getSpringFactoriesInstances方法来获取实例,从META-INF/spring.factories中读取Key为org.springframework.boot.SpringApplicationRunListener的Values,这里是EventPublishingRunListener:
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
getSpringFactoriesInstances中反射获取实例时会触发EventPublishingRunListener的构造函数:
列举核心如下,重点是在于这个广播器,EventPublishingRunListener 的构造方法将SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
//广播器
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
//将上面设置到SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中
this.initialMulticaster.addApplicationListener(listener);
}
}
}
将Listener添加到广播器:this.initialMulticaster.addApplicationListener(listener);
关键代码为this.defaultRetriever.applicationListeners.add(listener);,这是一个内部类,用来保存所有的监听器。也就是在这一步,将spring.factories中的监听器传递到SimpleApplicationEventMulticaster中。我们现在知道EventPublishingRunListener中有一个广播器SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster广播器中又存放所有的监听器。
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
//广播器的父类中存放保存监听器的内部内
private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false);
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
//内部类对象
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
private class ListenerRetriever {
//保存所有的监听器
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet();
public final Set<String> applicationListenerBeans = new LinkedHashSet();
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered) {
this.preFiltered = preFiltered;
}
public Collection<ApplicationListener<?>> getApplicationListeners() {
LinkedList<ApplicationListener<?>> allListeners = new LinkedList();
Iterator var2 = this.applicationListeners.iterator();
while(var2.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var2.next();
allListeners.add(listener);
}
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory();
Iterator var8 = this.applicationListenerBeans.iterator();
while(var8.hasNext()) {
String listenerBeanName = (String)var8.next();
try {
ApplicationListener<?> listenerx = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (this.preFiltered || !allListeners.contains(listenerx)) {
allListeners.add(listenerx);
}
} catch (NoSuchBeanDefinitionException var6) {
;
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
}
}
启动监听器 listeners.starting();
上面一步通过getRunListeners方法获取的监听器为EventPublishingRunListener,从名字可以看出是启动事件发布监听器,主要用来发布启动事件。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
先来看看SpringApplicationRunListener这个接口
SpringApplicationRunListener接口在Spring Boot 启动初始化的过程中各种状态时执行,我们也可以添加自己的监听器,在SpringBoot初始化时监听事件执行自定义逻辑
package org.springframework.boot;
public interface SpringApplicationRunListener {
// 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
void starting();
// 当environment构建完成,ApplicationContext创建之前,该方法被调用
void environmentPrepared(ConfigurableEnvironment environment);
// 当ApplicationContext构建完成时,该方法被调用
void contextPrepared(ConfigurableApplicationContext context);
// 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
void contextLoaded(ConfigurableApplicationContext context);
// 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
void started(ConfigurableApplicationContext context);
// 在run()方法执行完成前该方法被调用
void running(ConfigurableApplicationContext context);
// 当应用运行出错时该方法被调用
void failed(ConfigurableApplicationContext context, Throwable exception);
}
listeners.starting():
@Override
public void starting() {
//关键代码,先创建application启动事件`ApplicationStartingEvent`
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
这里先创建了一个启动事件ApplicationStartingEvent,继续进SimpleApplicationEventMulticaster,有个核心方法multicastEvent:
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//通过事件类型ApplicationStartingEvent获取对应的监听器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//获取线程池,如果为空则同步处理。这里线程池为空,还未没初始化。
Executor executor = getTaskExecutor();
if (executor != null) {
//异步发送事件
executor.execute(() -> invokeListener(listener, event));
}
else {
//同步发送事件
invokeListener(listener, event);
}
}
}
这里会根据事件类型ApplicationStartingEvent获取对应的监听器,在容器启动之后执行响应的动作,有如下4种监听器:
之后回去查询当前是否又线程池,如果有就新建线程异步调用, 如果没有就同步来进行初始化启动
进入 SimpleApplicationEventMulticaster . invokeListener 会调用SimpleApplicationEventMulticaster.doInvokeListener ,在doInvokeListener中会执行listener.onApplicationEvent();
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
然后就会进入当前传入的子类的onApplicationEvent方法,根据传入的不同的event的实例的type会进行不同阶段的初始化。这里一分析LoggingApplicationListener为例 , 此时传入的ApplicationEvent 的子类实例类型为org.springframework.boot.context.event.ApplicationStartingEvent,所以就会进行onApplicationStartedEvent()的事件。
此处只关注Spring boot的启动,对于logging初始化,后续在进行研究
@Override
public void onApplicationEvent(ApplicationEvent event) {
//在springboot启动的时候
if (event instanceof ApplicationStartedEvent) {
onApplicationStartedEvent((ApplicationStartedEvent) event);
}
//springboot的Environment环境准备完成的时候
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
//在springboot容器的环境设置完成以后
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
//容器关闭的时候
else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
.getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
//容器启动失败的时候
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
到这里,listeners的初始化和启动就完成了。
第二步:环境构建
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
进入该方法
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
//获取对应的ConfigurableEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
//发布环境已准备事件,这是第二次发布事件
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
ConfigurationPropertySources.attach(environment);
return environment;
}
来看一下getOrCreateEnvironment()方法,前面已经提到,environment已经被设置了servlet类型,所以这里创建的是环境对象是StandardServletEnvironment。
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();
}
}
接下来看一下listeners.environmentPrepared(environment)这里进行listeners的第二次事件发布.
一路跟进去,又到了EventPublishingRunListener , 继续由他进行environmentPrepared的事件发布,这里会将之前的Enviroment传进去生成一个新的ApplicationEnvironmentPreparedEvent
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
根据ApplicationEnvironmentPreparedEvent就会找到如下这些实现了ApplicationListener<ApplicationEnvironmentPreparedEvent>的监听器。
后续需要看的和补充的是AbstractApplicationEventMulticaster.getApplicationListeners方法,可以看到ConfigFileApplicationListener实现的是SmartApplicationListener,其中定义了supportsEventType()这个方法,也就是说应该可以让ConfigFileApplicationListener完成对多个Event的实现,需要后续进行仔细研究
主要来看一下ConfigFileApplicationListener,该监听器非常核心,主要用来处理项目配置。项目中的 properties 和yml文件都是其内部类所加载。具体来看一下:
可以看到,这里通过寻找在META-INF/spring.factories中的EnvironmentPostProcessor的配置,寻找到以下实现类。(由于我整合了Spring cloud,所以多了HostInfo类)
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
在执行完上述四个监听器流程后,ConfigFileApplicationListener会执行该类本身的逻辑。由其内部类Loader加载项目制定路径下的配置文件:
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
至此,项目的变量配置已全部加载完毕
这里一共6个配置文件,取值顺序由上到下。也就是说前面的配置变量会覆盖后面同名的配置变量。项目配置变量的时候需要注意这点。
第三步:创建容器
context = createApplicationContext();
这里创建容器的类型 还是根据webApplicationType进行判断的,该类型为SERVLET类型,所以会通过反射装载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext
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:
// public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext";
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容器前置处理
这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
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);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//注册启动参数bean,这里将容器指定的参数封装成bean,注入容器,大白话就是我们在启动容器时输的命令行
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//设置banner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
//
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
//获取我们的启动类指定的参数,可以是多个
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载我们的启动类,将启动类注入容器
load(context, sources.toArray(new Object[0]));
//发布容器已加载事件。
listeners.contextLoaded(context);
}
调用初始化器
这里终于用到了在创建SpringApplication实例时设置的初始化器了,依次对它们进行遍历,并调用initialize方法。我们也可以自定义初始化器,并实现initialize方法,然后放入META-INF/spring.factories配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value中,这里我们自定义的初始化器就会被调用,是我们项目初始化的一种方式
protected void applyInitializers(ConfigurableApplicationContext context) {
// 1. 从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer
for (ApplicationContextInitializer initializer : getInitializers()) {
// 2. 循环调用ApplicationContextInitializer中的initialize方法
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
加载启动指定类(重点)
先回到最开始,在创建SpringApplication实例时,将HelloWorldMainApplication.class存储在this.primarySources属性中,现在就是用到这个属性的时候了,我们来看看getAllSources()
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet();
if (!CollectionUtils.isEmpty(this.primarySources)) {
//获取primarySources属性,也就是之前存储的HelloWorldMainApplication.class
allSources.addAll(this.primarySources);
}
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
return Collections.unmodifiableSet(allSources);
}
很明显,获取了this.primarySources属性,也就是我们的启动类HelloWorldMainApplication.class,我们接着看load(context, sources.toArray(new Object[0]));
/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
*/
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) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
/**
* Load the sources into the reader.
*/
void load() {
for (Object source : this.sources) {
load(source);
}
}
private int load(Class<?> source) {
if (isGroovyPresent()
&& GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
if (isComponent(source)) {
//以注解的方式,将启动类bean信息存入beanDefinitionMap,也就是将HelloWorldMainApplication.class存入了beanDefinitionMap
this.annotatedReader.register(source);
return 1;
}
return 0;
}
这个annotatedReader 就是AnnotatedBeanDefinitionReader , 最终会调用AnnotatedBeanDefinitionReader的doRegisterBean()方法,将HelloWorldMainApplication.class放入beanDefinitionMap
后续该启动类将作为开启自动化配置的入口,之后再详细的分析,启动类是如何加载,以及自动化配置开启的详细流程。
通知监听器,容器已准备就绪
主要是对一些日志等监听器的响应处理
listeners.contextLoaded(context);
第五步:刷新容器
至此springBoot相关的处理工作已经结束,接下的工作就交给了spring。
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
//调用创建的容器applicationContext中的refresh()方法
((AbstractApplicationContext)applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/**
* 刷新上下文环境
*/
prepareRefresh();
/**
* 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/**
* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
* 添加ApplicationContextAwareProcessor处理器
* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
*/
prepareBeanFactory(beanFactory);
try {
/**
* 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
*/
postProcessBeanFactory(beanFactory);
/**
* 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
* 执行对应的postProcessBeanDefinitionRegistry方法 和 postProcessBeanFactory方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
/**
* 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
* 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
*/
registerBeanPostProcessors(beanFactory);
/**
* 初始化上下文中的资源文件,如国际化文件的处理等
*/
initMessageSource();
/**
* 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
*/
initApplicationEventMulticaster();
/**
* 给子类扩展初始化其他Bean
*/
onRefresh();
/**
* 在所有bean中查找listener bean,然后注册到广播器中
*/
registerListeners();
/**
* 设置转换器
* 注册一个默认的属性值解析器
* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
*/
finishBeanFactoryInitialization(beanFactory);
/**
* 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理
* 即对那种在spring启动后需要处理的一些类,这些类实现了ApplicationListener<ContextRefreshedEvent>,
* 这里就是要触发这些类的执行(执行onApplicationEvent方法)
* 另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
* 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
*/
finishRefresh();
}
finally {
resetCommonCaches();
}
}
}
efresh方法在spring整个源码体系中举足轻重,是实现 ioc 和 aop的关键。关于Spring的详细分析后续再写新的博客记录。
第六步:Spring容器后置处理
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。
第七步:发布结束执行的事件
获取EventPublishingRunListener监听器,并执行其started方法,并且将创建的Spring容器传进去了,创建一个ApplicationStartedEvent事件,并执行ConfigurableApplicationContext 的publishEvent方法,也就是说这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的11个监听器发布启动事件。
public void started(ConfigurableApplicationContext context) {
//这里就是获取的EventPublishingRunListener
Iterator var2 = this.listeners.iterator();
while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
//执行EventPublishingRunListener的started方法
listener.started(context);
}
}
public void started(ConfigurableApplicationContext context) {
//创建ApplicationStartedEvent事件,并且发布事件
//我们看到是执行的ConfigurableApplicationContext这个容器的publishEvent方法,和前面的starting是不同的
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
第八步:执行callRunners(context, applicationArguments);
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
//获取容器中所有的ApplicationRunner的Bean实例
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//获取容器中所有的CommandLineRunner的Bean实例
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
//执行ApplicationRunner的run方法
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
//执行CommandLineRunner的run方法
callRunner((CommandLineRunner) runner, args);
}
}
}
如果是ApplicationRunner的话,则执行如下代码:
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
runner.run(args);
} catch (Exception var4) {
throw new IllegalStateException("Failed to execute ApplicationRunner", var4);
}
}
如果是CommandLineRunner的话,则执行如下代码:
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
runner.run(args.getSourceArgs());
} catch (Exception var4) {
throw new IllegalStateException("Failed to execute CommandLineRunner", var4);
}
}
我们也可以自定义一些ApplicationRunner或者CommandLineRunner,实现其run方法,并注入到Spring容器中,在SpringBoot启动完成后,会执行所有的runner的run方法