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
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 實時查找
-
根據 Bean 名稱 + 類型查找:getBean(String, Class)
3. 集合類型依賴查找
集合類型依賴查找接口 - ListableBeanFactory
-
根據 Bean 類型查找
- 獲取同類型 Bean 名稱列表
- getBeanNamesForType(Class)
- Spring 4.2 getBeanNamesForType(ResolvableType)
- 獲取同類型 Bean 實例列表
- getBeansOfType(Class) 以及重載方法
- 獲取同類型 Bean 名稱列表
-
通過注解類型查找
-
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
- 根據 Bean 名稱查找
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依賴來源》章節中繼續討論。