91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么理解容器DefaultListableBeanFactory

發布時間:2021-11-02 16:11:45 來源:億速云 閱讀:256 作者:iii 欄目:web開發

這篇文章主要介紹“怎么理解容器DefaultListableBeanFactory”,在日常操作中,相信很多人在怎么理解容器DefaultListableBeanFactory問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么理解容器DefaultListableBeanFactory”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

 1.DefaultListableBeanFactory

要說 XmlBeanFactory 就不得不先說它的父類 DefaultListableBeanFactory,因為 XmlBeanFactory  中的大部分功能實際上在 DefaultListableBeanFactory 中就已經提供好了,XmlBeanFactory 只是對 IO  流的讀取做了一些定制而已。

DefaultListableBeanFactory 是一個完整的、功能成熟的 IoC 容器,如果你的需求很簡單,甚至可以直接使用  DefaultListableBeanFactory,如果你的需求比較復雜,那么通過擴展 DefaultListableBeanFactory  的功能也可以達到,可以說 DefaultListableBeanFactory 是整個 Spring IoC 容器的始祖。

我們先來看一下 DefaultListableBeanFactory 的繼承關系:

怎么理解容器DefaultListableBeanFactory

從這張類的關系圖中可以看出,DefaultListableBeanFactory 實際上也是一個集大成者。在 Spring 中,針對 Bean  的不同操作都有不同的接口進行規范,每個接口都有自己對應的實現,最終在 DefaultListableBeanFactory  中將所有的實現匯聚到一起。從這張類的繼承關系圖中我們大概就能感受到 Spring 中關于類的設計是多么厲害,代碼耦合度非常低。

這些類,在本系列后面的介紹中,大部分都會涉及到,現在我先大概介紹一下每個類的作用,大家先混個臉熟:

  1. BeanFactory:這個接口看名字就知道是一個 Bean 的工廠,BeanFactory 接口定義了各種獲取 Bean 的方法、判斷 Bean  是否存在、判斷 Bean 是否單例等針對 Bean 的基礎方法。

  2. ListableBeanFactory:這個接口繼承自 BeanFactory,在 BeanFactory 的基礎上,擴展了 Bean  的查詢方法,例如根據類型獲取 BeanNames、根據注解獲取 BeanNames、根據 Bean 獲取注解等。

  3. AutowireCapableBeanFactory:該接口繼承自 BeanFactory,在 BeanFactory 的基礎上,提供了 Bean  的創建、配置、注入、銷毀等操作。有時候我們需要自己手動注入 Bean 的時候,可以考慮通過實現該接口來完成。AutowireCapableBeanFactory  在 Spring Security 中有一個重要的應用就是 ObjectPostProcessor,這個松哥將在 ??Spring Security  系列中和大家詳細介紹。

  4. HierarchicalBeanFactory:該接口繼承自 BeanFactory,并在 BeanFactory 基礎上添加了獲取 parent  beanfactory 的方法。

  5. SingletonBeanRegistry:這個接口定義了對單例 Bean 的定義以及獲取方法。

  6. ConfigurableBeanFactory:這個接口主要定了針對 BeanFactory 的各種配置以及銷毀的方法。

  7. ConfigurableListableBeanFactory:這是 BeanFactory 的配置清單,這里定義了忽略的類型、接口,通過 Bean  的名稱獲取 BeanDefinition 、凍結 BeanDefinition 等。

  8. AliasRegistry:這個接口定義了對 alias 的注冊、移除、判斷以及查詢操作。

  9. SimpleAliasRegistry:這個類實現了 AliasRegistry 接口并實現了它里邊的方法,SimpleAliasRegistry 使用  ConcurrentHashMap 做載體,實現了對 alias 的注冊、移除判斷以及查詢操作。

  10. DefaultSingletonBeanRegistry:這個類基于 Java 中的集合,對 SingletonBeanRegistry  接口進行了實現。

  11. FactoryBeanRegistrySupport:該類繼承自 DefaultSingletonBeanRegistry,并在  DefaultSingletonBeanRegistry 的基礎上,增加了獲取 FactoryBean 類型、移除 FactoryBean  緩存的方法等等操作。

  12. AbstractBeanFactory:實現了 ConfigurableBeanFactory 接口并繼承自  FactoryBeanRegistrySupport,在 AbstractBeanFactory 中對 ConfigurableBeanFactory  中定義的方法進行了實現。

  13. AbstractAutowireCapableBeanFactory:該類繼承自 AbstractBeanFactory 并對  AutowireCapableBeanFactory 接口中定義的方法進行了落地實現。

  14. BeanDefinitionRegistry:這個接口繼承自 AliasRegistry 接口,并增加了一系列針對 BeanDefinition  的注冊、移除、查詢、判斷等方法。

  15. 最后的 DefaultListableBeanFactory 自然就具備了上面所有的功能。

