Spring(05)IoC 依賴查找


Spring(05)IoC 依賴查找

Spring 核心編程思想目錄:https://www.cnblogs.com/binarylei/p/12290153.html

1. 依賴查找的今世前生

  • 單一類型依賴查找

    • JNDI:javax.naming.Context
    • JavaBeans :java.beans.beancontext.BeanContext
  • 集合類型依賴查找

    • java.beans.beancontext.BeanContext
  • 層次性依賴查找

    • java.beans.beancontext.BeanContextServices

tomcat架構分析 (JNDI配置)

tomcat架構分析 (JNDI體系綁定)

2. 單一類型依賴查找

單一類型依賴查找接口 - BeanFactory

  • 根據 Bean 名稱查找

    • getBean(String)
    • Spring 2.5 覆蓋默認參數:getBean(String, Object...)
  • 根據Bean 類型查找

    • Bean 實時查找
      • Spring 3.0 getBean(Class)
      • Spring 4.1 覆蓋默認參數:getBean(Class, Object...)
    • Spring 5.1 Bean 延遲查找
      • getBeanProvider(Class)
      • getBeanProvider(ResolvableType)
  • 根據 Bean 名稱 + 類型查找:getBean(String, Class)

3. 集合類型依賴查找

集合類型依賴查找接口 - ListableBeanFactory

  • 根據 Bean 類型查找

    • 獲取同類型 Bean 名稱列表
      • getBeanNamesForType(Class)
      • Spring 4.2 getBeanNamesForType(ResolvableType)
    • 獲取同類型 Bean 實例列表
      • getBeansOfType(Class) 以及重載方法
  • 通過注解類型查找

    • Spring 3.0 獲取標注類型Bean 名稱列表

      • getBeanNamesForAnnotation(Class<? extends Annotation>)
    • Spring 3.0 獲取標注類型Bean 實例列表

      • getBeansWithAnnotation(Class<? extends Annotation>)
    • Spring 3.0 獲取指定名稱+ 標注類型Bean 實例

      • findAnnotationOnBean(String, Class<? extends Annotation>)

思考: getBeanNamesForType 和 getBeansOfType 區別?

getBeanNamesForType 是根據 BeanDefinition 或 FactoryBean#getObjectType 判斷對象類型,不會進行對象的初始化。而 getBeansOfType 可能將 bean 提前初始化,導致 bean 初始化不完全。

@Override
public String[] getBeanNamesForType(@Nullable Class<?> type) {
    return getBeanNamesForType(type, true, true);
}

@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException {
    return getBeansOfType(type, true, true);
}
@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, 
        boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
    String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    Map<String, T> result = new LinkedHashMap<>(beanNames.length);
    for (String beanName : beanNames) {
        // 最大的不同在這里:getBean(beanName) 實例化對象
        Object beanInstance = getBean(beanName);
        if (!(beanInstance instanceof NullBean)) {
            result.put(beanName, (T) beanInstance);
        }
    }
    return result;
}

說明: 無論是 getBeanNamesForType 還是 getBeansOfType 都會通過調用 getBeansOfType(type, true, true) 方法,根據類型查找 bean。不同的是 getBeansOfType 在查找到對應的 beanNames 后會調用 getBean(beanName) 實例化對象。

4. 層次性依賴查找

層次性依賴查找接口 - HierarchicalBeanFactory

  • 雙親 BeanFactory:getParentBeanFactory()
  • 層次性查找
    • 根據 Bean 名稱查找
      • 基於 containsLocalBean 方法實現
    • 根據 Bean 類型查找實例列表
      • 單一類型:BeanFactoryUtils#beanOfType
      • 集合類型:BeanFactoryUtils#beansOfTypeIncludingAncestors
    • 根據 Java 注解查找名稱列表
      • BeanFactoryUtils#beanNamesForTypeIncludingAncestors

5. 延遲依賴查找

Bean 延遲依賴查找接口

  • org.springframework.beans.factory.ObjectFactory
  • org.springframework.beans.factory.ObjectProvider
    • Spring 5 對 Java 8 特性擴展
    • 函數式接口
      • getIfAvailable(Supplier)
      • ifAvailable(Consumer)
    • Stream 擴展- stream()

6. 安全依賴查找

依賴查找類型 代表實現 是否安全
單一類型查找 BeanFactory#getBean
ObjectFactory#getObject
ObjectProvider#getIfAvailable
集合類型查找 ListableBeanFactory#getBeansOfType
ObjectProvider#stream

注意:層次性依賴查找的安全性取決於其擴展的單一或集合類型的 BeanFactory 接口。

7. 內建可查找的依賴

AbstractApplicationContext 內建可查找的依賴

Bean 名稱 Bean 實例 使用場景
environment Environment 對象外部化配置以及Profiles
systemProperties java.util.Properties 對象Java 系統屬性
systemEnvironment java.util.Map 對象操作系統環境變量
messageSource MessageSource 對象國際化文案
lifecycleProcessor LifecycleProcessor 對象Lifecycle Bean 處理器
applicationEventMulticaster ApplicationEventMulticaster 對象Spring 事件廣播器

注解驅動Spring 應用上下文內建可查找的依賴(部分)

Bean 名稱 Bean 實例 使用場景
org.springframework.context.annotation
.internalConfigurationAnnotationProcessor
ConfigurationClassPostProcessor 處理Spring 配置類
org.springframework.context.annotation
.internalAutowiredAnnotationProcessor
AutowiredAnnotationBeanPostProcessor 處理@Autowired 以及@Value注解
org.springframework.context.annotation
.internalCommonAnnotationProcessor
CommonAnnotationBeanPostProcessor (條件激活)處理JSR-250 注解,如@PostConstruct 等
org.springframework.context.event
.internalEventListenerProcessor
EventListenerMethodProcessor 處理標注@EventListener 的Spring 事件監聽方法
org.springframework.context.event
.internalEventListenerFactory
DefaultEventListenerFactory @EventListener 事件監聽方法適配為ApplicationListener
org.springframework.context.annotation
.internalPersistenceAnnotationProcessor
PersistenceAnnotationBeanPostProcessor (條件激活)處理JPA 注解場景

8. 依賴查找中的經典異常

異常類型 觸發條件(舉例) 場景舉例
NoSuchBeanDefinitionException 當查找Bean 不存在於IoC 容器時 BeanFactory#getBean
ObjectFactory#getObject
NoUniqueBeanDefinitionException 類型依賴查找時,IoC 容器存在多個Bean 實例 BeanFactory#getBean(Class)
BeanInstantiationException 當Bean 所對應的類型非具體類時 BeanFactory#getBean
BeanCreationException 當Bean 初始化過程中 Bean 初始化方法執行異常時
BeanDefinitionStoreException 當BeanDefinition 配置元信息非法時 XML 配置資源無法打開時

9. 面試題精選

ObjectFactory 與 BeanFactory 的區別?

答:ObjectFactory 與 BeanFactory 均提供依賴查找的能力。

不過 ObjectFactory 僅關注一個或一種類型的 Bean 依賴查找,並且自身不具備依賴查找的能力,能力則由 BeanFactory 輸出。BeanFactory 則提供了單一類型、集合類型以及層次性等多種依賴查找方式。

BeanFactory.getBean 操作是否線程安全?

答:BeanFactory.getBean 方法的執行是線程安全的,實現過程中會增加互斥鎖。

Spring 依賴查找與注入在來源上的區別?

答:答案將《Spring IoC依賴注入》以及《Spring IoC依賴來源》章節中繼續討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM