回顾一下前面,在
**AbstractApplicationContext**
中,**refresh()**
完成了整个IOC容器的刷新,上回我们分析到了初始化剩下所有的单实例bean,这里面有几个核心的地方,**getBean(),createBean(),populateBean()**
,三级缓存与循环依赖,完成这些后,整个IOC容器的大体流程就分析完了。本篇我们来分析Spring的**getBean()**
。
1.初始化所有的单实例bean对象
**finishBeanFactoryInitialization()**
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 为此上下文初始化转换服务
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 如果容器里面没有字符串转换器,初始化一个字符串转换器放到容器中。
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 尽早初始化LoadTimeWeaverAware beans,以便尽早注册它们的转换器。
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止使用临时类加载器进行类型匹配
beanFactory.setTempClassLoader(null);
// 允许缓存所有bean定义元数据,不期望进一步的更改,冻结bd信息,冻结之后就无法往bf注册bd了
beanFactory.freezeConfiguration();
// 实例化所有剩余的单实例bean
beanFactory.preInstantiateSingletons();
}
冻结bd的信息实际上就是通过一个状态位来控制的,这里面最核心的一个方法或者说步骤就是实例化所有剩余的单实例bean对象。**beanFactory.preInstantiateSingletons()**
2.preInstantiateSingletons()
@Override
public void preInstantiateSingletons() throws BeansException {
//日志打印
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
/*拿过来所有的beanDefinition names 信息*/
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 触发所有的非懒加载的单例bean的初始化
for (String beanName : beanNames) {
//获取bean的定义信息
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// bean不是抽象的 是单例的 不是懒加载的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//如果是工厂bean
if (isFactoryBean(beanName)) {
//通过getBean方法获取bean 前缀 & 拿到的是工厂bean
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
//如果拿到的bean确定是工厂bean
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
//判断这个工厂bean是否期望被初始化
/*判断逻辑:SmartFactoryBean里面有一个isEagerInit方法,这个方法为true就表示这个工厂bean是需要现在创建的*/
boolean isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
//如果期望被初始化
if (isEagerInit) {
//通过getBean走创建bean的逻辑
getBean(beanName);
}
}
}
else {//执行到这里,说明就是普通的单实例bean,不是工厂bean,直接通过getBean创建bean
//三级缓存解决循环依赖的入口:
/**
* 重点
*/
/**
* eg:man 和 women 产生循环依赖
* 1.第一次来到这里是首先去创建man
*/
getBean(beanName);
}
}
}
// 触发所有的单实例bean的初始化后的回调逻辑
for (String beanName : beanNames) {
//从一级缓存获取单实例bean
Object singletonInstance = getSingleton(beanName);
//类型断言,执行回调
/*SmartInitializingSingleton里面有一个方法 afterSingletonsInstantiated 这个方法需要在创建好单实例bean之后调用一下*/
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
//这里就是触发初始化后的回调逻辑
smartSingleton.afterSingletonsInstantiated();
smartInitialize.end();
}
}
}
这里拿到所有的**beanDefinition**
的名字,然后循环判断:【不是抽象的,单实例的,非懒加载的】,然后根据拿到的bean定义信息,再分为**FactoryBean**
和**Bean**
两种情况进行处理。
梳理一下这里的重点逻辑:
- 合并
**beanDefinition**
信息**getMergedLocalBeanDefinition(beanName)**
- 获取bean对象
**getBean() **
**SmartInitializingSingleton**
回调**afterSingletonsInstantiated() **
触发单实例bean初始化后的回调逻辑
�
接下来先来分析,如何合并bean的定义信息。
3. getMergedLocalBeanDefinition(beanName)
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
/*从缓存获取*/
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
/*缓存有,直接返回*/
if (mbd != null && !mbd.stale) {
return mbd;
}
/*真正的合并 bd 的逻辑*/
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
首先会先尝试从缓存来获取**beanDefinition**
的信息,如果缓存有,就直接返回,否则就要触发合并bd的逻辑。
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
/*合并后的bd信息
* */
RootBeanDefinition mbd = null;
/*表示当前beanname对应的过期的mbd信息*/
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
/*null==null*/
if (containingBd == null) {
/*从缓存拿信息*/
mbd = this.mergedBeanDefinitions.get(beanName);
}
/*条件成立说明mbd==null或者 过期...*/
if (mbd == null || mbd.stale) {
/*表示当前beanname对应的过期的mbd信息*/
previous = mbd;
/*没有当前beanName 对应的 bd 没有使用继承 那么就不用处理继承 */
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
/*如果 mbd 是 root bean*/
if (bd instanceof RootBeanDefinition) {
/*克隆一份保存*/
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
/*否则直接创建一个root bean*/
mbd = new RootBeanDefinition(bd);
}
}/*说明当前beanName 对应的 beanDefinition 存在继承关系*/
else {
/*表示bd 的父信息*/
BeanDefinition pbd;
try {
/*处理beanName 拿到处理了别名和&的真是父bd beanName 名称*/
String parentBeanName = transformedBeanName(bd.getParentName());
/*条件成立 说明 子 bd 和父 bd 名称不一样,就是普通情况*/
if (!beanName.equals(parentBeanName)) {
/*递归当前方法,最终返回父 bd 信息*/
pbd = getMergedBeanDefinition(parentBeanName);
}
else {/*特殊:父子bd名称一样*/
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// 按照父bd信息创建 mbd 对象
mbd = new RootBeanDefinition(pbd);
// 用子bd 覆盖mbd信息,以子bd 为基准 父 bd为辅
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
if (containingBd == null && isCacheBeanMetadata()) {
/*缓存合并后的 mbd信息*/
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
这里面需要关注的点有两个:
- 如何处理bean的名字
**transformedBeanName()**
- 如何合并bd信息
**getMergedBeanDefinition()**
4.处理bean的名字
protected String transformedBeanName(String name) {
/*
* 返回 BeanFactoryUtils.transformedBeanName(name) 处理完的bean name ,这里也可能是别名。
* spring的bean别名是通过aliasMap保存的。
* {C:B,B:A} a有一个别名叫做 b b有一个别名叫做 c
*
* 通过这个方法canonicalName 去处理 bean的名字 和别名之间的关系 ,最终返回的是 bean 的真实名字。
* */
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
4.1 canonicalName()
处理bean的名字与别名。
public String canonicalName(String name) {
/*假设传入c*/
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
/*根据c会从map拿到b*/
resolvedName = this.aliasMap.get(canonicalName);
/*如果获取到的结果不是null*/
if (resolvedName != null) {
/*赋值再次循环拿*/
canonicalName = resolvedName;
}
}
/*当resolvedName是空的时候,那么此时的canonicalName一定是最终的名字,返回即可。*/
while (resolvedName != null);
return canonicalName;
}
4.2 BeanFactoryUtils.transformedBeanName(name)
public static String transformedBeanName(String name) {
/*断言*/
Assert.notNull(name, "'name' must not be null");
/*如果当前bean对象不是 & 开头 (说明是正常bean对象实例) 直接返回*/
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
/*
* 这里是拿工厂bean的逻辑:
* transformedBeanNameCache:缓存处理完&开头的beanName,提升性能
* map.computeIfAbsent(k,v) 说明:
* 当map中对应的k ==null || v ==null 这次写操作就会成功,并且返回 k v,
* 否则就会失败,并且返回原有的k v。
*/
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
/**
* 假设bean name = &abc
* 判断如果name不是以 &开头 跳出循环 最终会返回 abc。
*/
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
5.合并bd信息
**getMergedBeanDefinition()**
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
/*从缓存获取*/
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
/*缓存有,直接返回*/
if (mbd != null && !mbd.stale) {
return mbd;
}
/*真正的合并 bd 的逻辑*/
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
再往下其实又回到了上面的**getMergedBeanDefinition()**
,递归去处理bd信息。
合并完bd信息之后就是判断是否是工厂bean的逻辑,想要获取工厂bean,在前面提到过,需要在bean的名字前面加一个 & 。
默认情况下,我们要看单实例bean的获取过程,此时我们去看 **getBean()**
。
6.获取单实例bean对象
**getBean()**
@Override
public Object getBean(String name) throws BeansException {
/*真正加载bean的方法*/
return doGetBean(name, null, null, false);
}
**doGetBean()**
返回一个指定的bean实例,这个bean可以是共享的,也可以是单例的。
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
/*
* 处理转换bean名字,可能是一个别名,也可能是一个带着& 开头的beanName
* 别名:重定向出来真的beanName
* &开头:说明要获取的bean实例对象实际上是一个工厂bean
* FactoryBean :如果某个bean的配置特别复杂,使用spring管理不容易...不够灵活,想要使用编码的形式去构建它,
* 那么你就可以提供一个构建该bean实例的工厂,这个工厂就是factoryBean接口
* factoryBean接口的实现类还是需要spring来管理的。
* 这里就涉及到两种对象:一种是beanFactory实现类 另一个是FactoryBean内部管理的对象。
*
* 如果要获取工厂bean,需要获取 &
* 如果要拿factoryBean内部管理的对象,直接传name 不需要带着 &
*/
String beanName = transformedBeanName(name);
//保留返回值的
Object beanInstance;
/*到缓存中获取共享单实例 第一次去缓存拿*/
/**
* 1.第一次经过这里是创建man的时候,首先去缓存获取,但是这个时候,man对象时第一次创建,所以什么都拿不到
* 2.此时man在第三级缓存,然后去拿women,这个时候women还没创建,所以锤子也拿不到
* 3.第三次经过这里的时候,实际上就是women创建完了,放到三级缓存了,然后发现属性赋值的时候需要man,又通过getBean来拿,
* 这个时候,在第三级缓存拿到了早期对象的引用,然后并对man进行一个缓存升级 ,从 三级缓存升级到了二级
*/
Object sharedInstance = getSingleton(beanName);
/*此时的逻辑应该是从二级缓存拿到了早期暴露的bean实例,并且属性没有填充*/
/*这里如果是第一次创建bean实例,上面从一级缓存实际上是啥也没拿到,所以走到这里,实例是null。*/
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 + "'");
}
}
/*
* 这里为什么又要包装一层呢?
* 从ioc中拿到的对象可能是普通的单实例,也可能是FactoryBean实例
* 如果是FactoryBean实例,还要考虑进行处理 主要看name带不带 &
* 带&说明这次getBean想要拿工厂bean,否则想要拿 FactoryBean 内部管理的 bean 实例
*/
/**
* 1.走到这里是什么时候?创建man,然后对man进行属性赋值,发现需要women,然后递归去创建women,然后对women进行属性赋值,
* 然后发现需要man,然后从缓存拿,恰好此时从三级缓存拿到了,早期man对象的引用,这个时候,这里啥也没干,直接return
*/
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
/*
* 执行到这里的情况:sharedInstance == null || args != null
* 1. 二级缓存未拿到bean实例
* 2. 二级缓存拿到了bean实例,但是属性已经填充完了 !!!这是不可能的,这样的话就在一级缓存了。
*
* 缓存没有想要的数据
* 1.原型循环依赖问题的判定
*/
else {
/*
* 原型循环依赖的判定
* eg: a(prototype) - b b - a (prototype)
* 1.会像正在创建中的原型集合添加 a
* 2.创建 a 早期对象 二级缓存
* 3.处理 a的依赖 发现 a 依赖 b 类型
* 4.触发 spring getBeab(b.class) 的操作
* 5.根据 b 的构造方法 反射创建 b 的早期实例
* 6.spring 处理 b 对象的依赖发现依赖了 a
* 7.所以spring砖头回来再次获取 a getBean(a.class)
* 8.程序再次来到这里会判断当前要获取的a对象是不是正在创建中 如果是循环依赖 会返回true ,最终抛出异常 结束了循环依赖注入
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/*父子容器相关的处理逻辑*/
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);
}
}
/*穿的是false就成立*/
if (!typeCheckOnly) {
/*
* 将指定的 bean 标记为已创建(或即将创建)。
* 允许 bean 工厂优化其缓存以重复创建指定 bean。
*/
/**
* 1.第一次创建man的时候,经过这里,标记man正在创建中
* 2.第二次经过这里的时候,就是对man进行属性赋值的过程中,发现依赖women,所以去走getBean逻辑。这个时候去标记women也是正在被创建中
*/
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
/*获取合并beanDefinition信息
* 为什么需要合并?
* bd 支持继承 子 会 继承 父亲 的所有 信息
* */
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
/*判断当前mbd是不是抽象的,如果是抽象的,需要抛出异常,因为抽象的bd不能创建实例,只能作为模板让子bd继承*/
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
/*
* depends-on 属性处理
* <bean name="A" depends-on="B" />
* <bean name="B" />
*
* 循环依赖问题 b - a a - b
* spring是处理不了这种情况的,需要报错
* spring需要发现这种情况的产生:
* 如何发现?依靠两个map
* 1.dependentBeanMap 记录依赖当前beanName的其他beanName
* 2.dependenciesForBeanMap 记录当前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 + "'");
}
/*
* 注册依赖关系
* 1.记录a依赖了谁
* 2.记录谁依赖了b
* */
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 创建单实例
if (mbd.isSingleton()) {
/*第二个 getSingthon() 创建实例并返回*/
/**
* 1.第一次经过这里是去创建man对象
* 2.创建women对象
*/
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也可能是工厂bean对象,所以需要根据名字判断到底返回
* bean对象还是工厂bean
* */
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
/*多例bean的创建*/
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
/*记录当前线程相关的正在创建的原型对象beanName*/
beforePrototypeCreation(beanName);
/*创建对象*/
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
/*从正在创建中的集合中移除*/
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
/*other作用域: 略 ....*/
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
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);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
/**
* 1.走到这里的逻辑:对man进行属性赋值,递归创建women,对women进行属性赋值,然后从缓存拿到了man
*/
return adaptBeanInstance(name, beanInstance, requiredType);
}
这个方法的逻辑有点多,进行一个简单的梳理:
- 首先上来先处理bean的名字
**transformedBeanName(name)**
- 然后尝试通过
**getSingleton(beanName) **
去一级缓存拿数据,但是这个时候这个bean对象还没有创建过,此时是拿不到数据的。
- 如果说拿到了bean对象,那么就再通过
**getObjectForBeanInstance() **
对bean对象进行一层包装。这里为什么又要包装一层呢? 从IOC中拿到的对象可能是普通单实例bean对象,也可能是一个工厂bean对象。 如果是工厂bean对象,还需要考虑是不是需要处理,主要是看名字里面带不带 & 。 如果带 & ,就是想要拿工厂本身,如果不带 & ,其实就是想拿工厂bean生产的对象。
- 正常第一次去获取bean对象的时候,是在缓存拿不到数据的,所以会走else的逻辑。
- 判断是不是原型模式的循环依赖,如果是的话,抛出异常。
- 然后就是护理父子容器相关的逻辑
- 如果是第一次创建bean,就会通过一个状态位来标记bean正在创建中
- 获取合并后的bd信息
- 判断当前bean对象是不是抽象的,如果是抽象的,需要跑出异常,因为抽象的bean是模板bean,不能创建实例
判断是不是发生互相依赖,注意是互相依赖,不是循环依赖,如果是发生了互相依赖,则抛出异常。
互相依赖:bean标签或者@Bean 注解里面配置了
**depends-on="B" a->b , b->a**
循环依赖:a里面有个属性叫做b,b里面有个属性a �
注册依赖关系,记录当前bean依赖了谁,谁依赖了当前bean
- 判断如果是单实例bean,这次就会通过
**getSingleton()->createBean()**
去创建bean对象 - 然后再通过
**getObjectForBeanInstance() **
对bean对象进行一层包装 - 如果是原型实例的bean对象,就会走多实例bean创建的流程,其实还是通过
**createBean()**
去创建对象,只是不会被一级缓存所缓存。 - 对于其他作用域的bean对象,则走他们的创建逻辑,再次不作为重点内容分析。
- 最终的逻辑
**adaptBeanInstance()**
其实就是对循环依赖的处理,对 A对象属性赋值的时候,发现需要B对象。然后从一级缓存拿发现没有,就走这里递归去创建B对象,从缓存拿到A对象,对B对象进行属性赋值。
7.getSingleton()
看一下这个方法,从缓存来获取bean。这个方法在 **DefaultSingletonRegistry**
中。
@Override
@Nullable
public Object getSingleton(String beanName) {
/*方法重载 allowEarlyReference 是否允许拿到早期引用*/
return getSingleton(beanName, true);
}
�这里发生了方法重载。这个方法挺叼的,根据名称来返回单实例bean对象,能够解决循环依赖。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
/*通过名字去一级缓存拿单实例bean对象*/
Object singletonObject = this.singletonObjects.get(beanName);
/*如果拿到的对象实例是null,有几种情况?
* 1.单实例确实没创建呢
* 2. 当前正在创建中,发生了循环依赖了,这个时候实例其实在二级缓存
*
* 循环依赖:
* A->B B->A
* 单实例的循环依赖有几种?
* 1.构造方法 无解
* 2.setter 有解 通过三级缓存
*
* 三级缓存实际上如何解决的循环依赖?
* 利用bean的中间状态 :已经实例化但是还未初始化
* A-B B->A setter依赖
* 1. 假设spring先实例化A,首先拿到A的构造方法,反射创建A的早期实例对象,这个早期对象被包装了一下,
* 变成ObjectFactory对象,放到三级缓存。
* 2. 处理A的依赖数据,检查发现 A依赖B ,所以,spring 根据 B的类型去容器中去getBean(B.class) ,这里就是递归了
* 3. 首先拿到B的构造方法,反射创建B的早期实例对象,把B包装成ObjectFactory对象,放到三级缓存。
* 4. 处理Bde 依赖数据,检查发现,B依赖对象A,所以接下来,spring就会根据A类型去容器去getBean(A.class) 对象,这个时候又递归了
* 5. 程序还会走到当前方法getSingleton
* 6. 条件一成立,条件二成立。
*
*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
/*从二级缓存拿数据*/
singletonObject = this.earlySingletonObjects.get(beanName);
/*条件成立说明二级缓存没有 去三级缓存拿*/
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
/*
* spring为什么需要有三级缓存,而不是只有二级缓存?
* AOP 靠什么实现呢?动态代理 jdk cglib
* 代理:静态代理:需要手动写代码实现新的JAVA文件,这个JAV类需要和代理对象实现同一个接口,内部维护一个被代理对象
* 代理类在接口调用原生对象前后可以加一些逻辑。
* 代理对象和被代理对象是两个不同的内存地址,一定是不一样的
* 动态代理:... 不需要人为写代码了,而是依靠字节码框架动态生成字节码文件,然后jvm在进行加载,然后也是一样
* 也是去new代理对象,这个代理对象没啥特殊的,也是内部保留了原生对象,然后再调用原生对象前后实现的字节码增强。
* 两者共同点:代理对象和被代理对象实际上都不是同一内存地址
*
* 三级缓存在这里有什么意义呢?
* 三级缓存里面保存的是对象工厂,这个对象工厂内部保留着原生对象的引用,ObjectFactory的实现类,getObject方法,
* 需要考虑一个问题:到底是返回原生的,还是增强的?
* getObject会判断当前早期实例是否需要被增强,如果是 那么提前完成动态代理增强,返回代理对象,否则,返回原生对象。
*
*/
/*从一级缓存拿*/
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
/*从二级缓存拿*/
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
/*从三级缓存拿*/
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
/*条件成立:说明第三级缓存有数据。这里就涉及到了缓存的升级 ,很简单 ,从三级挪到二级 ,再反手干掉三级的。*/
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
梳理一下这个方法的大体逻辑:(我们现在走的是单实例bean创建的流程,所以假设我们正在创建一个单实例bean,执行到了这里,三级缓存与循环依赖的问题会在后续文章分析。)
- 先根据名字去一级缓存拿bean,此时是拿不到的。
- 判断当前bean,是不是单实例bean对象,是不是正在创建中?
走这里的逻辑就是发生了循环依赖:
- 假设spring先实例化A,首先拿到A的构造方法,反射创建A的早期实例对象,这个早期对象被包装了一下,变成ObjectFactory对象,放到三级缓存。 � �2. 处理A的依赖数据,检查发现 A依赖B ,所以,spring 根据 B的类型去容器中去getBean(B.class) ,这里就是递归了 �
- 首先拿到B的构造方法,反射创建B的早期实例对象,把B包装成ObjectFactory对象,放到三级缓存。 �
- 处理Bde 依赖数据,检查发现,B依赖对象A,所以接下来,spring就会根据A类型去容器去getBean(A.class) 对象,这个时候又递归了 �
- 程序还会走到当前方法getSingleton �
- 首先去二级缓存拿数据,这个时候二级缓存是拿不到数据的,所以会继续往下走
- 再次尝试从一级缓存和二级缓存拿,这个时候其实还是拿不到的,所以从三级缓存来拿
- 如果三级缓存拿到了数据,那就进行缓存的升级
把三级缓存的对象拿到二级缓存,三级缓存的对象干掉。
8.思考与沉淀
spring为什么需要有三级缓存,而不是只有二级缓存?
AOP 靠什么实现呢?动态代理 jdk cglib
代理:静态代理:需要手动写代码实现新的JAVA文件,这个JAV类需要和代理对象实现同一个接口,内部维护一个被代理对象
代理类在接口调用原生对象前后可以加一些逻辑。
代理对象和被代理对象是两个不同的内存地址,一定是不一样的
动态代理:… 不需要人为写代码了,而是依靠字节码框架动态生成字节码文件,然后jvm在进行加载,然后也是一样
也是去new代理对象,这个代理对象没啥特殊的,也是内部保留了原生对象,然后再调用原生对象前后实现的字节码增强。
两者共同点:代理对象和被代理对象实际上都不是同一内存地址
三级缓存在这里有什么意义呢?
三级缓存里面保存的是对象工厂,这个对象工厂内部保留着原生对象的引用,ObjectFactory的实现类,getObject方法,
需要考虑一个问题:到底是返回原生的,还是增强的?
getObject会判断当前早期实例是否需要被增强,如果是 那么提前完成动态代理增强,返回代理对象,否则,返回原生对象。
9.getObjectForBeanInstance()
这个方法是获取给定的bean实例对象,如果是工厂bean,则根据名字返回工厂本身或者其创建的对象。
/**
* 获取给定 bean 实例的对象,如果是 FactoryBean,则是 bean 实例本身或其创建的对象。
* @param beanInstance 共享单实例对象
* @param name 未处理 & 的 name
* @param beanName 处理过& 和别名后的name
* @param mbd the merged bean definition 合并过后的beanDefinition信息
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
/*判断当前的name是不是&开始的,条件成立,说明当前要获取的是工厂bean对象*/
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
/*条件成立:说明但实例对象不是工厂bean接口的实现类 直接报错*/
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
/*打标 给当前bean对应的mbd打标,记录他表达的实例是一个工厂bean*/
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
/*
* 执行到这里有几种情况?
* 1.当前bean实例是普通单实例
* 2.当前bean实例是工厂bean接口实现类,但是当前要获取的是工厂内部管理的bean实例
*/
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
/*保存工厂bean实例的getobject值得*/
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
/*尝试到缓存获取工厂bean*/
object = getCachedObjectForFactoryBean(beanName);
}
/*此时说明缓存没有,需要到工厂bean getObject 获取*/
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 条件一几乎恒成立 条件二:判断spring中当前是否有当前beanName的bd信息
if (mbd == null && containsBeanDefinition(beanName)) {
/*拿到合并后的bd信息
* 为什么是合并后的呢?
* 因为bd支持继承的,合并后的bd信息是包含继承回来的bd
* */
mbd = getMergedLocalBeanDefinition(beanName);
}
/*synthetic默认值是false ,表示这是一个用户对象 如果是 true 表示是系统对象*/
boolean synthetic = (mbd != null && mbd.isSynthetic());
/*到这里说明 说明真正的去执行 getBean() 的逻辑 time 【51:32】*/
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
- 判断当前的name是不是 & 开始的,条件成立,说明当前要获取的是工厂bean对象
- 如果当前bean独享没有实现工厂bean接口,直接报错
- 打标:给当前bean对应的mbd打标,记录他表达的实例是一个工厂bean对象
- 返回bean实例
- 判断如果当前bean没有实现工厂bean接口,(思考一下,走到这里的逻辑,其实要么是单实例bean,要么是获取工厂bean创建的对象),既然没有实现工厂bean接口,所以这里的逻辑就是处理单实例bean的。
- 直接返回就行了
- 走到这里的逻辑就是一种情况:获取工厂bean创建的bean对象。
- 在mbd打标,表示是一个工厂bean对象
- 如果缓存里面没有当前bean工厂生产的对象,需要通过工厂bean的
**getBean()**
去获取。 - 判断有没有bd信息,如果没有就合并bd信息得到mbd信息
- 然后再通过
**getObjectFromFactoryBean() **
根据mbd信息去获取bean对象
9.1 getObjectFromFactoryBean()
这个方法的逻辑上存在问题,但是不影响分析。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
/*如果是已经存在的单实例bean对象*/
if (factory.isSingleton() && containsSingleton(beanName)) {
/*加锁 内部逻辑是串行化的,不存在并发*/
synchronized (getSingletonMutex()) {
/*先从缓存获取*/
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
/*这里已经是空了*/
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
/*这里一定是空,因为是串行化的方法,所以逻辑有问题*/
if (alreadyThere != null) {
object = alreadyThere;
} else {
if (shouldPostProcess) {
/*判断当前实例是否被创建 逻辑有问题 明明上面就是没创建 */
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
/*执行后置处理器的逻辑*/
object = postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
} finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
/*工厂bean对象内部维护的对象不是单实例,每次都是一个新对象*/
} else {
/*直接拿*/
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
/*后置处理器的逻辑*/
object = postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
if里面的判断是不会成立的,所以直接看else的逻辑。
通过委派模式委派给**doGetObjectFromFactoryBean()**
去拿bean对象,然后再执行后置处理器的逻辑。
继续往下分析:
9.2 doGetObjectFromFactoryBean()
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
object = factory.getObject();
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
这里面的核心代码其实就是只有一句:调用工厂bean的**factory.getObject()**
获取bean对象。
剩余的**createBean()**
& **adaptBeanInstance()**
,**createBean()**
创建bean的逻辑会在下一篇中深入分析,**adaptBeanInstance()**
循环依赖相关的逻辑会在后续的三级缓存与循环依赖篇中分析,与本次的创建单实例bean对象关系并不大。至此,整个**getBean()**
就分析完了。
10.触发所有单实例bean初始化后的回调逻辑
在**preInstantiateSingletons()**
里面通过 getBean() 方法实例化完所有的单实例bean以后,就会触发所有 **SmartInitializingSingleton**
的 **afterSingletonsInstantiated()**
。
�
�这个组件具体的作用,在前面的Spring组件与注解篇里面已经详细介绍过,在此不再赘述。
// 触发所有的单实例bean的初始化后的回调逻辑
for (String beanName : beanNames) {
//从一级缓存获取单实例bean
Object singletonInstance = getSingleton(beanName);
//类型断言,执行回调
/*SmartInitializingSingleton里面有一个方法 afterSingletonsInstantiated 这个方法需要在创建好单实例bean之后调用一下*/
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
//这里就是触发初始化后的回调逻辑
smartSingleton.afterSingletonsInstantiated();
smartInitialize.end();
}
}
下一篇,我们将继续分析bean对象的创建逻辑 **createBean()**
。