5. IOC 依赖查找 Dependency Lookup

109 阅读12分钟

5. IOC 依赖查找 Dependency Lookup

5.1 依赖查找简介

Java 中其实已经有依赖查找了,java.beans.beancontext.BeanContext 就实现了依赖查找。

5.2 单一 Bean 的依赖查找

单一类型依赖查找接口 - BeanFactory

  • 根据 Bean 名称查找:getString(String)
  • 根据 Bean 类型查找
    • Bean 实时查找:getBean(Class)
    • Bean 延迟查找:getBeanProvider(Class) , getBeanProvider(ResolvableType)
  • 根据 Bean 名称 + 类型查找:getBean(String, Class)
  1. 延迟查找 getBeanProvider(Class)
public static void main(String[] args) {
    // 1.创建 ApplicationContext 容器, 使用注解配置
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    // 2.将当前类作为配置类
    applicationContext.register(ObjectProviderDemo.class);
    // 3.启动应用上下文
    applicationContext.refresh();

    // 4.依赖查找
    lookupByObjectProvider(applicationContext);

    // 5.停止应用上下文
    applicationContext.close();
}

@Bean
public String helloWorld() {
    return "HelloWorld";
}

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

    System.out.println(hello);
}

输出结果

HelloWorld

还有根据 Bean 名称或类型查找的方式,在前面章节已经多次使用,就不一一举例了。

// 补充: 源码分析,查找过程

// 补充: 什么是延迟查找,有什么用?参考课程评论

public interface BeanFactory {

	String FACTORY_BEAN_PREFIX = "&";

    // 获取名称为name的bean实例
	Object getBean(String name) throws BeansException;
    // 获取类型为requiredType的bean实例
	<T> T getBean(Class<T> requiredType) throws BeansException;
    // 获取名称为name,类型为requiredType的bean实例
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
	// 延迟查找
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	boolean containsBean(String name);

	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
	// 获取bean的所有别名
	String[] getAliases(String name);
}

5.3 列表 Bean 的依赖查找

集合型依赖查找接口 - ListableBeanFactory

  • 根据 bean 类型查找

    • 获取同类型 bean 名称列表
      • getBeanNameForType(Class)
      • getBeanNameForType(ResolvableType)
    • 获取同类型 bean 实例列表:getBeansOfType(Class)
  • 通过注解类型查找

    • 获取标记的 bean 名称列表:getBeanNamesForAnnotation(Class <? extends Annotation>)

    • 获取标记的 bean 实例列表:getBeanWithAnnotation(Class <? extends Annotation>)

    • 获取指定名称 + 标记的 bean 实例:findAnnotationOnBean(String, Class <? extends Annotation>)

ListableBeanFactory 就是 BeanFactory 接口的实现类,针对某一个类型去查找一个集合列表(Listable),ListableBeanFactory 规定了集合类型的依赖查找方法,源码如下所示

ListableBeanFactory.java
    
public interface ListableBeanFactory extends BeanFactory {
    boolean containsBeanDefinition(String beanName);
    
	int getBeanDefinitionCount();
    
	String[] getBeanDefinitionNames();
    // 获取type类型的bean名称列表
    String[] getBeanNamesForType(Class<?> type);
    // 获取type类型的bean名称列表
	String[] getBeanNamesForType(ResolvableType type);
    // 获取type类型的bean实例列表
	<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
    // 获取annotationType注解标记的bean名称列表
	String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
    // 获取annotationType注解标记的bean实例列表
	Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
    // 获取名称为beanName, annotationType注解标记的bean实例
	<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
			throws NoSuchBeanDefinitionException;
}

5.4 层次性依赖查找

层次性依赖查找接口 - HierarchicalBeanFactory

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

源码分析

HierarchicalBeanFactory 是 BeanFactory 的实现类,规定了层次性的依赖查找方法,源码如下所示:

public interface HierarchicalBeanFactory extends BeanFactory {

    // 获取父容器BeanFactory
	BeanFactory getParentBeanFactory();

    // 查看当前BeanFactory是否包含bean,忽略父容器BeanFactory中的bean
	boolean containsLocalBean(String name);

}

image-20210421192921835