上面的內容可能看的大家眼花繚亂,松哥這里通過幾個簡單實際的例子,來帶大家使用一下 DefaultListableBeanFactory  的功能,可能大家的理解就比較清晰了。

DefaultListableBeanFactory 作為一個集大成者,提供了非常多的功能,我們一個一個來看。

2.代碼改造

首先文章中一開始的三行代碼我們可以對其略加改造,因為我們已經說了 XmlBeanFactory 中的大部分功能實際上在  DefaultListableBeanFactory 中就已經提供好了,XmlBeanFactory 只是對 IO  流的讀取做了一些定制而已,文件的讀取主要是通過 XmlBeanDefinitionReader  來完成的(本系列前面文章已經講過),我們可以對文章一開始的三行代碼進行改造,以便更好的體現“XmlBeanFactory 中的大部分功能實際上在  DefaultListableBeanFactory 中就已經提供好了”:

ClassPathResource res=new ClassPathResource("beans.xml"); DefaultListableBeanFactory factory=new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(res); User user = factory.getBean(User.class); System.out.println("user = " + user);

使用前四行代碼代替 XmlBeanFactory,這樣 XmlBeanFactory 的功能是不是就很明確了?就是前四行代碼的功能。

3.動態注冊 Bean

動態注冊 Bean,這是 DefaultListableBeanFactory 的功能之一,不過準確來說應該是動態注冊 BeanDefinition  。

我們先來看一個簡單的例子:

DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory(); GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition(); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.add("username", "javaboy"); pvs.add("address", "www.javaboy.org"); userBeanDefinition.setPropertyValues(pvs); userBeanDefinition.setBeanClass(User.class); defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition); User user = defaultListableBeanFactory.getBean(User.class); System.out.println("user = " + user);

首先我們自己手動構建一個 DefaultListableBeanFactory 對象。當然也可以使用前面的 XmlBeanFactory。

然后再手動構建一個 GenericBeanDefinition。在前面的文章中,松哥和大家講過,現在默認使用的 BeanDefinition 就是  GenericBeanDefinition,所以這里我們自己也手動構建一個 GenericBeanDefinition。有了  GenericBeanDefinition 之后,我們設置相關的類和屬性。

接下來再將 userBeanDefinition 注冊到 defaultListableBeanFactory。注冊完成之后,我們就可以從  defaultListableBeanFactory 中獲取相應的 Bean 了。

這里說一句題外話,希望大家在閱讀本系列每一篇文章的時候,能夠將本系列前后文章聯系起來一起理解,這樣會有很多意料之外的收獲。例如上面的,我們既可以聲明一個  DefaultListableBeanFactory,也可以聲明一個 XmlBeanFactory,那你大概就能據此推斷出 XmlBeanFactory  的主要目的可能就是對資源文件進行讀取和注冊。

那么到底是怎么注冊的呢?我們來看一下 defaultListableBeanFactory.registerBeanDefinition  方法的定義:

