实例化Bean
Spring 实例化bean的时机有两个:
- IOC容器启动时候;
- 真正调用的时候;
如果bean声明为scope=singleton
且lazy-init=false
,则容器启动时候就实例化该bean(Spring 默认就是此行为)。否则在调用时候再进行实例化。
IOC容器启动时实例化
回到AbstractApplicationContext.refresh()
,包含了如下代码,即bean实例化的第一种情况,容器启动时,直接初始化Bean:
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
finishBeanFactoryInitialization()包含如下代码,初始化非延迟加载的单例Bean:
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
单例Bean的实际初始化:
public void preInstantiateSingletons() throws BeansException {
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
getBean(beanName);
}
}
通过beanName从上一个大的步骤生成的BeanDefinition集合中获取BeanDefinition。
通过BeanDefinition获取bean。
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
doGetBean中处理的逻辑很多,为了减少干扰,下面只显示了创建bean的函数调用栈。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//创建bean
createBean(beanName, mbd, args);
}
创建bean。
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// 实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//实例化bean
return instantiateBean(beanName, mbd);
}
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
//调用实例化策略进行实例化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName,
}
判断哪种动态代理方式实例化bean。
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
//使用JDK动态代理
if (bd.getMethodOverrides().isEmpty()) {
return BeanUtils.instantiateClass(constructorToUse);
}
else {
//使用CGLIB动态代理
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
不管哪种方式最终都是通过反射的形式完成了bean的实例化。
public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
}
核心步骤:
- 容器启动时实例化,会遍历
单例+非延时加载
的所有BeanName列表;- 通过BeanName获取对应的BeanDefinition;
- 使用BeanDefinition创建Bean的instanceWrapper,基于反射实现的(反射实现的动态代理,有JDK的动态代理或者CGILIB);
Bean实例化
继续回到doGetBean
,
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//获取beanName
final String beanName = transformedBeanName(name);
Object bean;
// 先检查该bean是否为单例且容器中是否已经存在例化的单例类.
Object sharedInstance = getSingleton(beanName);
//如果已存在该bean的单例类
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 获取父BeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
//先判断该容器中是否注册了此bean,如果有则在该容器实例化bean,否则再到父容器实例化bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 如果父容器有该bean,则调用父beanFactory的方法获得该bean
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//如果该bean有依赖bean,先实递归例化依赖bean。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
registerDependentBean(dep, beanName);
getBean(dep);
}
}
//如果scope为Singleton执行此逻辑
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// scope是prototype类型的
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//如果scope为Request,Session,GolbalSession执行此逻辑
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
}
}
return (T) bean;
}
上面方法中首先调用getSingleton(beanName)
方法来获取单例bean,如果获取到则直接返回该bean。方法调用栈如下:
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从singletonObjects中获取bean。
Object singletonObject = this.singletonObjects.get(beanName);
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
getSingleton方法先从singletonObjects
属性中获取bean 对象,如果不为空则返回该对象,否则返回null。
那 singletonObjects保存的是什么?什么时候保存的呢?
回到doGetBean()
函数继续分析。如果singletonObjects没有该bean的对象,进入到创建bean的逻辑。处理逻辑如下:
//获取父beanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果该容器中没有注册该bean,且父容器不为空,则去父容器中获取bean后返回
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
下面是判断容器中有没有注册bean的逻辑,此处beanDefinitionMap
即为XMLBeanDefinitionReader
处理xml配置后,注册BeanDefinition的位置。在注册bean的流程里已经说过所有的bean信息都会保存到该变量中。
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
如果该容器中已经注册过bean,继续往下走。
先获取该bean的依赖bean,如果存在子依赖bean,则先递归获取相应的依赖bean。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
registerDependentBean(dep, beanName);
getBean(dep);
}
}
依赖bean创建完成后,接下来就是创建自身bean实例了。
获取bean实例的处理逻辑有三种,即Singleton、Prototype、其它(request、session、global session),下面一一说明。
获取单例singleton实例
如果bean是单例模式,执行此逻辑。
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
//创建bean回调
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
获取单例bean,如果已经有该bean的对象直接返回。如果没有则创建单例bean对象,并添加到容器的singletonObjects
Map中,以后直接从singletonObjects直接获取bean。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
//如果singletonObjects中没有该bean
if (singletonObject == null) {
//回调参数传进来的ObjectFactory的getObject方法,即调用createBean方法创建bean实例
singletonObject = singletonFactory.getObject();
//置新创建单例bean标志位为true。
newSingleton = true;
if (newSingleton) {
//如果是新创建bean,注册新生成bean对象
addSingleton(beanName, singletonObject);
}
}
//返回获取的单例bean
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
把新生成的单例bean加入到类型为MAP 的singletonObjects
属性中,这也就是前面singletonObjects()方法中获取单例bean时从此Map中获取的原因。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//把新生成bean对象加入到singletonObjects属性中。
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.registeredSingletons.add(beanName);
}
}
获取Prototype实例
Prototype是每次获取该bean时候都新建一个bean,因此逻辑比较简单,直接创建一个bean后返回。
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
//创建bean
prototypeInstance = createBean(beanName, mbd, args);
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
获取request、session、global session的实例
else {
//获取该bean的scope
String scopeName = mbd.getScope();
//获取相应scope
final Scope scope = this.scopes.get(scopeName);
//获取相应scope的实例化对象
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return createBean(beanName, mbd, args);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
从相应scope获取对象实例。每个scope均需要实现get(String name, ObjectFactory<?> objectFactory)
方法来获取特定scope下面的Bean instance。
public Object get(String name, ObjectFactory<?> objectFactory) {
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
//先从指定scope中获取bean实例,如果没有则新建,如果已经有直接返回
Object scopedObject = attributes.getAttribute(name, getScope());
if (scopedObject == null) {
//回调函数调用createBean创建实例
scopedObject = objectFactory.getObject();
//创建实例后保存到相应scope中
attributes.setAttribute(name, scopedObject, getScope());
}
}
return scopedObject;
}
判断scope,获取实例函数逻辑。从RequestAttributes
中获取beanName属性的对象,如果获取成功则并表示对象存在,无需创建,否则需要createBean。
如果是RequestScope,那么从Requet中获取/设置;如果是global scope那么从Application中获取实例,如果是session scope 那么从session中获取/设置。
RequestAttributes
中获取beanName属性的对象逻辑:
public Object getAttribute(String name, int scope) {
//scope是request时
if (scope == SCOPE_REQUEST) {
//从request中获取实例
return this.request.getAttribute(name);
}
else {
PortletSession session = getSession(false);
if (session != null) {
//scope是globalSession时,从application中获取实例
if (scope == SCOPE_GLOBAL_SESSION) {
//从globalSession中获取实例
Object value = session.getAttribute(name, PortletSession.APPLICATION_SCOPE);
return value;
}
else {
//从session中获取实例
Object value = session.getAttribute(name);
return value;
}
}
return null;
}
}
在相应scope中设置实例函数逻辑:
public void setAttribute(String name, Object value, int scope) {
if (scope == SCOPE_REQUEST) {
this.request.setAttribute(name, value);
}
else {
PortletSession session = getSession(true);
if (scope == SCOPE_GLOBAL_SESSION) {
session.setAttribute(name, value, PortletSession.APPLICATION_SCOPE);
}
else {
session.setAttribute(name, value);
}
}
}
怎么实现的依赖注入呢?
在getBean()
方法获取各种scope类型的bean过程中,如果需要创建Bean,那么需要调用doCreateBean()
方法,该方法创建Bean分为2步:
- 通过BeanDefinition创建BeanWrapper包装实例,包装了bean实例(通过反射创建);
- 初始化bean,核心方法为
populateBean()
,设置bean的属性和完成依赖注入。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
// Initialize the bean instance.
Object exposedObject = bean;
//初始化bean
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
// 注册bean的disposable方法。即bean的销毁方法
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
populateBean中包括了如下的内容:
//属性依赖分析
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
//最后设置属性依赖
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
从BeanDefinition 中获取属性配置,并切自动注入属性,自动注入的方法有autowireByName
或autowireByType
。
autowireByName的实现如下:
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
}
}
}
}
通过beanName获取依赖的Bean列表。
然后继续运行populateBean,
总结
在doCreateBean时,调用populateBean
方法,解析Bean的依赖Beans,并通过applyPropertyValues
注入。
怎么解决循环依赖的?
spring bean初始化的核心过程:
createBeanInstance
:实例化beanpopulateBean
:设置bean的属性initializeBean
:调用bean的init方法
那么可能发生循环依赖的阶段在createBeanInstance,构造注入的时候和populateBean设值注入的时候,那么要解决循环引用也应该从初始化过程着手。
对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。
** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
三级缓存分别对应:
singletonObjects
:单例对象的cacheearlySingletonObjects
: 提前暴光的单例对象的CachesingletonFactories
: 单例对象工厂的cache
我们在创建bean的时候,首先想到的是从cache中获取这个单例的bean,这个缓存就是singletonObjects
。从缓存singletonObjects
中获取Bean的主要方法就就是:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从一级缓存singletonObjects中获取Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 未从缓存中获取到Bean,切当前对象正在创建切
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;
}
上面的代码需要解释两个参数:
isSingletonCurrentlyInCreation()
:判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)allowEarlyReference
: 是否允许从singletonFactories中通过getObject拿到对象
分析getSingleton()
的整个过程:
- Spring首先从一级缓存
singletonObjects
中获取; - 如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取;
- 如果还是获取不到且允许
singletonFactories
通过getObject()
获取,就从三级缓存singletonFactory.getObject()
(三级缓存)获取,如果获取到了则:
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
从singletonFactories中移除,并放入earlySingletonObjects
中。其实也就是从三级缓存移动到了二级缓存。
从上面三级缓存的分析,我们可以知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。这个cache的类型是ObjectFactory
,定义如下:
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
singletonFactories
缓存的添加发生在addSingletonFactory()
,addSingletonFactory()
发生在createBeanInstance
之后,populateBean
之前:
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
这里就是解决循环依赖的关键,这段代码发生在createBeanInstance
之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家使用。
这样做有什么好处呢?让我们来分析一下, 由于循环依赖导致问题:A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象:
- A首先完成了初始化的第一步,并且将自己提前曝光到
singletonFactories
中; - 此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),
- get(A)尝试一级缓存
singletonObjects
(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects
(也没有),尝试三级缓存singletonFactories
,由于A通过ObjectFactory
将自己提前曝光了; - 所以B能够通过
ObjectFactory.getObject
拿到A对象(虽然A还没有初始化完全,但是总比没有好呀); - B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存
singletonObjects
中。 - 此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存
singletonObjects
中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。
知道了这个原理时候,肯定就知道为啥Spring不能解决A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象这类问题了!因为加入singletonFactories
三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。
--Posted from Rpc