前書き
Springソースコードでは、beanDefinitionは最も重要な知識ポイントの1つです。ソースコードでは、beanDefinitionorg.springframework.beans.factory.support.AbstractBeanFactory
#getMergedLocalBeanDefinitionをマージするためのマージ操作があります。
mergeBeanDefinitionについて説明する前に、概念があります。最初に明確にする必要があります。つまり、初期バージョンでは、rootBeanDefinitionとchildBeanDefinitionの概念があります。簡単に言うと、beanDefinitionのプロパティを継承できるということです。たとえば、一部のパブリックデータをrootBeanDefinitionに配置すると、子beanDefinitionはrootBeanDefinitionを直接継承できます。複数の子BeanDefinitionsは、独自のbeanDefinitionにパブリック属性を複数回設定する必要はありません。したがって、mergeBeanDefinitionはと互換性があると思います。古いバージョンのrootBeanDefinitionを実行してから、プロセスを実行します
現在のソースコードでは、自動スキャンによって取得されたbeanDefinitionは、genericBeanDefinitionのサブクラスであるScannedGenericBeanDefinitionです。元のrootBeanDefinitionとchildBeanDefinitionを処理するにはどうすればよいですか?
応用
次の例は私が書いたデモです
@Configuration
@ComponentScan("com.spring.study.beandefinition")
public class BeanDefinitionConfig {
}
public class RootBeanEntity {
private String name;
private String type;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void testRoot() {
System.out.println("name:" + name + "\t" + "type:" + type);
}
}
public class UserEntity {
private String name;
private String type;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void test() {
System.out.println(name + "===" + type);
}
}
@Component
public class UserService {
}
public class BeanDefinitionTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(BeanDefinitionConfig.class);
/**
* 初始化一个rootBeanDefinition
*/
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.getPropertyValues().add("name","testName");
rootBeanDefinition.getPropertyValues().add("type","typeTest");
rootBeanDefinition.setBeanClass(RootBeanEntity.class);
ac.registerBeanDefinition("rootBeanEntity",rootBeanDefinition);
/**
* 将genericBeanDefinition的父bd指向上面的rootBeanDefinition
* 如果在genericBeanDefinition中覆盖了父bd中的属性,在打印的时候,就会取覆盖的值,如果未覆盖,则使用父bd的
*/
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(UserEntity.class);
genericBeanDefinition.getPropertyValues().add("name","genBeanName");
genericBeanDefinition.setParentName("rootBeanEntity");
ac.registerBeanDefinition("userEntity",genericBeanDefinition);
ac.refresh();
ac.getBean(RootBeanEntity.class).testRoot();
ac.getBean(UserEntity.class).test();
System.out.println("===============================");
System.out.println("通过@Configuration和@ComponentScan注入的bean是不同的beanDefinition类型");
/**
* class org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition
* class org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
* AnnotatedGenericBeanDefinition
*
* spring在扫描bean的时候,将包下所有的.class扫描到之后,会为每个class创建一个ScannedGenericBeanDefinition,所以,@Component注解对应
* 的bean都是Scanned类型的
*
* 加了@Configuration注解的bean,是在ac.registry()的时候,添加到beanDefinitionMap的,这时候,使用的是 AnnotatedBeanDefinitionReaders
* 所以,对于配置类是AnnotatedGenericBeanDefinition
*/
System.out.println(ac.getBeanDefinition("userService").getClass());
System.out.println(ac.getBeanDefinition("userService").getClass().getSimpleName());
System.out.println(ac.getBeanDefinition("beanDefinitionConfig").getClass());
System.out.println(ac.getBeanDefinition("beanDefinitionConfig").getClass().getSimpleName());
}
}
最終的な印刷結果は次のとおりです。
name:testName type:typeTest
genBeanName===typeTest
===============================
通过@Configuration和@ComponentScan注入的bean是不同的beanDefinition类型
class org.springframework.context.annotation.ScannedGenericBeanDefinition
ScannedGenericBeanDefinition
class org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition
Process finished with exit code 0
ソースコード
/**
* 这里大致的意思是:
* 1.在beanDefinition进行了合并之后,会存入到mergedBeanDefinitions这个集合中
* 2.如果从map中获取到了合并之后的bd,那就不需要再次进行解析了
* 3.如果获取不到,就重走一遍merge的步骤
* @param beanName
* @return
* @throws BeansException
*/
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) {
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;
// Check with full lock now in order to enforce the same merged instance.
//1.containingBd 这个参数从上层调用过来,在代码中写死的null;如果为null,就从map中判断一下,是否已经存在
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
/**
* 在5.2之后的源码中,这里的判断加了一个stale的判断,这个标识的意思是:定义是否需要合并bean
*
* 这里的mbd变量需要注意:
* 不管bd是RootBeanDefinition还是GenericBeanDefinition,都会强转成RootBeanDefinition(mbd)
*/
if (mbd == null) {
/**
* 2.判断当前bd是否有设置parentName
* 如果当前bd没有设置parentName,我们姑且可以认为,这个bd就是父bd
* 下面的判断可以看到:如果bd是RootBeanDefinition,就clone一个新的bd
* 如果bd不是RootBeanDefinition,那就根据bd,new一个RootBeanDefinition对象
*
*/
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.
/**
* 3.如果进入到这里,说明当前bd设置了parentName属性
*/
BeanDefinition pbd;
try {
/**
* 3.1 这里的意思,我的理解是:递归获取到bd的parent,直到获取到最后一个bd
*/
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
/**
* 3.2 如果beanName和parentBeanName一样?这个场景是什么?
* 根据parentName获取到parentBeanDefinition
*/
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 an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
/**
* 下面的两行代码中,
* 第一行代码是:根据父bd new一个RootBeanDefinition
* 第二行代码是:将bd(可以理解为子bd)的属性赋值到mbd中,子类的属性会覆盖父类的属性,
* 方法中,就是通过一堆的set进行属性覆盖
*
* 如果bd本身就是RootBeanDefinition,那就不会执行这里的逻辑
*/
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
/**
* 如果bd没有设置scope,默认是singleton
*/
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.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()) {
/**
* 将合并后的bd存入到map集合中,spring在后面初始化bean的流程中,就无需再次merge,直接从这个map中根据beanName获取即可
*/
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
ここでのコメントも明確なので、あまり説明しません。大きく2つのケースに分けることができます
。1。現在のbeanDefinitionの親属性が設定されていない場合、それはrootBeanDefinitionであり、他の処理は必要ありません。
。2 。現在のbeanDefinitionが親プロパティを設定する場合、最初に親beanDefinitionのプロパティを取得してから、独自のbeanDefinitionのプロパティを親beanDefinitionに上書きする必要があります。3
。最後に、取得したrootBeanDefinitionをキャッシュに保存します。
総括する
要約すると、
1。現在の子beanDefinitionにrootBeanDefinitionが設定されている場合、子beanDefinitionが初期化されると、rootBeanDefinitionの属性がマージされ、一連のsetメソッドを介して、子beanDefinitionの属性がオーバーライドされます。 rootBeanDefinitionの属性
現在のザ・beanDefinitionがparentBeanDefinition属性を設定しない場合は2、それはあなたが唯一の属性カバレッジの問題を考慮せず、beanDefinitionに基づいてrootBeanDefinitionを作成する必要があるので、現在のbeanDefinition自体は、rootBeanDefinitionであることを意味
3 。マージ後、マージ後のbeanDefinitionはコレクションキャッシュに配置されます。BeanDefinitionをマージするためのスプリングソースコードには複数の場所があります。キャッシュに配置された後は、毎回マージする必要はありません
。4したがって、mergeBeanDefinitionのこの操作は、元のバージョンのrootBeanDefinitionおよびchildBeanDefinitionと互換性があると思います。設定方法は、卒業して作業した後、rootBeanDefinitionおよびchildBeanDefinitionを介してプロパティを設定するプロジェクトに遭遇していません。