mergeBeanDefinitionの原則

前書き

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を介してプロパティを設定するプロジェクトに遭遇していません。

おすすめ

転載: blog.csdn.net/CPLASF_/article/details/115079290