扯淡 Spring BeanDefinition

相關文章java

大多數的方法都能從它的名字知道它是幹啥的、都能在 XML 配置文件中找到對應的配置項緩存

大部分的實現是落在 AbstractBeanDefinition 中、裏面的邏輯也並非特別的複雜、畢竟只是一些 get/set 方法架構

對於它的三個子類 GenericBeanDefinition RootBeanDefinition ChildBeanDefinition 其實本質上來講、它們並沒有太大的區別、它們都繼承了 AbstractBeanDefinition 、在它們各自的類中、並無什麼太大的特殊的邏輯、某種程度上來講、它們能夠說是差異很是小的框架

咱們在 Spring 容器初始化的時候、讀取 XML 配置文件並註冊 BeanDefinition 、這個BeanDefinition 是子類中的哪一個類呢ide

// 解釋 bean 標籤的時候
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
複製代碼
public static AbstractBeanDefinition createBeanDefinition( @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

   GenericBeanDefinition bd = new GenericBeanDefinition();
   bd.setParentName(parentName);
   if (className != null) {
      if (classLoader != null) {
         bd.setBeanClass(ClassUtils.forName(className, classLoader));
      }
      else {
         bd.setBeanClassName(className);
      }
   }
   return bd;
}
複製代碼

最終它會落到這個工具類裏面、建立的都是 GenericBeanDefinition工具

而在 BeanDefinitionRegistry 的實現類中、都是如此存儲的post

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
複製代碼

咱們也是可使用其餘的 BeanDefinition 的子類註冊ui

而咱們在 getBean 的流程中的時候、當咱們沒法在三級緩存中獲取到 bean 的時候、就開始了建立 bean 的流程、這個時候、就要從 beanDefinition 中獲取相關信息建立 beanthis

final 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));
	}
複製代碼

咱們能夠在 AbstractBeanFactory 中找到spa

private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
複製代碼

能夠看到 Map 中的 value 的類型是 RootBeanDefinition

若是你在定義中存在了父子 bean、或者更加具體的說、就是在 BeanDefinition 中、你的parentName 不爲空、做爲子 bean、你就要合成父 bean 的一些屬性

synchronized (this.mergedBeanDefinitions) {
    RootBeanDefinition mbd = null;
    RootBeanDefinition previous = null;
    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;
    ......................
    // Deep copy with overridden values.
    mbd = new RootBeanDefinition(pbd);
    mbd.overrideFrom(bd);
    }

    ........

    if (containingBd == null && isCacheBeanMetadata()) {
    this.mergedBeanDefinitions.put(beanName, mbd);
    }
    }
    return mbd;
}
複製代碼

貌似到目前爲止、咱們仍是沒有看到 ChildBeanDefinition 使用的場景

貌似確實沒啥用是吧在整一個 Spring 框架中、個人版本 5.2

可是呢、其實咱們能夠手動的建立一個 BeanDefiniton 註冊給 Spring

DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Company.class);
rootBeanDefinition.getPropertyValues().add("name", "XX");
rootBeanDefinition.getPropertyValues().add("numberOfPeople", "1000");
defaultListableBeanFactory.registerBeanDefinition("rootCompany", rootBeanDefinition);

ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("rootCompany");
defaultListableBeanFactory.registerBeanDefinition("childCompany", childBeanDefinition);

System.out.println(defaultListableBeanFactory.getBean("rootCompany"));
System.out.println(defaultListableBeanFactory.getBean("childCompany"));
System.out.println(defaultListableBeanFactory.getBean("rootCompany") == defaultListableBeanFactory.getBean("childCompany"));
複製代碼

其實在 RootBeanDefinition 和 ChildBeanDefinition 中咱們看到註釋說、其實首選是 GenericBeanDefinition 、由於 RootBeanDefinition 不可以指定 parentName、而 ChildBeanDefinition 必須有 parentName、這在使用上是很是不靈活的

或許這就是 GenericBeanDefinition 出現的緣由吧

在 AbstractAutowireCapableBeanFactory#doCreateBean 中

在建立好了一個 bean 的時候(不完整的 bean ),會對 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 進行回調、這個時候是比加入第三級緩存以前早一點

defaultListableBeanFactory.addBeanPostProcessor(new MergedBeanDefinitionPostProcessor() {
   @Override
   public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
      System.out.println("beanName:" + beanName);
   }
});
複製代碼

此次必定?
相關文章
相關標籤/搜索