## BeanFactory - [BeanFactory](#beanfactory) - [一、基本信息](#一基本信息) - [二、基本描述](#二基本描述) - [三、主要功能](#三主要功能) - [四、接口源码](#四接口源码) - [五、主要实现](#五主要实现) - [六、最佳实践](#六最佳实践) - [七、与其他组件的关系](#七与其他组件的关系) - [八、常见问题](#八常见问题) ### 一、基本信息 ✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading) ### 二、基本描述 `BeanFactory`接口是Spring框架中IoC容器的核心接口,定义了一套用于管理和获取Java对象实例的标准机制。通过`getBean`方法,可以按名称从容器中检索Bean实例,而`containsBean`方法用于检查容器中是否存在指定名称的Bean。提供的`getType`方法允许获取指定Bean名称的类型信息,而`isSingleton`方法则用于判断指定Bean是否为单例。该接口支持延迟加载,有助于提高性能。虽然`BeanFactory`是IoC容器的基础,但在实际应用中,通常使用`ApplicationContext`接口,它继承自`BeanFactory`并提供了更多高级特性,包括事件发布、AOP、国际化等,使得开发者更容易构建灵活且功能强大的应用。 ### 三、主要功能 1. **获取Bean** + `BeanFactory` 提供了 `getBean(String name)` 方法,用于从容器中获取指定名称的Bean实例。这使得我们可以通过配置文件或注解将Bean定义在容器中,并在需要时获取它们。 2. **检查是否包含Bean** + 通过 `containsBean(String name)` 方法,我们可以检查容器是否包含指定名称的Bean。这对于避免重复定义相同名称的Bean以及检查Bean是否已被注册很有用。 3. **获取Bean类型** + 使用 `getType(String name)` 方法,我们可以获取指定名称的Bean的类型信息。这允许在运行时动态地了解Bean的类型,从而采取相应的处理措施。 4. **判断Bean是否为单例** + 通过 `isSingleton(String name)` 方法,我们可以判断指定名称的Bean是否为单例。这对于了解Bean的作用域,以及是否在容器中共享同一个实例,具有重要意义。 ### 四、接口源码 `BeanFactory`接口是Spring框架中负责管理和获取Java对象(即Bean)的根接口,作为Bean容器的基本客户端视图。它集中了应用程序组件的配置,支持不同类型的Bean实例,提供丰富的Bean生命周期管理和依赖注入功能,同时支持工厂之间的层次结构。通过这一接口,Spring实现了控制反转(IoC)和依赖注入,为构建灵活、可维护的应用程序提供了基础。 ```java /** * Spring bean 容器访问的根接口。 * *
这是 bean 容器的基本客户端视图; * 针对特定目的,还提供了其他接口,如 {@link ListableBeanFactory} 和 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}。 * *
此接口由包含多个 bean 定义的对象实现,每个 bean 定义都由字符串名称唯一标识。根据 bean 定义, * 工厂将返回包含对象的独立实例(原型设计模式)或单个共享实例 * (Singleton 设计模式的一种更好的替代,其中实例是工厂范围内的单例)。将返回哪种类型的实例取决于 * bean 工厂的配置:API 是相同的。从 Spring 2.0 开始,根据具体的应用上下文,还可以使用进一步的范围 * (例如 Web 环境中的 "request" 和 "session" 范围)。 * *
这种方法的要点是,BeanFactory 是应用程序组件的中央注册表,集中配置应用程序组件 * (例如,不再需要单独的对象读取属性文件)。有关此方法优点的讨论,请参阅《Expert One-on-One * J2EE Design and Development》的第 4 章和第 11 章。 * *
请注意,通常最好依赖于依赖注入("推"配置)通过 setter 或构造函数配置应用程序对象, * 而不是使用任何形式的 "拉" 配置,如 BeanFactory 查找。Spring 的依赖注入功能使用此 BeanFactory * 接口及其子接口实现。通常,BeanFactory 将加载存储在配置源中的 bean 定义(例如 XML 文档), * 并使用 {@code org.springframework.beans} 包来配置这些 bean。但是,实现可以简单地直接在 * Java 代码中根据需要返回它创建的 Java 对象。关于定义可能存储在何处的约束没有限制:LDAP、 * RDBMS、XML、属性文件等。鼓励实现支持 bean 之间的引用(依赖注入)。 * *
与 {@link ListableBeanFactory} 中的方法不同,此接口中的所有操作还将检查 * 父工厂,如果这是 {@link HierarchicalBeanFactory}。如果在此工厂实例中找不到 bean, * 将询问直接父工厂。在此工厂实例中的 bean 应该覆盖任何父工厂中具有相同名称的 bean。 * *
Bean 工厂实现应尽可能支持标准的 bean 生命周期接口。初始化方法及其标准顺序的完整集合是: *
在关闭 bean 工厂时,以下生命周期方法适用: *
此方法允许将 Spring BeanFactory 用作替代 Singleton 或 Prototype 设计模式。 * 在单例 bean 的情况下,调用者可以保留对返回对象的引用。 *
将别名转换回相应的规范 bean 名称。 *
如果在此工厂实例中找不到 bean,则将询问父工厂。 * @param name 要检索的 bean 的名称 * @return bean 的实例 * @throws NoSuchBeanDefinitionException 如果没有具有指定名称的 bean * @throws BeansException 如果无法获取 bean */ Object getBean(String name) throws BeansException; /** * 返回指定 bean 的实例,该实例可以是共享的或独立的。 *
与 {@link #getBean(String)} 行为相同,但通过抛出 BeanNotOfRequiredTypeException * 来提供类型安全性。这意味着与 {@link #getBean(String)} 可能发生的正确类型转换上不会抛出 ClassCastException。 *
将别名转换回相应的规范 bean 名称。 *
如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要检索的 bean 的名称
* @param requiredType bean 必须匹配的类型;可以是接口或超类
* @return bean 的实例
* @throws NoSuchBeanDefinitionException 如果没有这样的 bean 定义
* @throws BeanNotOfRequiredTypeException 如果 bean 不是所需类型
* @throws BeansException 如果无法创建 bean
*/
允许指定显式构造函数参数/工厂方法参数,覆盖 bean 定义中指定的默认参数(如果有)。
* @param name 要检索的 bean 的名称
* @param args 在使用显式参数创建 bean 实例时使用的参数
* (仅在创建新实例而不是检索现有实例时应用)
* @return bean 的实例
* @throws NoSuchBeanDefinitionException 如果没有这样的 bean 定义
* @throws BeanDefinitionStoreException 如果给定参数但受影响的 bean 不是原型
* @throws BeansException 如果无法创建 bean
* @since 2.5
*/
Object getBean(String name, Object... args) throws BeansException;
/**
* 返回与给定对象类型唯一匹配的 bean 实例(如果存在)。
* 此方法进入 {@link ListableBeanFactory} 按类型查找领域,
* 但也可以根据给定类型的名称将其转换为传统的按名称查找。
* 要在一组 bean 中执行更广泛的检索操作,请使用 {@link ListableBeanFactory} 和/或 {@link BeanFactoryUtils}。
* @param requiredType bean 必须匹配的类型;可以是接口或超类
* @return 匹配所需类型的单个 bean 的实例
* @throws NoSuchBeanDefinitionException 如果没有找到给定类型的 bean
* @throws NoUniqueBeanDefinitionException 如果找到给定类型的多个 bean
* @throws BeansException 如果无法创建 bean
* @since 3.0
* @see ListableBeanFactory
*/
允许指定显式构造函数参数/工厂方法参数,覆盖 bean 定义中指定的默认参数(如果有)。
* 此方法进入 {@link ListableBeanFactory} 按类型查找领域,
* 但也可以根据给定类型的名称将其转换为传统的按名称查找。
* 要在一组 bean 中执行更广泛的检索操作,请使用 {@link ListableBeanFactory} 和/或 {@link BeanFactoryUtils}。
* @param requiredType bean 必须匹配的类型;可以是接口或超类
* @param args 在使用显式参数创建 bean 实例时使用的参数
* (仅在创建新实例而不是检索现有实例时应用)
* @return bean 的实例
* @throws NoSuchBeanDefinitionException 如果没有这样的 bean 定义
* @throws BeanDefinitionStoreException 如果给定参数但受影响的 bean 不是原型
* @throws BeansException 如果无法创建 bean
* @since 4.1
*/
如果给定的名称是一个别名,它将被转换回相应的规范 bean 名称。
* 如果此工厂是分层的,如果在此工厂实例中找不到 bean,则将询问任何父工厂。
* 如果找到与给定名称匹配的 bean 定义或单例实例,
* 无论指定的 bean 定义是具体的还是抽象的,是懒加载的还是急加载的,是否在范围内,此方法都将返回 {@code true}。
* 因此,请注意,此方法的 {@code true} 返回值不一定表示 {@link #getBean}
* 将能够为相同名称获取实例。
* @param name 要查询的 bean 的名称
* @return 是否存在具有给定名称的 bean
*/
boolean containsBean(String name);
/**
* 此 bean 是否为共享单例?也就是说,{@link #getBean} 是否始终返回相同的实例?
* 注意:此方法返回 {@code false} 不清楚地指示独立的实例。
* 它表示非单例实例,这可能对应于作用域 bean。使用 {@link #isPrototype} 操作明确检查独立实例。
* 将别名转换回相应的规范 bean 名称。
* 如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要查询的 bean 的名称
* @return 此 bean 是否对应于单例实例
* @throws NoSuchBeanDefinitionException 如果没有具有给定名称的 bean
* @see #getBean
* @see #isPrototype
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 此 bean 是否为原型?也就是说,{@link #getBean} 是否始终返回独立的实例?
* 注意:此方法返回 {@code false} 不清楚地指示单例对象。
* 它表示非独立实例,这可能对应于作用域 bean。使用 {@link #isSingleton} 操作明确检查共享单例实例。
* 将别名转换回相应的规范 bean 名称。
* 如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要查询的 bean 的名称
* @return 此 bean 是否始终生成独立实例
* @throws NoSuchBeanDefinitionException 如果没有具有给定名称的 bean
* @since 2.0.3
* @see #getBean
* @see #isSingleton
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 检查具有给定名称的 bean 是否与指定类型匹配。
* 更具体地说,检查对给定名称的 {@link #getBean} 调用是否会返回可分配给指定目标类型的对象。
* 将别名转换回相应的规范 bean 名称。
* 如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要查询的 bean 的名称
* @param typeToMatch 要匹配的类型(作为 {@code ResolvableType})
* @return 如果 bean 类型匹配,则为 {@code true},
* 如果不匹配或尚不能确定,则为 {@code false}
* @throws NoSuchBeanDefinitionException 如果没有具有给定名称的 bean
* @since 4.2
* @see #getBean
* @see #getType
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 检查具有给定名称的 bean 是否与指定类型匹配。
* 更具体地说,检查对给定名称的 {@link #getBean} 调用是否会返回可分配给指定目标类型的对象。
* 将别名转换回相应的规范 bean 名称。
* 如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要查询的 bean 的名称
* @param typeToMatch 要匹配的类型(作为 {@code Class})
* @return 如果 bean 类型匹配,则为 {@code true},
* 如果不匹配或尚不能确定,则为 {@code false}
* @throws NoSuchBeanDefinitionException 如果没有具有给定名称的 bean
* @since 2.0.1
* @see #getBean
* @see #getType
*/
boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 确定具有给定名称的 bean 的类型。
* 更具体地说,确定 {@link #getBean} 对于给定名称将返回的对象的类型。
* 对于 {@link FactoryBean},返回 FactoryBean 创建的对象的类型,由 {@link FactoryBean#getObjectType()} 公开。
* 这可能导致以前未初始化的 {@code FactoryBean} 的初始化(请参阅 {@link #getType(String, boolean)})。
* 将别名转换回相应的规范 bean 名称。
* 如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要查询的 bean 的名称
* @return bean 的类型,如果无法确定则为 {@code null}
* @throws NoSuchBeanDefinitionException 如果没有具有给定名称的 bean
* @since 1.1.2
* @see #getBean
* @see #isTypeMatch
*/
@Nullable
Class> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 确定具有给定名称的 bean 的类型。
* 更具体地说,确定 {@link #getBean} 对于给定名称将返回的对象的类型。
* 对于 {@link FactoryBean},返回 FactoryBean 创建的对象的类型,由 {@link FactoryBean#getObjectType()} 公开。
* 根据 {@code allowFactoryBeanInit} 标志的不同,如果没有提供早期类型信息,则可能导致以前未初始化的 {@code FactoryBean} 的初始化。
* 将别名转换回相应的规范 bean 名称。
* 如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要查询的 bean 的名称
* @param allowFactoryBeanInit 是否可能为了确定其对象类型而初始化 {@code FactoryBean}
* @return bean 的类型,如果无法确定则为 {@code null}
* @throws NoSuchBeanDefinitionException 如果没有具有给定名称的 bean
* @since 5.2
* @see #getBean
* @see #isTypeMatch
*/
@Nullable
Class> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
/**
* 返回给定 bean 名称的别名,如果有的话。
* 在 {@link #getBean} 调用中,所有这些别名都指向相同的 bean。
* 如果给定的名称是别名,则将返回相应的原始 bean 名称和其他别名(如果有的话),
* 原始 bean 名称将是数组中的第一个元素。
* 如果在此工厂实例中找不到 bean,则将询问父工厂。
* @param name 要检查别名的 bean 名称
* @return 别名,如果没有则为空数组
* @see #getBean
*/
String[] getAliases(String name);
}
```
### 五、主要实现
+ `DefaultListableBeanFactory`
+ `DefaultListableBeanFactory`是Spring框架中实现`BeanFactory`接口的关键类之一,负责注册、管理和初始化应用程序中的所有Bean定义。它支持依赖注入、不同作用域的Bean管理、处理`FactoryBean`、层次性容器、以及各种生命周期回调等功能,是Spring IoC容器的核心实现,提供了灵活而强大的Bean管理和配置机制。
### 六、最佳实践
使用`BeanFactory`接口的不同方法来操作和查询Spring容器中的Bean,涵盖了获取Bean、类型判断、别名查询等功能。
```java
public class BeanFactoryDemo {
public static void main(String[] args) {
// 创建 BeanFactory
BeanFactory beanFactory = new AnnotationConfigApplicationContext(MyBean.class).getBeanFactory();
// 根据名称获取 bean
Object bean = beanFactory.getBean("myBean");
System.out.println("通过名称获取Bean: " + bean);
// 获取 bean 的 ObjectProvider
ObjectProvider