@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)   throws BeanDefinitionStoreException {  Assert.hasText(beanName, "Bean name must not be empty");  Assert.notNull(beanDefinition, "BeanDefinition must not be null");  if (beanDefinition instanceof AbstractBeanDefinition) {   try {    ((AbstractBeanDefinition) beanDefinition).validate();   }   catch (BeanDefinitionValidationException ex) {    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,      "Validation of bean definition failed", ex);   }  }  BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);  if (existingDefinition != null) {   if (!isAllowBeanDefinitionOverriding()) {    throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);   }   else if (existingDefinition.getRole() < beanDefinition.getRole()) {    // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE    if (logger.isInfoEnabled()) {     logger.info("Overriding user-defined bean definition for bean '" + beanName +       "' with a framework-generated bean definition: replacing [" +       existingDefinition + "] with [" + beanDefinition + "]");    }   }   else if (!beanDefinition.equals(existingDefinition)) {    if (logger.isDebugEnabled()) {     logger.debug("Overriding bean definition for bean '" + beanName +       "' with a different definition: replacing [" + existingDefinition +       "] with [" + beanDefinition + "]");    }   }   else {    if (logger.isTraceEnabled()) {     logger.trace("Overriding bean definition for bean '" + beanName +       "' with an equivalent definition: replacing [" + existingDefinition +       "] with [" + beanDefinition + "]");    }   }   this.beanDefinitionMap.put(beanName, beanDefinition);  }  else {   if (hasBeanCreationStarted()) {    // Cannot modify startup-time collection elements anymore (for stable iteration)    synchronized (this.beanDefinitionMap) {     this.beanDefinitionMap.put(beanName, beanDefinition);     List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);     updatedDefinitions.addAll(this.beanDefinitionNames);     updatedDefinitions.add(beanName);     this.beanDefinitionNames = updatedDefinitions;     removeManualSingletonName(beanName);    }   }   else {    // Still in startup registration phase    this.beanDefinitionMap.put(beanName, beanDefinition);    this.beanDefinitionNames.add(beanName);    removeManualSingletonName(beanName);   }   this.frozenBeanDefinitionNames = null;  }  if (existingDefinition != null || containsSingleton(beanName)) {   resetBeanDefinition(beanName);  }  else if (isConfigurationFrozen()) {   clearByTypeCache();  } }

registerBeanDefinition 方法是在 BeanDefinitionRegistry  接口中聲明的,DefaultListableBeanFactory 類實現了 BeanDefinitionRegistry  接口,并實現了該方法,我們來看分析下該方法:

  • 首先對傳入的 beanDefinition 對象進行校驗,這也是注冊前的最后一次校驗,不過這個時候 BeanDefinition  對象已經到手了,所以這個校驗并非 XML 文件校驗,這里主要是對 methodOverrides 的校驗。

  • 接下來會根據 beanName 從 beanDefinitionMap 中獲取 BeanDefinition,看看當前 Bean  是否已經定義過了。beanDefinitionMap 是一個 Map 集合,這個集合中 key 是 beanName,value 是  BeanDefinition 對象。

  • 如果 BeanDefinition 已經存在了,那么接下來會判斷是否允許 BeanDefinition  覆蓋,如果不允許,就直接拋出異常(不知道小伙伴們有沒有印象,在松哥前面的 OAuth3 系列教程中,經常需要配置允許 BeanDefinition  的覆蓋,就是因為這個原因,公眾號【江南一點雨】后臺回復 OAuth3 獲取該教程),如果允許 BeanDefinition 的覆蓋,那就向  beanDefinitionMap 中再次存一次值,覆蓋之前的值。

  • 如果 BeanDefinition 不存在,那就直接注冊。直接注冊分兩種情況:項目已經運行了和項目還沒運行。

  • 如果項目已經運行,由于 beanDefinitionMap 是一個全局變量,可能存在并發問題,所以要加鎖處理。否則就直接注冊,所謂的注冊就是把對象存入  beanDefinitionMap 中,同時將 beanName 都存入 beanDefinitionNames 集合中。

這便是 registerBeanDefinition 方法的工作流程。

有小伙伴會說,這個方法從頭到尾都是 BeanDefinition,跟 Bean 有什么關系呢?

咋一看確實好像和 Bean 沒有直接關系。

其實這涉及到另外一個問題,就是 Bean 的懶加載。這個時候先把 BeanDefinition 定義好,等到真正調用 Bean 的時候,才會去初始化  Bean。我們可以在 User 類的構造方法中打印日志看下,如下:

public class User {     private String username;     private String address;      public User() {         System.out.println("--------user init--------");     }      @Override     public String toString() {         return "User{" +                 "username='" + username + '\'' +                 ", address='" + address + '\'' +                 '}';     }      public String getUsername() {         return username;     }      public void setUsername(String username) {         this.username = username;     }      public String getAddress() {         return address;     }      public void setAddress(String address) {         this.address = address;     } }

從下圖可以看到,當 BeanDefinition 注冊完成后,User 并沒有初始化,等到 getBean 方法被調用的時候,User  才初始化了。

怎么理解容器DefaultListableBeanFactory

需要注意的是,我們日常開發中使用的 ApplicationContext 并非懶加載

那么如果不想懶加載該怎么辦呢?當然有辦法。

4.提前注冊 Bean

在 DefaultListableBeanFactory 中還有一個 preInstantiateSingletons 方法可以提前注冊  Bean,該方法是在 ConfigurableListableBeanFactory 接口中聲明的,DefaultListableBeanFactory  類實現了 ConfigurableListableBeanFactory 接口并實現了接口中的方法:

@Override public void preInstantiateSingletons() throws BeansException {  if (logger.isTraceEnabled()) {   logger.trace("Pre-instantiating singletons in " + this);  }  // Iterate over a copy to allow for init methods which in turn register new bean definitions.  // While this may not be part of the regular factory bootstrap, it does otherwise work fine.  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);  // Trigger initialization of all non-lazy singleton beans...  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) {      final 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);    }   }  }  // Trigger post-initialization callback for all applicable beans...  for (String beanName : beanNames) {   Object singletonInstance = getSingleton(beanName);   if (singletonInstance instanceof SmartInitializingSingleton) {    final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;    if (System.getSecurityManager() != null) {     AccessController.doPrivileged((PrivilegedAction<Object>) () -> {      smartSingleton.afterSingletonsInstantiated();      return null;     }, getAccessControlContext());    }    else {     smartSingleton.afterSingletonsInstantiated();    }   }  } }

preInstantiateSingletons 方法的整體邏輯比較簡單,就是遍歷 beanNames,對符合條件的 Bean  進行實例化,而且大家注意,這里所謂的提前初始化其實就是在我們調用 getBean 方法之前,它自己先調用了一下 getBean。

我們可以在案例中手動調用該方法:

DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory(); GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition(); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.add("username", "javaboy"); pvs.add("address", "www.javaboy.org"); userBeanDefinition.setPropertyValues(pvs); userBeanDefinition.setBeanClass(User.class); defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition); defaultListableBeanFactory.preInstantiateSingletons(); User user = defaultListableBeanFactory.getBean(User.class); System.out.println("user = " + user);

此時在調用 getBean 方法之前,User 就已經初始化了,如下圖:

怎么理解容器DefaultListableBeanFactory

5.getBean

DefaultListableBeanFactory 中另外一個重量級方法就是 getBean 了。不過 getBean 方法的真正實現是在  DefaultListableBeanFactory 的父類 AbstractBeanFactory 中,具體的實現方法是  doGetBean,本來想和大家子在這里聊一聊這個問題,但是發現這是一個非常龐大的問題,BeanFactory 和 FactoryBean  都還沒和大家分享,所以這個話題我們還是暫且押后,一個點一個點來。

到此,關于“怎么理解容器DefaultListableBeanFactory”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

兴隆县| 乡宁县| 奇台县| 白水县| 旌德县| 永登县| 黄大仙区| 洛川县| 西乡县| 黄梅县| 德格县| 英德市| 平和县| 大厂| 奉节县| 铅山县| 玛纳斯县| 德州市| 陇西县| 抚顺县| 漳州市| 东明县| 波密县| 陵川县| 溆浦县| 临泽县| 六枝特区| 保亭| 武山县| 稻城县| 宣恩县| 龙州县| 万山特区| 鹤山市| 泰顺县| 平原县| 常熟市| 建宁县| 鹿泉市| 山丹县| 邵东县|