前言
经过了前一章的分析(spring 源码解析之 bean 的获取),我们是对 bean 的获取过程有了大致的了解,接下来就是详细剖析每个方法。以及为什么要这样做。
源码解析
transformedBeanName
根据 name获取 beanName,这里的 name 跟 beanName 有什么区别呢,这个 name 可能是普通的 bean名称,也可能是 factoryBean这个特殊的bean名称,factoryBean的名称是带有&的,所以要去掉特殊的符号。
getSingleton
前面已经提到过,
单例
在Spring 的同一个容器内只会被创建一次
,后续再获取 bean 直接从单例缓存
中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试从singletonFactories
中加载。因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
,Spring 创建bean的原则是不等bean 创建完成
就会将创建bean 的 ObjectFactory
提早曝光
加人到缓存中,一旦下一个 bean 创建时需要依赖上个 bean,则直接使用ObjectFactory
。这里好多概念如循环依赖、单例缓存、提早曝光等,后面会一一讲清楚,不着急,先混个眼熟。
- 优先从
singletonObjects
这个缓存中获取,如果存在则直接返回, - 如果不存在则判断该
bean是否正在创建
,如果是,则从earlySingletonObjects
获取,返回 - 如果还获取不到,则判断
是否运行循环依赖
,允许则在singletonFactories
这个缓存中获取,返回 - 如果再获取不到,那就返回 null。
java
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 获取单例 bean
Object singletonObject = this.singletonObjects.get(beanName);
// 如果bean 不在缓存中,并且当前正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 获取早期曝光的 bean (二级缓存里的 bean)
singletonObject = this.earlySingletonObjects.get(beanName);
// allowEarlyReference 是否可以循环依赖
if (singletonObject == null && allowEarlyReference) {
// 因为所有的 bean 缓存都是全局的,因此需要在锁内检查一次
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
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;
}
这里最主要的就是这几个缓存是什么东西?这三个缓存就是用来解决循坏依赖的问题,这也是面试会经常被问到的问题。
java
// singleton对象的缓存:bean名称到bean实例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
// 单例工厂缓存:bean名称到ObjectFactory HashMap。这是为了解决循环依赖问题,用于提前暴露对象 (三级缓存)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
// 早期曝光的singleton对象的缓存:bean名称到bean实例 (二级缓存)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** Names of beans that are currently in creation. */
// 当前正在创建的bean的名称
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
这里有一个问题了,什么是循坏依赖,什么是早期曝光的 bean?
下面是简单解释一下,详细了解看一下这篇文章:spring 源码解析番外篇之什么是循环依赖
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BeanA {
private final BeanB beanB;
// A依赖 B
@Autowired
public BeanA(BeanB beanB) {
this.beanB = beanB;
}
}
@Component
public class BeanB {
private final BeanA beanA;
// B 依赖 A
@Autowired
public BeanB(BeanA beanA) {
this.beanA = beanA;
}
}
-
上面的例子就是
循坏依赖
的例子,如果先是BeanA先实例化,则会查找该 bean 的依赖 bean。查到依赖 BeanB之后,先将BeanA 暂停实例化,同时会将BeanA的引用ObjectFactory缓存到singletonFactories之中
,然后就会优先将 BeanB 实例化完,再对 BeanA 继续实例化。 -
由于 BeanA 暂停实例化了,优先 BeanB 进行实例化,那么重复上面的步骤,BeanB 会找到 BeanA 的依赖,又优先实例化 BeanA,如此就会进入一个死循环,所以为了解决这个问题,
spring 就创建了上面那三个缓存
。 -
当实例化BeanB时,查询 BeanA 依赖同样会优先尝试从
singletonObjects
里面获取实例,如果获取不到再从earlySingletonObjects
里面获取,如果还获取不到,再尝试从ingletonFactories 里面获取 beanName 对应的ObjectFactory
,然后调用这个 ObjectFactory 的getObject
来创建 bean,并放到earlySingletonObjects
里面去,并且从singletonFactories 里面 remove 掉这个 ObjectFactory
。此时earlySingletonObjects
中的 BeanA 就是早期曝光的 bean
。 -
而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在 allowEarlyReference 为 true 的情况下才会使用。
-
这里涉及用于存储bean 的不同的 map,一开始可能很难理解,这也是所谓的三级缓存,用来处理循环依赖问题。
singletonObjects
:用于保存 BeanName和创建bean 实例之间的关系,bean name --> bean instance(一级缓存
)earlySingletonObjects
:也是保存 BeanName 和创建 bean 实例之间的关系,与singletonObjects 的不同之处在于,当一个单例bean 被放到这里面后,那么当 bean 还在创建过程中,就可以通过 getBean 方法获取到了,其目的是用来检测循环引用 (二级缓存
)singletonFactories
:用于保存 BeanName 和创建 bean的工厂之间的关系,bean name --> ObjectFactory (三级缓存
)registeredSingletons
:用来保存当前所有已注册的bean。
getObjectForBeanInstance
AbstractBeanFactory#getObjectFromFactoryBean
根据方法名称可以知道,这个方法就是返回bean 实例对象的。我们无论是从缓存中获取到的 bean 还是通过不同的 scope 策略加载的 bean 都只是最原始的 bean 状态
,并不一定是我们最终想要的 bean。举个例子,假如我们需要对工厂的 bean 进行处理,那么这里得到的其实是工厂bean 的初始状态
,但是我们真正需要的是工厂 bean 中定义的factory-method
方法中返回的 bean,而getObjectForBeanInstance
就是完成这个工作的。
java
/**
* 获取给定bean实例的对象,在FactoryBean的情况下,可以是bean实例本身,也可以是其创建的对象。这个话会有解释
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 判断name是否是FactoryBean的 name
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 以&开头又不是FactoryBean实现类,则抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 此时bean可能是 FactoryBean 或者 普通的bean。
// 判断如果 beanInstance 不是 FactoryBean而是普通的bean, 就直接返回
if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
return beanInstance;
}
// 到这一步就可以确定,当前beanInstance 是FactoryBean,并且需要获取getObject() 的结果
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 尝试从缓存中加载bean。这一步是从 factoryBeanObjectCache 集合中获取
// 在后面获取 bean 成功后,可能会将 其缓存到 factoryBeanObjectCache 中
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// Caches object obtained from FactoryBean if it is a singleton.
// containsBeanDefinition 检测 beanDefinitionMap中也就是所有已经加载的类中检测是否定义beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 如果存在 则合并父类 bean 定义的属性
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 这一步中对FactoryBean进行了解析。
object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
}
return object;
}
获取给定bean实例的对象,在FactoryBean的情况下,可以是bean实例本身,也可以是其创建的对象。这句话怎么理解呢?比如下面这个例子
java
public class MyFactoryBean implements FactoryBean<MyObject> {
@Override
public MyObject getObject() throws Exception {
// 这里创建并返回MyObject实例
return new MyObject();
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
// 简单写个方法
MyObject myObject = (MyObject) context.getBean("myFactoryBean");
MyFactoryBean myFactoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");
- 这也就为什么在一开始会有
特殊字符处理
,所以这个方法一开始在判断是否是FactoryBean
- 如果不是FactoryBean那就是
普通的 bea
n 实例,直接返回 - 如果是FactoryBean,则使用这个
FactoryBean创建 bean 实例
- 调用
getObjectFromFactoryBean
获取 bean 实例
从上述的代码来看,其实这个方法没有什么重要的信息,大多是辅助代码以及一些功能性判断,而真正的核心代码委托给了
FactoryBeanRegistrySupport#getObjectFromFactoryBean
,我们一起来看看。
getObjectFromFactoryBean
java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 判断是否是单例并且是否已经缓存过了
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 获取缓存的单例对象
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 在这个方法中进行解析。调用 FactoryBean 的 getObject 方法。factory.getObject()
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)
// 因为是单例模式,所以要保证变量的全局唯一。所以这里如果缓存中已经创建好了bean则替换为已经创建好的bean
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
// // 如果允许调用bean的后置处理器。因为这里是直接将bean创建返回了,如果要调用后置方法则只能在这里调用。
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
// 将beanName 添加到 singletonsCurrentlyInCreation 中缓存,表示当前bean正在创建中
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// 将beanName 从 singletonsCurrentlyInCreation 中移除,表示当前bean已经创建结束
afterSingletonCreation(beanName);
}
}
// 添加到factoryBeanObjectCache缓存中
if (containsSingleton(beanName)) {
// 这里保存的是 beanName : FactoryBean
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
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;
}
}
如果是单例并且在
singletonObjects
这个缓存中已经缓存过的,非单例获取未缓存过的直接使用doGetObjectFromFactoryBean,并调用后置处理器postProcessObjectFromFactoryBean
- 先尝试在
factoryBeanObjectCache
这个缓存中获取,如未缓存 - 则再从
doGetObjectFromFactoryBean
此方法使用factory.getObject()
获取 - 如果允许调用后置处理器,则调用
postProcessObjectFromFactoryBean
- 添加
factoryBeanObjectCache
缓存
我当时看到这里就有个疑问,为什么要先判断singletonObjects是否已经缓存了?那如果已经缓存了,为什么不直接使用这个 bean 实例呢?
singletonObjects
这个缓存中存在对应的 bean,那么就意味着这个Bean已经被实例化过了。这并不意味着我们可以直接从singletonObjects缓存中获取Bean的实例对象。因为这里的 bean 只是一个原始的 bean 实例
,也就是在这个方法解析之前所说,我们从缓存获取到的实例对象并不是最终状态的 bean 对象
。- 因为在Spring中,一个Bean的创建过程可能会涉及到一些
后处理操作
,这些操作可能会改变Bean的最终状态。这就是为什么我们需要尝试从factoryBeanObjectCache这个缓存中获取Bean的原因
。 factoryBeanObjectCache缓存中存储的是已经经过后处理的Bean实例
。当我们调用getObjectFromFactoryBean方法时,如果beanName已经存在于singletonObjects缓存中,那么我们会尝试从factoryBeanObjectCache
缓存中获取已经经过后处理的Bean实例。如果在factoryBeanObjectCache
缓存中找不到,那么我们会执行后处理操作,然后将处理后的Bean实例存入factoryBeanObjectCache缓存
。- 这样做的好处是,我们可以
确保无论何时获取Bean
,都能获取到的是已经经过后处理的Bean实例
,而不仅仅是原始的、未经处理的Bean实例。这对于保证Spring框架的稳定性和可预测性是非常重要的。
doGetObjectFromFactoryBean
经过上面的代码,还是没有看到有关键的信息,重要的操作委托给了
FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
而重要的代码就是这一行
object = factory.getObject();
java
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
object = factory.getObject();
}
......
return object;
}
上面我们已经讲述了 FactoryBean 的调用方法,如果 bean 声明为 FactoryBean 类型,则当提取 bean 时提取的并不是 FactoryBean,而是 FactoryBean 中对应的getObject 方法返回的 bean,而 doGetObjectFromFactoryBean 正是实现这个功能的。但是,我们看到在上面的方法中除了调用 object = factory.getObject()
得到我们想要的结果后并没有直接返回,而是接下来又做了些后处理的操作,回到getObjectFromFactoryBean
继续跟踪进入 AbstractAutowireCapableBeanFactory类的 postProcessObjectFromFactoryBean 方法。
java
@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
- 对于后处理器的使用还未过多接触,后续会详细介绍,这里,我们只需了解在 Spring获取 bean 的规则中有这样一条:
尽可能保证所有bean 初始化后都会调用注册的BeanPostProcessor 的 postProcessAfterInitialization
方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。
getParentBeanFactory
回到doGetBean方法,接下来解析getParentBeanFactory。如果存在父级工厂,并当前的BeanDefinition不存在,则尝试去父级工厂获取
java
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 递归到BeanFactory中检测
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory abf) {
return abf.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);
}
}
getMergedLocalBeanDefinition
将当前的BeanDefinition与父级的BeanDefinition 合并成一个BeanDefinition,RootBeanDefinition:mdb,后面基本都是使用这个参数,一路点点点点下去,最终会来到
AbstractBeanFactory#getMergedBeanDefinition
java
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
// 判断如果parentName为空则没必要进行合并了,直接克隆返回即可
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition rootBeanDef) {
mbd = rootBeanDef.cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
// 递归调用,解析更上层的parent BeanDefinition ,直到beanName=parentBeanName或者parentBeanName为 null
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 获取父bean的beanDefinition
if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent) {
pbd = 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);
}
// Deep copy with overridden values.
// 深拷贝
mbd = new RootBeanDefinition(pbd);
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()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
- 使用BeanDefinition获取parentName,
判断如果parentName为空则没必要进行合并了,直接克隆返回即可
- 如果存在父类的 bean,递归调用,解析更上层的parent BeanDefinition ,直到beanName=parentBeanName或者parentBeanName为 null
- 获取父bean的
beanDefinition#pbd
,然后深拷贝到RootBeanDefinition#mdb
- 添加缓存
mergedBeanDefinitions
查询依赖 bean
原本以为这个方法很简单,但是当初详细深入进去,有几个地方有疑问的,带我一一剖析。
先直接看到源码中的isDependent这个方法。
DefaultSingletonBeanRegistry#isDependent
java
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
// 是否已经检测过了
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
// 从aliasMap中获取别名映射的 beanName
String canonicalName = canonicalName(beanName);
// 获取依赖的beanName
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null || dependentBeans.isEmpty()) {
return false;
}
// 如果 依赖于 beanName中存在 dependentBeanName 则说明存在循环依赖。
// 代码走到这里说明是beanName 创建过程中要依赖 dependentBeanName。但是dependentBeans.contains(dependentBeanName) = true 则说明dependentBeanName依赖于beanName
// 造成了 A依赖B,B依赖A的情况
if (dependentBeans.contains(dependentBeanName)) {
return true;
}
// 递归,确定没有A->B->C-A 这种长链路的循环依赖情况
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
for (String transitiveDependency : dependentBeans) {
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
}
return false;
}
当时我的疑问? 问题1、为什么dependentBeans.contains(dependentBeanName)如果存在这个依赖就直接抛异常?(isDependent这个方法返回true,则 doGetCreate 方法就抛异常)
这里涉及到两个缓存dependentBeanMap、dependenciesForBeanMap
,这两个缓存主要用于存储和管理Bean之间的依赖关系,但是作用一个是依赖的 bean 作为 key,一个是被依赖的作为 key。
如果一个 BeanA 使用 @Autowired
注入了 BeanB,那么在这两个缓存中的存储方式如下:
dependentBeanMap
:在这个缓存中,BeanB 作为键,BeanA 作为值。这是因为 BeanA 依赖于 BeanB,所以 BeanB 被 BeanA 所依赖。dependenciesForBeanMap
:在这个缓存中,BeanA 作为键,BeanB 作为值。这是因为 BeanA 依赖于 BeanB,所以 BeanA 有一个依赖,即 BeanB。
所以一开始就确定beanName依赖于dependentBeanName,所以这里使用dependentBeanMap判断两者是否存在循坏依赖,如果存在,则直接抛异常
问题 2、为什么循坏依赖直接抛异常,不是有三级缓存吗?
这里有涉及到一个问题,mbd.getDependsOn();获取的并非是依赖注入(使用@Autowired)的依赖 bean,而是depends-on中的 bean,下面的beanA则依赖于beanB,但是beanB 并非直接注入到 beanA 中,而是要确定beanB的初始化必须要在beanA 之前
。
所以@Autowired是直接依赖注入,depends-on(@DependsOn)则是定义 bean 的初始化循序。
xml
<beans>
<bean id="beanA" class="ExampleBean" depends-on="beanB">
<property name="manager" ref="manager" />
</bean>
<bean id="beanB" class="BeanB" />
</beans>
所以如果出现循坏依赖时,即 BeanA 与 BeanB 相互依赖,但是BeanA 又使用了@DependsOn依赖 BeanB,那么在初始化 BeanA 时,发现BeanB 要初始化完成在 BeanA 之前,但是 BeanB 又要依赖 BeanA,就会相互冲突,所以 spring 对此会直接抛异常。
注: @DependsOn:注解是在另外一个实例创建之后
才创建当前实例,也就是,最终两个实例都会创建,只是顺序不一样 @ConditionalOnBean :注解是只有当另外一个实例存在时,才创建,否则不创建,也就是,最终有可能两个实例都创建了,有可能只创建了一个实例,也有可能一个实例都没创建