Spring IoC 依赖查找

单一类型依赖查找

单一类型依赖查找接口 - 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)

private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) {
     ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
//        Iterable<String> stringIterable = objectProvider;
//        for (String string : stringIterable) {
//            System.out.println(string);
//        }
     // Stream -> Method reference
     objectProvider.stream().forEach(System.out::println);
 }

 private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) {
     ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
     User user = userObjectProvider.getIfAvailable(User::createUser);
     System.out.println("当前 User 对象:" + user);
 }

 @Bean
 @Primary
 public String helloWorld() { // 方法名就是 Bean 名称 = "helloWorld"
     return "Hello,World";
 }

 @Bean
 public String message() {
     return "Message";
 }

 private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
     ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
     System.out.println(objectProvider.getObject());
 }

集合类型依赖查找

集合类型依赖查找接口 - 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>)

层次性依赖查找

层次性依赖查找接口 - HierarchicalBeanFactory

• 双亲 BeanFactory:getParentBeanFactory()

• 层次性查找

  • 根据 Bean 名称查找
    • 基于 containsLocalBean 方法实现
  • 根据 Bean 类型查找实例列表
    • 单一类型:BeanFactoryUtils#beanOfType
    • 集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
  • 根据 Java 注解查找名称列表
    • BeanFactoryUtils#beanNamesForTypeIncludingAncestors
private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) {
     BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
     if (parentBeanFactory instanceof HierarchicalBeanFactory) {
         HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
         if (containsBean(parentHierarchicalBeanFactory, beanName)) {
             return true;
         }
     }
     return beanFactory.containsLocalBean(beanName);
 }

 private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {
     System.out.printf("当前 BeanFactory[%s] 是否包含 Local Bean[name : %s] : %s\n", beanFactory, beanName,
             beanFactory.containsLocalBean(beanName));
 }

延迟依赖查找

Bean 延迟依赖查找接口
• org.springframework.beans.factory.ObjectFactory

• org.springframework.beans.factory.ObjectProvider

  • Spring 5 对 Java 8 特性扩展
    • 函数式接口
      • getIfAvailable(Supplier) • ifAvailable(Consumer)
      • Stream 扩展 - stream()

安全依赖查找

依赖查找安全性对比

依赖查找类型代表实现是否安全
单一类型查找BeanFactory#getBean
ObjectFactory#getObject
ObjectProvider#getIfAvailable
集合类型查找ListableBeanFactory#getBeansOfType
ObjectProvider#stream
public class TypeSafetyDependencyLookupDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 TypeSafetyDependencyLookupDemo 作为配置类(Configuration Class)
        applicationContext.register(TypeSafetyDependencyLookupDemo.class);
        // 启动应用上下文
        applicationContext.refresh();

        // 演示 BeanFactory#getBean 方法的安全性
        displayBeanFactoryGetBean(applicationContext);
        // 演示 ObjectFactory#getObject 方法的安全性
        displayObjectFactoryGetObject(applicationContext);
        // 演示 ObjectProvider#getIfAvaiable 方法的安全性
        displayObjectProviderIfAvailable(applicationContext);

        // 演示 ListableBeanFactory#getBeansOfType 方法的安全性
        displayListableBeanFactoryGetBeansOfType(applicationContext);
        // 演示 ObjectProvider Stream 操作的安全性
        displayObjectProviderStreamOps(applicationContext);

        // 关闭应用上下文
        applicationContext.close();
    }

    private static void displayObjectProviderStreamOps(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectProviderStreamOps", () -> userObjectProvider.forEach(System.out::println));
    }

    private static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory beanFactory) {
        printBeansException("displayListableBeanFactoryGetBeansOfType", () -> beanFactory.getBeansOfType(User.class));
    }

    private static void displayObjectProviderIfAvailable(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectProviderIfAvailable", () -> userObjectProvider.getIfAvailable());
    }

    private static void displayObjectFactoryGetObject(AnnotationConfigApplicationContext applicationContext) {
        // ObjectProvider is ObjectFactory
        ObjectFactory<User> userObjectFactory = applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectFactoryGetObject", () -> userObjectFactory.getObject());
    }

    public static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
        printBeansException("displayBeanFactoryGetBean", () -> beanFactory.getBean(User.class));
    }

    private static void printBeansException(String source, Runnable runnable) {
        System.err.println("==========================================");
        System.err.println("Source from :" + source);
        try {
            runnable.run();
        } catch (BeansException exception) {
            exception.printStackTrace();
        }
    }
}

注意:层次性依赖查找的安全性取决于其扩展的单一或集合类型的 BeanFactory 接口

内建可查找的依赖

AbstractApplicationContext 内建可查找的依赖

Bean 名称Bean 实例使用场景
environmentEnvironment 对象外部化配置以及 Profiles
systemPropertiesjava.util.Properties 对象Java 系统属性
systemEnvironmentjava.util.Map 对象操作系统环境变量
messageSourceMessageSource 对象国际化文案
lifecycleProcessorLifecycleProcessor 对象Lifecycle Bean 处理器
applicationEventMulticasterApplicationEventMulticaster 对 象Spring 事件广播器

注解驱动 Spring 应用上下文内建可查找的依赖

Bean 名称Bean 实例使用场景
org.springframework.context.annotation.internalConfigurationAnnotationProcessorConfigurationClassPostProcessor 对象处理 Spring 配置类
org.springframework.context.annotation.internalAutowiredAnnotationProcessorAutowiredAnnotationBeanPostProcessor 对象处理 @Autowired 以及 @Value 注解
org.springframework.context.annotation.internalCommonAnnotationProcessorCommonAnnotationBeanPostProcessor 对象(条件激活)处理 JSR-250 注解,如 @PostConstruct 等
org.springframework.context.event.internalEventListenerProcessorEventListenerMethodProcessor 对象处理标注 @EventListener 的Spring 事件监听方法
org.springframework.context.event.internalEventListenerFactoryDefaultEventListenerFactory 对 象@EventListener 事件监听方法适配为 ApplicationListener
org.springframework.context.annotation.internalPersistenceAnnotationProcessorPersistenceAnnotationBeanPostProcessor 对象(条件激活)处理 JPA 注解场景

依赖查找中的经典异常

BeansException 子类型

异常类型触发条件(举例)场景举例
NoSuchBeanDefinitionException当查找 Bean 不存在于 IoC 容器时BeanFactory#getBean、ObjectFactory#getObject
NoUniqueBeanDefinitionException类型依赖查找时,IoC 容器存在多个 Bean 实例BeanFactory#getBean(Class)
BeanInstantiationException当 Bean 所对应的类型非具体类时BeanFactory#getBean
BeanCreationException当 Bean 初始化过程中Bean 初始化方法执行异常时
BeanDefinitionStoreException当 BeanDefinition 配置元信息非法时XML 配置资源无法打开时

面试题

ObjectFactory 与 BeanFactory 的区别?
答:ObjectFactory 与 BeanFactory 均提供依赖查找的能力。
不过 ObjectFactory 仅关注一个或一种类型的 Bean 依赖查找,并且自身不具备依赖查找的能力,能力则由 BeanFactory 输出。
BeanFactory 则提供了单一类型、集合类型以及层次性等多种依赖查找方式。

BeanFactory.getBean 操作是否线程安全?
答:BeanFactory.getBean 方法的执行是线程安全的,超过过程中会增加互斥锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值