DefaultListableBeanFactory 是 Spring 中最常见的兜底的容器,它实现了 BeanFactory 接口,可以根据 bean 名称,根据 bean 类型进行依赖查找;实现了 ListableBeanFactory,可以根据 bean 类型查找所有 bean 实例列表,根据 注解标记查找所有 bean 实例列表;实现了 HierarchicalBeanFactory 接口,可以根据 bean 名称进行层次性依赖查找,可以根据 bean 类型层次性查找所有 bean 实例列表。

1. 根据 Bean 名称层次性依赖查找

根据 Bean 的名称层次性查找当前容器及其祖先容器是否存在 bean

  1. 创建一个父容器,并加载 xml 中的bean,包括userbean等
<bean id="user" class="org.geekbang.ioc.overview.lookup.domain.User">
    <property name="id" value="1"/>
    <property name="name" value="tracccer"/>
</bean>
// 创建一个容器 BeanFactory, 该xml中定义了user等bean
private static HierarchicalBeanFactory createParentBeanFactory() {
    // 创建BeanFactory容器
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    // bean 配置文件路径
    String location = "dependcy-lookup-context.xml";
    // 加载xml配置文件中的bean
    reader.loadBeanDefinitions(location);

    return beanFactory;
}
  1. 判断当前容器本地是否存在 bean,忽略父容器中 bean
private static void displayLocalBean(HierarchicalBeanFactory beanFactory, String beanName, String BeanFactoryMode) {
    if (beanFactory.containsLocalBean(beanName)) {
        Object bean = beanFactory.getBean(beanName);
        System.out.println(BeanFactoryMode + "存在bean: " + beanName + ", " + bean);
    } else {
        System.out.println(BeanFactoryMode + "不存在bean: " + beanName);
    }
}
  1. 判断当前容器是否存在 bean,包括父容器中的 bean,会依次向上查找父容器。
private static void displayBean(HierarchicalBeanFactory beanFactory, String beanName) {
    System.out.println("层次性查找当前容器是否包含bean=" 
			+ beanName + ": "+ 
        	containsBean(beanFactory, beanName));
}

// 递归查询容器及其父容器是否存在bean
private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) {
    // 获取父容器
    BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
    // 父容器是HierarchicalBeanFactory类型, 正面其还有父容器
    if (parentBeanFactory instanceof HierarchicalBeanFactory) {
        HierarchicalBeanFactory hierarchicalBeanFactory = (HierarchicalBeanFactory) parentBeanFactory;
        // 递归调用, 判断父容器中是否包含bean
        if (containsBean(hierarchicalBeanFactory, beanName)) {
            // 父容器中包含bean, 返回true
            return true;
        }
    }
    // 返回当前容器是否包含bean
    return beanFactory.containsLocalBean(beanName);
}
  1. 为当前容器设置设置父容器,并判断userbean 在本地容器还是在父容器,然后使用递归的方式层次性向上查找父容器中是否存在user bean

    ConfigurableListableBeanFactory 实现了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,提供了设置父容器的setParentBeanFactory()方法。

public static void main(String[] args) {
    // 1.创建应用上下文, 使用注解配置, 并启动
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    applicationContext.register(DependpencyLookupHierarchicalDemo.class);

    // 2.获取 HierarchicalBeanFactory 的实现类 ConfigurableListableBeanFactory
    // HierarchicalBeanFactory -> ConfigurableBeanFactory -> ConfigurableListableBeanFactory
    ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
    System.out.println("当前BeanFactory的父容器ParentBeanFactory: " + beanFactory.getParentBeanFactory());

    // 3.设置 parent BeanFactory
    HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
    beanFactory.setParentBeanFactory(parentBeanFactory);
    System.out.println("当前BeanFactory的父容器ParentBeanFactory: " + beanFactory.getParentBeanFactory());

    // 4.判断bean在本地容器还是在父容器
    displayLocalBean(beanFactory, "user", "本地容器LocalBeanFactory");
    displayLocalBean(parentBeanFactory, "user", "父容器ParentBeanFactory");

    // 注解bean在容器启动时才会加载
    applicationContext.refresh();
    displayLocalBean(beanFactory, "hello", "本地容器LocalBeanFactory");

    // 5.层次性查找bean是否在当前容器及其祖先容器
    System.out.println("====层次性查找bean是否在当前容器及其祖先容器=====");
    displayBean(beanFactory, "user");
}

@Bean
public String hello() {
    return "HelloWorld";
}

输出结果

