第五章:Spring IoC依赖查找

第五章:Spring IoC依赖查找(Dependency Lookup)

背景

传统 Java 技术中的依赖查找

  • 单一类型
    • JNDI - javax.naming.Context#lookup(javax.naming.Name)
    • JavaBeans - java.beans.beancontext.BeanContext
  • 集合类型
    • java.beans.beancontext.BeanContext
  • 层次性
    • java.beans.beancontext.BeanContext

单一类型依赖查找

  • 根据 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)

public class ObjectProviderDemo { // @Configuration 是非必须注解

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

        ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
        System.out.println(objectProvider.getObject());

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

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

集合类型依赖查找

  • 集合类型依赖查找接口 - 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 获取指定名称 + 标注类型
        • findAnnotationOnBean(String ,Class<? extends Annotation>)

层次性依赖查找

  • 层次性依赖查找接口 - HierarchicalBeanFactory
    • 双亲 BeanFactory : getParentBeanFactory()
    • 层次性查找
      • 根据 Bean 名称查找
        • 基于 containsLocalBean 方法实现
      • 根据 Bean 类型查找实例列表
        • 单一类型: BeanFactoryUtils#beanOfType
        • 集合类型: BeanFactoryUtils#beansOfTypeIncludingAncestors
      • 根据 Java 注解查找名称列表
        • BeanFactoryUtils#beanNamesForTypeIncludingAncestors

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 ObjectProviderDemo 作为配置类(Configuration Class)
        applicationContext.register(ObjectProviderDemo.class);

        // 1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListableBeanFactory
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        // 2. 设置 Parent BeanFactory
        HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
        beanFactory.setParentBeanFactory(parentBeanFactory);
    }

    private static ConfigurableListableBeanFactory createParentBeanFactory() {
        // 创建 BeanFactory 容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // XML 配置文件 ClassPath 路径
        String location = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载配置
        reader.loadBeanDefinitions(location);
        return beanFactory;
    }
public interface ConfigurableListableBeanFactory
        extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {}

public interface ListableBeanFactory extends BeanFactory {
    int getBeanDefinitionCount();
    String[] getBeanDefinitionNames();
}

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
    void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
    void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
}

public interface HierarchicalBeanFactory extends BeanFactory {
    BeanFactory getParentBeanFactory();
    boolean containsLocalBean(String name);
}
    // 依赖查找也有双亲委派
    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);
    }

延迟依赖查找

  • Bean 延迟依赖查找接口
    • org.springframework.beans.factory.ObjectFactory
    • org.springframework.beans.factory.ObjectProvider
      • ObjectFactory 的子类
      • Spring 5 对 Java 8 的特性扩展
      • 函数式接口
        • T getIfAvailable(Supplier )
        • void ifAvailable(Consumer )
      • Stream 扩展
        • Stream stream()

ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
User user = userObjectProvider.getIfAvailable(User::createUser);
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
objectProvider.stream().forEach(System.out::println);

安全依赖查找

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

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

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();
        }
    }
}

内建可查找的依赖

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.internalCommonAnnotationProcessorCommonAnnotationBeanProcessor 对象(条件激活)处理 JSR-250 注解,如 @PostContruct
org.springframework.context.event.internalEventListenerProcessorEventListenerMethodProcessor 对象处理标注 @EventListener 的 Spring 事件监听方法
org.springframework.context.event.internalEventListenerFactoryDefaultEventListenerFactory 对象@EventListener 事件监听方法适配为 ApplicationListener
org.springframework.context.annotation.internalPersistenceAnnotationProcessorPersistenceAnnotationBeanPostProcessor 对象(条件激活)处理 JPA 注解

org.springframework.context.annotation.AnnotationConfigUtils

依赖查找中的常见异常

BeansException 子类型

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

// BeanInstantiationException

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 BeanDefinition Bean Class 是一个 CharSequence 接口
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CharSequence.class);
        applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());

        // 启动应用上下文
        applicationContext.refresh();

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

// BeanCreationException

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 BeanDefinition Bean Class 是一个 POJO 普通类,不过初始化方法回调时抛出异常
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(POJO.class);
        applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());

        // 启动应用上下文
        applicationContext.refresh();

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

    static class POJO implements InitializingBean {

        @PostConstruct // CommonAnnotationBeanPostProcessor
        public void init() throws Throwable {
            throw new Throwable("init() : For purposes...");
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            throw new Exception("afterPropertiesSet() : For purposes...");
        }
    }

总结

  1. ObjectFactory 与 BeanFactory 的区别?

BeanFactory 是 Spring 底层的 IoC 容器,提供了单一类型、集合类型、层次性等多种依赖查找方式;

ObjectFactory 仅关注一种类型的 Bean 的依赖查找,并且底层依然是使用 ioc 容器进行依赖查找然后输出;

ObjectProvider 继承 ObjectFactory ;

  1. BeanFactory.getBean 操作是否线程安全?

是线程安全的,操作过程中会增加互斥锁;

// DefaultListableBeanFactory

	private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				if (condition.test(this.manualSingletonNames)) {
					Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
					action.accept(updatedSingletons);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		}
		else {
			// Still in startup registration phase
			if (condition.test(this.manualSingletonNames)) {
				action.accept(this.manualSingletonNames);
			}
		}
    }
    
			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);
				}
            }

		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames);
				updatedDefinitions.remove(beanName);
				this.beanDefinitionNames = updatedDefinitions;
			}
		}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值