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,来进行修改一下。

posted @ 2022-08-25 00:22  雩娄的木子  阅读(38)  评论(0编辑  收藏  举报