当前BeanFactory的父容器ParentBeanFactory: null
当前BeanFactory的父容器ParentBeanFactory: org.springframework.beans.factory.support.DefaultListableBeanFactory@7ac7a4e4: defining beans [user,objectFactory,org.geekbang.ioc.overview.lookup.domain.SuperUser#0]; root of factory hierarchy

本地容器LocalBeanFactory不存在bean: user
父容器ParentBeanFactory存在bean: user, User{id=1, name='tracccer'}
本地容器LocalBeanFactory存在bean: hello, HelloWorld

====层次性查找bean是否在当前容器及其祖先容器=====
层次性查找当前容器是否包含bean=user: true

2. 根据 Bean 类型层次性依赖查找

  1. 创建一个父容器,并加载 xml 中的 bean,有两个 User 类型的 bean
<bean id="user" class="org.geekbang.ioc.overview.lookup.domain.User">
    <property name="id" value="1"/>
    <property name="name" value="tracccer"/>
</bean>

<bean  class="org.geekbang.ioc.overview.lookup.domain.SuperUser" parent="user" primary="true">
    <property name="address" value="杭州"/>
</bean>
  1. 创建应用上下文,设置父容器,然后使用 BeanFactoryUtils.beansOfTypeIncludingAncestors 依次向上查找(层次性查找)当前容器及其祖先容器中是否存在 bean
public static void main(String[] args) {
    // 1.创建应用上下文, 使用注解配置, 并启动
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    applicationContext.register(DependpencyLookupHierarchicalDemo.class);

    // 2.获取 HierarchicalBeanFactory 的实现类 ConfigurableListableBeanFactory
    // HierarchicalBeanFactory -> ConfigurableBeanFactory -> ConfigurableListableBeanFactory
    ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
    System.out.println("当前BeanFactory的父容器ParentBeanFactory: " + beanFactory.getParentBeanFactory());

    // 3.设置 parent BeanFactory
    HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
    beanFactory.setParentBeanFactory(parentBeanFactory);
    System.out.println("当前BeanFactory的父容器ParentBeanFactory: " + beanFactory.getParentBeanFactory());

    // 6.使用BeanFactoryUtils查找当前容器及其祖先容器是否存在bean
    Map<String, User> users = BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, User.class);
    System.out.println("user类型bean列表: " + users);
}

输出结果:查找出了当前容器及其祖先容器中存在两个 User 类型的bean,分别是 user 和 SuperUser#0

当前BeanFactory的父容器ParentBeanFactory: null
当前BeanFactory的父容器ParentBeanFactory: org.springframework.beans.factory.support.DefaultListableBeanFactory@6ca8564a: defining beans [user,objectFactory,org.geekbang.ioc.overview.lookup.domain.SuperUser#0]; root of factory hierarchy

user类型bean列表: {user=User{id=1, name='tracccer'}, org....SuperUser#0=User{id=1, name='tracccer, address='杭州'}}

源码分析,BeanFactoryUtils 是如何依次查找当前容器及其祖先容器(层次性查找)中是否存在 type 类型的 bean,源码如下所示:

BeanFactoryUtils.java

public static <T> Map<String, T> beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type)
    throws BeansException {

    Assert.notNull(lbf, "ListableBeanFactory must not be null");
    Map<String, T> result = new LinkedHashMap<>(4);
    result.putAll(lbf.getBeansOfType(type));
    // 若当前容器是不是层次性Hierarchical容器, 则存在父容器
    if (lbf instanceof HierarchicalBeanFactory) {
        HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
        // 获取父容器
        if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
            // 查找父容器中type类型的bean, 递归调用
            Map<String, T> parentResult = beansOfTypeIncludingAncestors(
                (ListableBeanFactory) hbf.getParentBeanFactory(), type);
            
            // 遍历查找到的bean
            parentResult.forEach((beanName, beanInstance) -> {
                // 子容器不存在且当前容器存在该bean, 则将其加入result
                // 若子容器存在则不加入,即忽略了父容器中的同名bean
                if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {
                    result.put(beanName, beanInstance);
                }
            });
        }
    }
    // 返回查找到的bean
    return result;
}

从源码也可以看出,如果父容器和子容器存在同名的 bean,则优先选择子容器中的 bean。

