Spring版本:
<version>5.2.1.RELEASE</version>
上一篇:15-Spring源码解析之refresh(8)——【finishBeanFactoryInitialization】
本篇我们来解决上一篇中遗留的问题,即finishBeanFactoryInitialization
中是如何通过getBean
来创建Bean
实例的。
为了更好更清晰的理解Bean
的生命周期。我首先给出一个很简单的例子。这个例子包含:
- 实体类(
User
)- 实现了
InitializingBean
接口,实现这个接口的目的是更好的看afterPropertiesSet
方法的执行时机 - 这个类不包含
@Autowired
、@Value
、@Resource
等注解,因为这些注解需要在Bean
创建的时候进行解析,为了更好的理解Bean
生命周期的整体逻辑,这里先不额外增加以上注解,后续文章会讲解这些注解在Bean
创建中的哪一步起作用。
- 实现了
- 自定义
BeanPostProcessor
类MyBeanPostProcessor
。- 实现了
BeanPostProcessor
接口,重写postProcessBeforeInitialization
方法和postProcessAfterInitialization
方法。 - 例子中包含这个接口的目的是为了看
postProcessBeforeInitialization
和postProcessAfterInitialization
的执行时机
- 实现了
- 配置类(
MainConfig
)- 这个类只有两个注解:
@Configuration
:标注当前类是配置类的注解,用于标注Spring
首先解析的类@ComponentScan
:包扫描注解,用于扫描 实现类User
和自定义类MyBeanPostProcessor
- 这个类只有两个注解:
下面给出这个例子的源代码
一、例子
包结构
1. 实体类User
package com.spring.csdn;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class User implements InitializingBean {
private String name;
public User() {
System.out.println("User类的 【无参构造器】");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("User类的 【afterPropertiesSet】 方法");
}
}
2. 自定义BeanPostProcessor
类MyBeanPostProcessor
package com.spring.postprocessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization -> 当前类为:" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization -> " + beanName);
return bean;
}
}
3. 配置类MainConfig
package com.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.spring")
public class MainConfig {
}
4. 测试类Test
package com.spring;
import com.spring.config.MainConfig;
import com.spring.csdn.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
User user = applicationContext.getBean(User.class);
}
}
5. 输出结果
我们知道BeanPostProcessor
会拦截每个Bean
的创建,然后在每个Bean
的初始化方法执行前执行postProcessBeforeInitialization
,在初始化方法执行后执行postProcessAfterInitialization
。所以可以看到输出结果中,回对Spring
中的每一个类都执行了postProcessBeforeInitialization
和postProcessAfterInitialization
方法。 而有关构造器和afterPropertiesSet
的执行时机,我们下面来慢慢分析。
二、getBean
获取Bean
实例
2.1 当前beanFactory
中的值
上一篇文章,我们讲到了finishBeanFactoryInitialization
方法在最后会调用getBean
方法获取Bean
实例。那么接下我们就具体看一下它是如何获取到Bean
实例的。
在看这个方法之前,我们有必要看一下当前BeanDefinition
的情况,以及beanFactory
已经创建Bean
的情况。
beanDefintion
的情况:
beanFactory
的registeredSingletons
属性保存已经创建的Bean
的情况。
从上面图片可以看出当前容器中有12个Bean
已经被创建了,其中只有registeredSingletons[9]
是我们自己的Bean
,其他的都是Spring
内部自己创建的Bean
,我们暂时不考虑Spring
内部自己创建的Bean
的作用(因为涉及的内容太多了,有一些已经在前面的文章中讲过了)。
接下来是真正到了看一下finishBeanFactoryInitialization
是如何获取到Bean
实例的时候了。
2.2 getBean
方法
我们以获取User
类为例子进行讲解。接着上篇文章,上篇文章在最后finishBeanFactoryInitialization
方法调用preInstantiateSingletons
方法,preInstantiateSingletons
方法在每一个for
循环里面调用getBean
方法。现在我们就进入getBean
方法。
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
它调用的是AbstractBeanFactory
类的getBean
方法,我们可以看一下AbstractBeanFactory
类实际上有4个getBean
方法。
注意,在初始化容器的时候,调用的是getBean(String)
方法。但是这里还需要注意的另外一个事情是:虽然AbstractBeanFactory
类有4个getBean
方法,但是每个方法都调用了doGetBean
方法,且AbstractBeanFactory
的doGetBean
方法只有一个。
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
2.3 doGetBean
高能预警:这个doGetBean
做了好多事情,而且代码有点长。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// ------------------------------------------【功能一】--2.3.1详细介绍----------------------------------------
// ------------------------------------------转换对应 beanName----------------------------------------
final String beanName = transformedBeanName(name);
Object bean;
// ------------------------------------------【功能二】--2.3.2详细介绍----------------------------------------
// ------------------------------------------尝试从缓存中加载单例----------------------------------------
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
// ------------------------------------------根据【功能二】返回的结果进行------------------------------------------
// ------------------------------------------【功能三】------------------------------------------
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// -------------------------------------------------------------------------
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// ------------------------------------------根据【功能二】返回的结果进行------------------------------------------
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// ------------------------------------------【功能三】------------------------------------------
// 只有singleton情况下才会尝试解决循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// ------------------------------------------【功能四】------------------------------------------
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// ------------------------------------------【功能五】---2.3.3详细介绍---------------------------------------
if (!typeCheckOnly) {
// 将创建的Bean加入到beanFactory的alreadyCreated属性中
markBeanAsCreated(beanName);
}
// ------------------------------------------【功能六】------------------------------------------
try {
// BeanDfinitiaon定义公共的抽象累是AbstractBeanDefinition。
// 普通的Bean在Spring注册BeanDefinition的时候,实例化出来的是GenericBeanDefinition
// Spring内置的Bean在注册BeanDefinition的时候,实例化出来的是RootBeanDefinition,
// 这时候,就要用getMergedLocalBeanDefinition将所有的BeanDefinition都转换为RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// ------------------------------------------【功能七】--寻找依赖----------------------------------------
// Guarantee initialization of beans that the current bean depends on.
// 若当前Bean有依赖,则先创建依赖Bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// ------------------------------------------【功能八】核心方法:下一篇文章重点介绍---------------------------------------
// 针对不同的scope进行bean的创建
// ---------------------------【Singleton】类型---------------------------
if (mbd.isSingleton()) {
// 核心方法:下一篇文章重点介绍!!!
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// ---------------------------【Prototype】类型---------------------------
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// ---------------------------【其他Scope】类型---------------------------
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// ------------------------------------------【功能九】------------------------------------------
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
在本文的最后会总结doGetBean
方法的功能,我们先一步步拆解这里面的每个功能所作的事情。
2.3.1 【功能一】 transformedBeanName
根据这个方法的名字可以知道,该方法的作用是:转换对于的beanName
,那这里为什么要转换呢?
实际上,在创建Spring
容器的过程中是不需要转换beanName
的,因此在创建Spring
容器的时候,该方法还是将我们原来的beanName
返回。
但是当我们在获取Spring
容器之后,自己在程序中调用getBean
方法的时候,就可能会用到这个方法。比如我们在程序中写:
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
PeopleFactory peopleFactory = (PeopleFactory)applicationContext.getBean("&people");
}
}
在写applicationContext.getBean();
的时候,我们会给getBean
方法传入String
类型的参数。当获取的bean
是一个实现了FactoryBean
接口的类的时候,transformedBeanName
方法就起作用了。
下面看一下transformedBeanName
方法的实现:
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
从上面方法可以看出,transformedBeanName
首先调用了BeanFactoryUtils.transformedBeanName
。
// BeanFactoryUtils类的transformedBeanName方法
// String FACTORY_BEAN_PREFIX = "&";
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
可以看出,先去除FactoryBean
的修饰符&
,即如果name = &people
,那么会首先除去&
而使name = people
。
返回后transformedBeanName
方法又调用canonicalName
方法
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
2.3.2 【功能二】getSingleton
从缓存中加载单例
单例在Spring
的同一个容器中只会被创建一次,创建完成后,会把创建好的Bean
加入到缓存中。
因此Spring
每次在getSingleton
获取Bean
的时候会先尝试从缓存中加载,如果加载不成功再次从singletonFactories
中加载。因为在创建单例Bean
的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring
中创建Bean
的时候,执行createBean
-> doCreateBean
-> createBeanInstance
之后,就会将刚实例化好还没有进行属性注入(populate
)的Bean
加入到缓存中。一旦下一个Bean
创建的时候需要依赖上一个Bean
,则直接使用ObjectFactory
。
我们先来看看getSingleton
方法所在的类:
这个类有3个getSingleton
方法。而我们从缓存中加载单例是调用的getSingleton(beanName)
方法。
下面我们来具体看一下Spring
是怎么从缓存中加载单例的。
public Object getSingleton(String beanName) {
// 第二个参数设置为true表示:允许早期依赖
return getSingleton(beanName, true);
}
它又调用了getSingleton(beanName, true)
方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 检查缓存singletonObjects中是否存在beanName的实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 如果此Bean正在加载则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
singletonObjects
:用于保存beanName
和bean
实例之间的关系singletonFactories
:用于保存beanName
和创建bean
工厂之间的关系earlySingletonObjects
:用于保存beanName
和bean
实例之间的关系,与singletonObjects
不同之处在于:当一个单利bean
被放到这里面之后,那么当bean
还在创建过程种,就可以通过getBean
方法获取到了,目的是用来检查循环依赖。registeredSingletons
:用于保存当前所有已经创建的bean
。
2.3.3 【功能五】markBeanAsCreated
走到这一步说明缓存中没有beanName
的单例,所以下面要开始创建Bean
了,那么在创建之前,我们需要将即将创建的Bean
加入到beanFactory
的alreadyCreated
属性中。
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {
// 将RootBeanDefinition的re-merge属性设置为true
// 因为我们要创建这个bean了,所以以放在创建过程中它的metadata发生变化
clearMergedBeanDefinition(beanName);
this.alreadyCreated.add(beanName);
}
}
}
}
三、总结
doGetBean
方法的工作流程:
doGetBean
方法是为了获取bean
,首先从缓存中获取,缓存中没有就开始创建Bean
,而本篇文章只讲到了从缓存中获取,下一篇文章讲解重头戏,
-
getSingleton -> createBean
来创建Bean
。