从 SpringApplication.run 开始
这是你的 SpringBoot ,启动,只需一键。
@SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class,args);
}
}
但这一键背后发生了什么?
挂着嘴边的 IOC 容器何时诞生,天天见的 @Autowired、@Service 如何实现,陪你一路的 Bean,穿林打叶, 始于何处又终于何方?
这次,从 SpringApplication.run 开始。
本文 SpringBoot Version : 2.1.15
SpringBoot
1. 要有光
从SpringApplication.run
下来:
public static ConfigurableApplicationContext run(Class<?> primarySource,String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return (new SpringApplication(sources)).run(args);
}
首先是new SpringApplication(sources)
,构建 SpringApplication 实例,将 ServerApplication.class
存储在 this.primarySources
属性中。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
// 把 ServerApplication.class 设置为属性存储起来
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 设置应用类型
this.webApplicationType = deduceWebApplicationType();
// 设置初始化器,最后会调用这些初始化器
setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
// 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 根据堆栈,推断并设置主类
this.mainApplicationClass = deduceMainApplicationClass();
}
2. run
有了实例,就要 run。这个方法看上去就知道做了一堆工作,一个个说。代码里已标出序号。
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
***
// 1:获取并启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 2:根据 SpringApplicationRunListeners 及参数来准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
configureIgnoreBeanInfo(environment);
// 打字:启动 Spring Boot的时候打印在控制台上的ASCII艺术字
Banner printedBanner = printBanner(environment);
// 3:创建 Spring 容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 4:容器前置处理
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
// 5:刷新容器
refreshContext(context);
// 6:Spring容器后置处理
afterRefresh(context, applicationArguments);
// 7:发出结束执行的事件
listeners.started(context);
// 8:执行Runners
this.callRunners(context, applicationArguments);
stopWatch.stop();
// 9. 返回容器
return context;
}***
}
2.1. 监听器
// 1:获取并启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
首先看第一个,获取并启动监听器。会在 spring.factories 文件中寻找 SpringApplicationRunListener
实现类名,反射构造实例,且持有SpringApplication
的引用。再把实例放到SpringApplicationRunListeners
容器来管理。
最后遍历执行listeners
容器里所有SpringApplicationRunListener
对象的starting
方法,其实就是调用EventPublishingRunListener
的starting()
启动。
这个也不是我们要谈的, 不展开了。
2.2. 环境构建
// 2:根据 SpringApplicationRunListeners 及参数来准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
稍微跟一下
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
***
// 配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布环境已准备事件,这是第二次发布事件
listeners.environmentPrepared(environment);
***
}
listeners.environmentPrepared(environment)
发布事件,哪个监听器获取呢,有个很重要的,叫ConfigFileApplicationListener
,顾名思义, 配置文件。
是的,项目中的 properties 和 yml 配置文件都是其内部类所加载。
场间休息
Banner printedBanner = printBanner(environment);
这个打印了启动时在控制台看到的 Spring Boot
艺术字。
2.3. 创建容器
// 3:创建 Spring 容器
context = createApplicationContext();
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);
}
}
***
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
创建ApplicationContext
, 容器类型根据webApplicationType
判断。比如是SERVLET
时,会通过反射装载对应的字节码,是AnnotationConfigServletWebServerApplicationContext。
需要注意,这里的三个类型全都是继承GenericApplicationContext
。记住,后面要考。
2.4. 事前准备
// 4:容器前置处理
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);
// 注册启动参数bean,将容器指定的参数封装成bean,注入容器; 设置banner
***
// 获取启动类指定的参数,可以是多个
Set<Object> sources = getAllSources()
// 加载启动类,将启动类注入容器
load(context, sources.toArray(new Object[0]));
// 发布容器已加载事件
listeners.contextLoaded(context);
}
看一下getAllSources()
.
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet();
if (!CollectionUtils.isEmpty(this.primarySources)) {
//获取primarySources属性,也就是之前存储的HelloWorldMainApplication.class
allSources.addAll(this.primarySources);
}
***
}
primarySources
还记得不?在实例化SpringApplication
时存了起来。也就是我们的启动类。
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
再顺着listeners.contextLoaded(context)
一路向下,来到load
方法。以注解方式,将启动类 bean 信息加载到 beanDefinitionMap 中,后续该启动类将作为开启自动化配置的入口。
private int load(Class<?> source) {
***
if (isComponent(source)) {
// 以注解方式,将启动类 bean 信息存入 beanDefinitionMap
this.annotatedReader.register(source);
***
}
***
}
2.5. 好戏登场
refreshContext(context);
刷新容器。就像本节标题,前面其实都是 Spring Boot
的工作, Bean 是放在 Spring 的 IOC 容器里,Spring 在哪呢?这就是了。
这调用的是org.springframework.context.support.AbstractApplicationContext
的refresh
。
如果你在网上冲浪,搜索 Spring IOC 初始化
,大抵都是从这开始的。当然,如果不用Spring Boot
,用原生的 Spring、Spring Mvc ,那前面的流程就变了,这里就不说了。
SpringFramework
从前所述,Spring Boot 告一段落,来到 SpringFramework 的 refresh。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备工作,记录时间、标记状态、处理配置文件中的占位符等
prepareRefresh();
// 1.初始化 IOC 容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 2. 设置 BeanFactory 的类加载器,添加BeanPostProcessor后置处理器
prepareBeanFactory(beanFactory);
try {
// 提供子类覆盖的额外处理
postProcessBeanFactory(beanFactory);
// 3. 调用BeanFactory后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean后置处理器BeanPostProcessor 的实现类
registerBeanPostProcessors(beanFactory);
// 初始化当前 ApplicationContext 的 MessageSource,国际化处理
initMessageSource();
// 初始化当前 ApplicationContext 的事件广播器
initApplicationEventMulticaster();
// 模板方法(钩子),供子类实现,初始化一些特殊的 Bean
onRefresh();
// 注册事件监听器,监听器需实现 ApplicationListener 接口。
registerListeners();
// 4. 初始化所有(non-lazy-init)singleton beans
finishBeanFactoryInitialization(beanFactory);
// 广播事件,ApplicationContext 初始化完成
finishRefresh();
}
catch (BeansException ex) {
// 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
destroyBeans();
***
}
finally {
***
}
}
}
又是很多工作,但这里只重点关注部分内容。代码中也加上了序号。
1. 初始化 IOC 容器
// 1.初始化 IOC 容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
在没Spring Boot
的岁月, 这一步会做很多重要工作,比如将 xml
配置中的 bean
配置信息,也就是Resource
转成Document
再转成BeanDefinition
, 接着注册到 IOC 容器 BeanFactory。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
有两个实现类,大多数文章会告诉你,下一步是AbstractRefreshableApplicationContext
。
protected final void refreshBeanFactory() throws BeansException {
***
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
***
loadBeanDefinitions(beanFactory);
}
***
}
接着会有不同的实现类,一般是 XmlWebApplicationContext
, 之后解析配置等等。
没错。在使用 Spring MVC,xml 配置时,当启动 tomcat ,一路往下,初始化 Spring 应用上下文创建的是WebApplicationContext
。(详见 ContextLoaderListener 父类 ContextLoader)
最终实例化的实现类默认值在ContextLoader.properties
中配置:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
所以这种说法是正确的。
不过现在是基于 SpringBoot 的注解方式。难道是从 XmlWebApplicationContext
换成了图中的AnnotationConfigWebApplicationContext
,那它怎么知道动态用了注解呢?
SpringBoot 版本
后退一步,回到refreshBeanFactory()
,看看另一个实现类GenericApplicationContext
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true))
***
this.beanFactory.setSerializationId(getId());
}
这里几乎什么都没做,看起来像是没用的。但SpringBoot
项目就是会走到这里,在第一部分SpringBoot.容器构建
那里说过:
需要注意,这里的三个类型全都是继承
GenericApplicationContext
。记住,后面要考。
所以其实创建ApplicationContext
时就选定了类型。这样的话,BeanDefinition
在哪加载的?
2. 准备bean 容器
带着上一个问题,往下看。
// 2. 设置 BeanFactory 的类加载器,添加BeanPostProcessor后置处理器
prepareBeanFactory(beanFactory);
如果是原始的 Spring MVC 模式,上一步把 xml 配置的 bean 注册后,这里会手动注册下特殊bean。
也会对 BeanFactory 各种功能进行填充,如常用注解 @Autowired、 @Qualifier 等,添加后置处理器。
3. BeanFactory 处理器
// 3. 调用BeanFactory后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
调用BeanFactoryPostProcessor
各实现类的 postProcessBeanFactory()
回调方法。这个在SpringBoot
里就有点重要了。
因为它实现了将 annotation 的 Bean 配置转化为 BeanDefinition ,以及注册。
是的,本章第 1 小结, SpringMvc 时期obtainFreshBeanFactory()
的部分工作到了这里。刚才遗留的问题,在这听到了答案。
再一路到PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
, 有
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
这儿就是 BeanDefinition 的注册入口,注册 BeanDefinition 的后置处理器。
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
其实现类是ConfigurationClassPostProcessor
, 再往下到processConfigBeanDefinitions
。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
for (String beanName : candidateNames) {
// 默认仅有主类被添加
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
// 解析被 @Configuration 注解的类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory,
this.problemReporter,this.environment,this.resourceLoader,
this.componentScanBeanNameGenerator,registry);
do {
// 解析的核心方法
parser.parse(candidates);
parser.validate();
}
}
解析
看这个解析的核心方法
parser.parse(candidates);
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
// 主类的解析从这开始
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
}
protected final void parse(AnnotationMetadata metadata, String beanName) {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
主类被作为 BeanDefinition 加载到 BeanFactory 中,被 ConfigurationClassParser 解析器所解析。
protected void processConfigurationClass(ConfigurationClass configClass) {
// 从 main方法所在主类开始,递归解析
SourceClass sourceClass = asSourceClass(configClass);
do {
// 解析单个配置类
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
}
doProcessConfigurationClass
负责解析的主要工作,会处理一个非常或者说必用的注解@ComponentScan
,根据该注解信息得到扫描路径,开始扫描。
同时,对扫描出来的 Bean 又会返回个新的 sourceClass 用于继续解析。新 sourceClass 是上一个 sourceClass 的父类。所以该解析过程是个递归,主类开始,逐层向上。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) {
// 处理 @ComponentScan 注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
for (AnnotationAttributes componentScan : componentScans) {
Set<BeanDefinitionHolder> scannedBeanDefinitions =
// 处理扫描出来bean
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
}}}
}
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
***
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
现在,获得了扫描器和扫描路径, 调用doScan
.
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 1. 扫描获取 BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
***
// 2. 注册 BeanDefinition 到 BeanFactory
registerBeanDefinition(definitionHolder, this.registry);
}
}
return beanDefinitions;
}
扫描
findCandidateComponents
方法将会根据扫描路径获取非常重要的 BeanDefinition
。
关于BeanDefinition,随口一提 : 在容器本身内,bean 定义表示为 BeanDefinition 对象。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
***
return scanCandidateComponents(basePackage);
}
好了,现在路径知道了,也开始扫描了,但哪个可爱的 Class 有幸被转化为 BeanDefinition 呢?
是的,肯定有一个判断。
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
for (Resource resource : resources) {
if (resource.isReadable()) {
// 类的元数据
MetadataReader metadataReader = this.metadataReaderFactory.
getMetadataReader(resource);
// 判断是否满足条件
if (isCandidateComponent(metadataReader)) {
***
}
protected boolean isCandidateComponent(MetadataReader metadataReader) {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
在判断方法isCandidateComponent
里,会进行很多的过滤检查处理。
其中ClassPathScanningCandidateComponentProvider#registerDefaultFilters
方法,会给includeFilters
添加默认的AnnotationTypeFilter
,负责处理 @Component,@ManagedBean等注解。
最终的调用链是:
AnnotationTypeFilter#match -> matchSelf
.
protected boolean matchSelf(MetadataReader metadataReader) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
这里会获取 Class 的注解元数据,检查是否有对应 annotationType, 简单来说,就是检查有没有那些我们常用的 @Service
、@Repository
了,并检查嵌套注解是否有对应的 annotationType。
注册
回到doScan
,扫描出来的 BeanDefinition 将会调用 registerBeanDefinition 注册。
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder,BeanDefinitionRegistry registry) {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
***
}
这里的 registry,默认实现类是 DefaultListableBeanFactory 。
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
public void registerBeanDefinition(String beanName,BeanDefinition beanDefinition) {
***
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
*** }
} ***
}
}
最终,也就是将 BeanDefinition 添加到一个 key-value 的集合当中,这样就完成了注册工作。
4. 实例化Bean
前面我们得到了充满 BeanDefinition 的 BeanFactory,中间一些流程先忽略。来到最重要的地方,实例化 Bean。
// 4. 初始化所有(non-lazy-init)singleton beans
finishBeanFactoryInitialization(beanFactory);
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
***
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
***
}
getBean
, 该方法的实现位于AbstractBeanFactory.doGetBean
protected <T> T doGetBean(
final String name,
@Nullable final Class<T> requiredType,
@Nullable final Object[] args,
boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 获取已注册的单例 Bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 根据 name 和 beanName 判断应该返回 factoryBean 还是 bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// *** 判断循环依赖、类型检查、获取父 BeanFactory
***
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 初始化依赖的Bean(@DependsOn)
***
// 创建单例
if (mbd.isSingleton()) {
// 回调创建
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建 Bean
return createBean(beanName, mbd, args);
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// 如果是 prototype scope 的
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
// 创建Bean
prototypeInstance = createBean(beanName, mbd, args);
} ***
} else {
// 既不是单例Bean,也不是prototype,获取其 Scope,委托给相应的实现类来处理
}
} ***
}
// 类型检查
return (T) bean;
}
循环依赖
// 尝试获取Bean
Object sharedInstance = getSingleton(beanName);
根据 beanName 尝试从 singletonObjects 缓存中获取单例Bean,获取不到则再尝试从earlySingletonObjects、singletonFactories 从获取。同时这也是Spring 解决循环依赖的关键。
创建Bean
createBean(beanName, mbd, args);
缓存中获取不到,就创建,
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
它会调用doCreateBean()
。在这停顿,打这开始,又是一个热门问题:Spring Bean 生命周期
。
Spring Bean 生命周期
如图,谈到 Bean 生命周期,大概都是这张图的内容。对应的其实就是上文的doCreateBean
。
protected Object doCreateBean(
final String beanName, final RootBeanDefinition mbd,
final @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
***
if (instanceWrapper == null) {
// 1. 说明不是 FactoryBean,实例化 Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// *** 解决循环依赖等
***
Object exposedObject = bean;
try {
// 2. 前面实例化后,属性装配,自动注入
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化。init-method、InitializingBean、BeanPostProcessor等,各种回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
} ***
try {
// 4. 销毁-注册回调接口
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
return exposedObject;
}
这个方法也有点长,而且每个分支跟下去都更长,这里截取部分且不进行过多深究。前面图中看着挺多,但实际可以分为几大步,代码中已标识。
1. 实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
***
// 校验类访问权限
if (mbd.getFactoryMethodName() != null) {
// 工厂方法实例化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 非第一次创建,如prototype 。判断用无参构造,还是构造函数依赖注入来实例化
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
// 构造函数依赖注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 无参构造函数
return instantiateBean(beanName, mbd);
}
}
// 是否采用有参构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 构造函数依赖注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// (默认) 调用无参构造函数
return instantiateBean(beanName, mbd);
}
默认会采用无参构造函数
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
// 实例化
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
// 实例化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
// 包装一下,返回
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
} ***
}
可以看到,关键在于getInstantiationStrategy().instantiate(mbd, beanName, parent)
在进行实际的实例化。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果不存在需要被重写的方法,就不用cglib,使用反射
if (!bd.hasMethodOverrides()) {
***
// 通过构造方法实例化
return BeanUtils.instantiateClass(constructorToUse);
} else {
// 存在方法覆写,通过cglib生成
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
到这里,Bean 初始化完成了。
2. 属性装配
populateBean(beanName, mbd, instanceWrapper);
属性装配,也就是注入。对已实例化好的 bean 的属性进行赋值, 如果 bean 中关联着其他 bean,也会帮建立 bean 间的关系。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
***
// bean 实例的所有属性。获取待注入的property,配置文件中的<property>也将在这里被处理
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
***
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 按照名字获取属性
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 按照类型获取属性
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
***
if (hasInstAwareBpps) {
***
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
***
if (pvsToUse == null) {
***
// 后置处理器处理@Autowired @Resource等注解
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
***
}
pvs = pvsToUse;
}}}
// 注入 <property> 属性
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
这里有个很重要的地方,处理 Bean 间的依赖注入,说白点就是 @Autowored 注解。
ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
在对 Bean 赋值时,会先去处理该 Bean 中注入的 Bean,因此对于相互注入的 Bean 来说不用担心 Bean 的生成先后顺序问题。
3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
属性注入完成后,这一步就是处理各种回调了。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 1. 如bean实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 接口,回调
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 2. 执行BeanPostProcessor预初始化方法:postProcessBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 3. 处理自定义的init-method,如实现了InitializingBean接口执行afterPropertiesSet()
invokeInitMethods(beanName, wrappedBean, mbd);
}***
if (mbd == null || !mbd.isSynthetic()) {
// 执行BeanPostProcessor初始化后回调 postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
可以看到,在Bean 生命周期
图里各种初始化操作都是在这里完成的。
- 执行一些Aware方法,比如 BeanNameAware的setBeanName(beanName)
- 执行 BeanPostProcessor 预初始化方法,例如,@PostConstruct 注解的方法。
- 执行 afterPropertiesSet() 方法与自定义的 inti-method
- 执行 BeanPostProcessor 初始化后方法
4. 销毁
最后就是销毁。这个销毁当然不是指对象被 GC 的销毁。
registerDisposableBeanIfNecessary(beanName, bean, mbd);
register
, 这里是在进行销毁逻辑的注册,在销毁时会执行。
比如使用@Bean(destroyMethod = "***")
。
SpringBoot 回来啦
好了,SpringFramework 的工作结束了,还记得开头的SpringApplication.run
吗, 还没执行完呢。
// 5:刷新容器
refreshContext(context);
// 6:Spring容器后置处理
afterRefresh(context, applicationArguments);
// 7:发出结束执行的事件
listeners.started(context);
// 8:执行Runners
this.callRunners(context, applicationArguments);
stopWatch.stop();
// 9. 返回容器
return context;
现在 步骤5 容器已经刷新了,之后还有:
(6). afterRefresh
扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。
(7).listeners.started
发布结束执行事件
(8). this.callRunners
区分ApplicationRunner
和CommandLineRunner
, 执行run
方法。
可以自定义 ApplicationRunner 或 CommandLineRunner,实现 run 方法,注入到容器中, 在SpringBoot 启动后,就会执行所有的 runner 的 run 方法。
(9). return context
终于 run 完了,返回容器。
总结
从 SpringApplication.run
开始,我们所看到的简单的一行代码背后却有这么多弯弯绕。
以上很多地方只是浅尝辄止或一笔带过,主要谈了 IOC 和 Bean有关的主流程,尚有很多比如何解决循环依赖、为何 @Transactional 同类调用会失效等等一些称得上常见的问题,都可以在这里找到答案。
本文主要为了对 SpringBoot 乃至 SpringFramework 的启动流程有个基本的认识,但一叶知秋透过这些不难看出很多巧妙的设计和思路。
话说回来,有时会想,若非热爱和 interview,读源码或深究原理用处何在?
转念又一想,提笔成文是基于大量阅读乃至背诵的。但编码一如识了字、懂些寻常语法便仗键天涯,虽二者不可一概,但总有共通之处。
俗话说,“学而不思则罔”,对比文字逻辑性更强的代码,很难初窥门径便读名家之作。所以我觉得,目的性是要浓厚一些,无论是出发点还是阅读姿势。
俗话说,“学而不思则罔”,比文字逻辑性更强的代码,很难初窥门径便读大师之作。所以我觉得目的性是要热烈一些,不论是出发点还是阅读姿势。一为解决问题而究其根源,二为习名家之法长己身之技,三为做些大家都不想做但又想做的事情。