根据 Bean 类型层次性查找 Bean 的单一实例的逻辑与上面的源码相同,当查找结果同在多个该类型的 Bean 则抛出异常,源码如下所示

BeanFactoryUtils.java
    
public static <T> T beanOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type)
    throws BeansException {
	// 层次性查找容器及其祖先容器中type类型的所有bean
    Map<String, T> beansOfType = beansOfTypeIncludingAncestors(lbf, type);
    // 返回查找到的单个bean
    return uniqueBean(type, beansOfType);
}

private static <T> T uniqueBean(Class<T> type, Map<String, T> matchingBeans) {
    int count = matchingBeans.size();
    if (count == 1) {
        // 如果查找到的bean为1个, 则返回bean
        return matchingBeans.values().iterator().next();
    }
    else if (count > 1) {
        // 如果查找到的bean为多个, 则抛出异常
        throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
    }
    else {
        // 如果未查找到bean, 则抛出异常
        throw new NoSuchBeanDefinitionException(type);
    }
}

3. 应用场景

比如 Spring MVC 中,Biz 组件放在 Root ApplicationContext,而 Web 组件放在 DispatcherServlet 的 ApplicationContext,后者是前者的子 ApplicationContext,所以,子 ApplicationContext 可以读取父 ApplicationContext

5.5 延迟依赖查找

Bean 延迟依赖查找接口

  • ObjectFactory
  • ObjectProvider,是 ObjectFactory 的子接口
    • getIfAvailable() 如果 bean 不存在,返回 null
    • getIfAvailable(Supplier defaultSupplier) 如果 bean 不存在,返回默认值
    • objectProvider.getObject() 如果 bean 不存在,抛出异常
    • getIfUnique(Supplier defaultSupplier) 如果 bean 不唯一,返回默认值

所谓的延迟查找,就是applicationContext.getBeanProvider(User.class)并没有真正去容器中查找,当调用objectProvider#getxxx时才会真的去容器进行依赖查找,故称之为延迟依赖查找,本节并没有演示其延迟的特性,只演示了其 api 的使用。

**应用场景:**延迟查找并非是Bean的延迟加载,跟@Lazy是两码事,ObjectProvider#getxxx 方法 底层还是通过BeanFactory来进行依赖查找的,但是在进行依赖查找前,可以制定以下规则,比如Bean找到后,再设置额外的属性,完成一些用户的自定义需求;Bean没有找到,该如何处理。ObjectProvider 在 Springboot,SpringCloud 中大量使用。

  1. ObjectProvider 接口的依赖查找示例
private static void lookupByIfAvaiable(AnnotationConfigApplicationContext applicationContext) {
    // 查找User类型的bean, 肯定找不到,由于是延迟查找,并不会报错
    ObjectProvider<User> objectProvider = applicationContext.getBeanProvider(User.class);

    // 1.若找不到bean, 返回null
    User user = objectProvider.getIfAvailable();
    System.out.println("bean不存在返回null: " + user);

    // 2.若找不到bean, 返回默认bean
    User user2 = objectProvider.getIfAvailable(() -> new User());
    System.out.println("bean不存在返回默认bean: " + user2);

    // 3. 若找不到bean, 抛出异常
    System.out.println(objectProvider.getObject());
}
  1. ObjectFactory 使用示例,参考 3.1 章节 根据Bean名称延迟查找

// 补充:延迟查找的应用场景,参考time.geekbang.org/course/deta… 评论区

5.6 依赖查找的安全性

依赖查找的安全性指的是否有可能抛出异常,如果有可能抛出异常,则该方法不安全。

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

推荐使用 ObjectProvider 查询,可以避免异常,SpringBoot 和 SpringCloud 大量使用。

5.7 内建可查找的依赖

AbstractApplicationContext 是 Spring 中所有应用上下文的一个基类,基本上所有的应用上下文的实现,包括注解类型的实现 AnnotationConfigApplicationContext 和 web 类型的实现都是基于 AbstractApplicationContext,该抽象类在应用上下文启动过程中会初始化一些相关的内部的一些依赖,这些内部的依赖我们称为内建可查找的依赖

AbstractApplicationContext 内建可查找的依赖

