spring之为什么要来进行合并
spring在调用的时候,已经将所有的类生成了BeanDefinition。invokeBeanFactoryPostProcessors(beanFactory);完成扫描逻辑。
那么下面将会对bean来做处理。
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
关于第一步骤中要来进行BeanDefinition的合并?为什么要来进行合并呢?回到第一章节提到的BeanDefinition。
GenericBeanDefinition parentGenericBeanDefinition = new GenericBeanDefinition();
parentGenericBeanDefinition.setInitMethodName("init");
parentGenericBeanDefinition.setLazyInit(false);
parentGenericBeanDefinition.setPrimary(true);
parentGenericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
parentGenericBeanDefinition.setDestroyMethodName("destroy");
parentGenericBeanDefinition.setAbstract(true);
applicationContext.registerBeanDefinition("parent",parentGenericBeanDefinition);
GenericBeanDefinition aGenericBeanDefinition = new GenericBeanDefinition();
aGenericBeanDefinition.setBeanClass(A.class);
aGenericBeanDefinition.setParentName("parent");
applicationContext.registerBeanDefinition("a",aGenericBeanDefinition);
GenericBeanDefinition bGenericBeanDefinition = new GenericBeanDefinition();
bGenericBeanDefinition.setBeanClass(B.class);
bGenericBeanDefinition.setParentName("parent");
applicationContext.registerBeanDefinition("b",bGenericBeanDefinition);
因为有些BeanDefinition需要去“继承”父BeanDefinition中的内容,所以在每个BeanDefinition来做处理的时候,都需要来判断一下,
是否满足条件能够去创建得到一个Bean,不止一个地方用到。
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
是不管你有没有父BeanDefinition,这里都会来尝试获取得到BeanDefinition中所有的属性信息。
合并的步骤:
创建一个新的RootBeanDefinition,先把父BeanDefinition中的信息放进去,然后再将子BeanDefinition的信息放进去。
子BeanDefinition中没有设置,那么继承父BeanDefinition的属性;如果自己来进行设置了,那么使用当前的BeanDefinition中的属性。
但是比较诡异的情况是,第一次来进行获取的时候,mergedBeanDefinitions居然是有合并的值的。那么就说明之前已经被设置了值的。
那么什么情况下才会被设置值呢?看一下mergedBeanDefinitions的put方法,打上断点,在哪里被调用的即可。
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
在这里就开始调用了,那么这里在干什么?为什么要来提前来进行判断呢?
根据上面的思路,可能是子BeanDefinition中没有,但是父BeanDefinition中可能来进行设置了。
因为在BeanDefinition中,也有一个属性:beanClass,这里也有可能是来继承父BeanDefinition的,所以这里也需要对每个beanClass来做一个判断。
这个在BeanDefinition的介绍中已经介绍过了,这里直接看一下代码接口:
RootBeanDefinition mbd = 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;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
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;
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
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);
}
// 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());
}
// 合并完成之后,这里会有判断说明
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
总结一下合并使用到的地方:
1、BeanDefinitionRegistryPostProcessor执行的时候需要来进行合并一次;
2、ImportBeanDefinitionRegistrar在这个地方也会来合并一次;
3、BeanFactoryPostProcessor会来合并一次;
....
所以在之后逻辑流程中,做了大量的判断逻辑来进行处理。
所以在实例化之前,已经做了BeanDefinition的合并。并不是说在之后才来做的处理。
但是有一个步骤中做了一个说明:
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
clearMergedBeanDefinition(beanName);
this.alreadyCreated.add(beanName);
}
}
}
}
protected void clearMergedBeanDefinition(String beanName) {
super.clearMergedBeanDefinition(beanName);
this.mergedBeanDefinitionHolders.remove(beanName);
}
那么看一下注释:在创建Bean的时候,需要重新来进行合并Bean,因为可能在中间的某个过程中修改了一些元数据。
我们可以在中间流程中来进行处理BeanDefinition,来进行修改一下。