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依赖来源》章节中继续讨论。

猜你喜欢

转载自www.cnblogs.com/binarylei/p/12297797.html