Bean 名称Bean 类型使用场景
environmentEnvironment外部化配置以及 Profiles
systemPropertiesjava.util.PropertiesJava 系统属性
systemEnvironmentjava.util.Map操作系统环境变量
messageSourceMessageSource国际化文件
lifecycleProcessorLifecycleProcessorLifecycle Bean 处理器
applicationEventMulticasterApplicationEventMulticasterSpring 事件广播器

外部化配置指的是 -D那些启动参数,Java 系统属性包括user.home 等属性,操作系统环境变量包括JAVA_HOME等属性。

image-20210421200700775

image-20210421201838578

  1. 用来处理 @Autowired 依赖注入,见 6.15 章节,在 AnnotationConfigUtils 中注册到容器中
AutowiredAnnotationBeanPostProcessor.java
    
// 处理@Autowired @Value注解
public AutowiredAnnotationBeanPostProcessor() {
    this.autowiredAnnotationTypes.add(Autowired.class);
    this.autowiredAnnotationTypes.add(Value.class);

    this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                                      ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
}
AnnotationConfigUtils.java

public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    BeanDefinitionRegistry registry, @Nullable Object source) {

	// .....

    // 向容器注册内建bean,名称为internalAutowiredAnnotationProcessor
    // 类型为AutowiredAnnotationBeanPostProcessor.class
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
}
  1. 用来处理 @Resource,@PostConstruct,@PreDestroy 等注解
CommonAnnotationBeanPostProcessor.java

// 处理@PostConstruct @PreDestroy注解
public CommonAnnotationBeanPostProcessor() {
    setOrder(Ordered.LOWEST_PRECEDENCE - 3);
    setInitAnnotationType(PostConstruct.class);
    setDestroyAnnotationType(PreDestroy.class);
    ignoreResourceType("javax.xml.ws.WebServiceContext");
}
  1. 用来处理 @EventListener 注解
EventListenerMethodProcessor.java

// 处理@EventListener注解
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    this.beanFactory = beanFactory;

    // 获取容器中EventListenerFactory类型的bean
    Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
    List<EventListenerFactory> factories = new ArrayList<>(beans.values());
    AnnotationAwareOrderComparator.sort(factories);
    this.eventListenerFactories = factories;
}

5.8 依赖查找中的常见异常

BeansException 的子类型:

image-20210421202319905

  1. 指定 Bean 的类型为 Map 接口,Bean 实例化时,会抛出异常 BeanInstantiationException,提示"实例化失败,Map是一个接口" Failed to instantiate [java.util.Map]: Specified class is an interface
public static void main(String[] args) {
    // 创建 BeanFactory 容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

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

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

输出结果:

警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'errorBean': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.Map]: Specified class is an interface
Exception in thread "main" org...BeanCreationException: 
	Error creating bean with name 'errorBean': Instantiation of bean failed; 
	nested exception is org..BeanInstantiationException: 
		Failed to instantiate [java.util.Map]: Specified class is an interface
Caused by: org....BeanInstantiationException: 
	Failed to instantiate [java.util.Map]: Specified class is an interface
  1. 当容器中不存在 Bean,或者查找时写错了 Bean 的名称,会抛出 NoSuchBeanDefintionException
  2. 当按类型查找时,容器中存在多个符合条件的 bean,会抛出 NoUniqueBeanDefintionException
  3. Bean 在实例化时发生异常,如 Bean 类型是接口等,会抛出 BeanInstantiationException
  4. Bean 在初始化时,如回调 @PostConstruct 方法发生异常,会抛出 BeanCreationExceptionDemo
  5. 当指定的 xml 配置文件不存在时,或者写错了 xml 配置文件名称,Bean 的定义读取失败,会报这个异常 BeanDefinitionStoreException。

5.9 面试题

  1. ObjectFactory 与 BeanFactory 的区别?

    二者均具备依赖查找能力,从名字可以看出二者都是工厂,ObjectFactory 仅关注一个或者一种类型的 Bean 依赖查找,是延迟查找,底层由 BeanFactory 执行查找逻辑。

    BeanFactory 则提供了单一 Bean,列表 Bean 和 层次性多种依赖查找方式。

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

    是线程安全的,操作过程中会使用互斥锁 synchronized。这块并没有完全搞明白,视频其实也没讲清楚。参考AbstractAutowireCapableBeanFactory#doCreateBean 方法中 synchronized 关键字部分

  3. Spring 依赖查找和依赖注入在来源上有什么区别?

    见后续 依赖注入 和 依赖来源 章节