Spring 如何创建 bean 对象?
前情回顾
前文「Spring 如何从 IoC 容器中获取对象?」从整体上分析了如何从 Spring IoC 容器获取一个 bean 对象。该逻辑由 AbstractBeanFactory#doGetBean 方法实现,主要流程如下:
本文进一步深入细节,主要分析如何创建 singleton(单例)类型的对象。
如何创建单例对象?
从流程图可以看出,当获取一个 bean 对象时,Spring 会首先尝试从缓存中获取单例对象。
值得注意是的:
只有对象是单例的场景,即 scope 为 singleton 时才会缓存对象。 这里其实涉及到了所谓的「三级缓存」,为了更容易理解三级缓存,本文先研究这个 bean 对象是什么时候放入缓存的,后面再研究三级缓存。
既然能取,必然有地方把 bean 对象存入了缓存,那缓存中的数据是从哪里来的呢?
下面主要分析单例对象是如何创建、并放入缓存中的。
该逻辑在 AbstractBeanFactory#doGetBean 方法中,主要代码如下(保留了创建单例 bean 对象的代码,其他部分暂时忽略):
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
// ...
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// 从缓存中获取单例 bean 对象
Object sharedInstance = getSingleton(beanName);
// 缓存中不存在 bean 对象
else {
// ...
try {
// 获取 BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 获取依赖的 bean 对象
// 若创建一个 bean 对象时依赖其他对象,则先创建被依赖对象
// ...
// 创建 scope 为 singleton(单例)的对象
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ...
}
});
// 处理 FactoryBean 的场景
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建 scope 为 prototype 的对象
else if (mbd.isPrototype()) {
// ...
}
// 创建其他类型对象
else {
// ...
}
}
catch (BeansException ex) {
// ...
}
}
// 类型检查
return (T) bean;
}
}
其实就是这个 DefaultSingletonBeanRegistry#getSingleton 方法,代码如下:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 单例 bean 对象缓存(beanName, bean)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 先从缓存中获取 bean 对象
Object singletonObject = this.singletonObjects.get(beanName);
// 缓存中不存在时再去创建
if (singletonObject == null) {
// ...
// 创建单例对象前
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 创建单例对象
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
// catch ...
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 创建单例对象后
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 将对象添加到缓存
addSingleton(beanName, singletonObject);
}
}
// 缓存中有的话直接返回
return singletonObject;
}
}
}
getSingleton 方法会先从缓存 singletonObjects(其实就是一个 Map)中获取 bean 对象,如果缓存有就直接返回,否则再去创建。创建成功后,会把该对象存入缓存。
创建的逻辑在哪呢?
看代码是通过 ObjectFactory#getObject 方法来创建的,ObjectFactory 是一个函数式接口:
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
这个方法的实现是什么呢?退回上一层,即 getBean 方法,看这里:
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建 bean 对象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ...
}
});
这里用到了 Lambda 表达式,将如下表达式作为参数:
() -> {
try {
// 创建 bean 对象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ...
}
}
创建 bean 对象的逻辑就在这个 createBean 方法中,它在 AbstractAutowireCapableBeanFactory 类中:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
// catch ...
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 这里可能返回代理对象
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
// catch ...
try {
// 创建 bean 对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
// catch ...
}
}
值得注意的是,resolveBeforeInstantiation 方法其实是跟 AOP 实现相关的,可能在这里生成代理对象就返回了。由于现在主要分析 IoC 的流程,因此这里暂时略过,有兴趣的朋友们可以自行研究。
这里继续沿着主线逻辑走。
创建 bean 对象是在 doCreateBean 方法中实现的,如下:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// 1. 实例化 bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
// catch ...
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 2. 填充属性
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// catch ...
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// ...
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
// catch ...
return exposedObject;
}
}
注意:Instantiate 和 Initialize 虽然看起来有点像,但它俩不是一回事,前者是“实例化”,后者是“初始化”。
这个方法看起来有点长,但最主要的事情只有三件:
创建 bean 对象:createBeanInstance 方法 填充属性:populateBean 方法 初始化 bean:initializeBean 方法
这几个方法内部其实都有一大堆堆堆堆堆……的代码,再对照一下前面给出的整体流程图:
就是这样。
本文在前文整体分析的基础上又进一步细化,先到这里吧,后面再继续分析~
小结
如何从 Spring IoC 容器中获取 bean 对象?前文对此进行了整体流程的分析。
本文在前文的基础上又进一步细化,主要从整体上探讨了 Spring 如何创建单例的 bean 对象,整体上分为三个步骤:
创建 bean 对象 填充 bean 属性 初始化 bean 对象
至于这三个步骤具体又做了什么,且听下回分解。
有点「自顶向下」的感觉了,这就是「金字塔原理」?