简单来说,BeanFactory是Spring IoC 容器的根接口(“容器本身”),而FactoryBean是自定义 Bean 创建逻辑的工厂接口(“创建 Bean 的工厂”),两者的角色和职责天差地别。
一、核心概念与区别(先看表格,一目了然)
| 维度 | BeanFactory | FactoryBean |
|---|---|---|
| 核心定位 | Spring IoC 容器的根接口(“容器”) | 特殊的 Bean 类型(“工厂 Bean”),用于创建复杂 Bean |
| 核心作用 | 管理所有 Bean 的生命周期(实例化、配置、依赖注入、获取 Bean) | 自定义 Bean 的创建过程(解决复杂 Bean 的初始化问题) |
| 使用方式 | 开发者直接调用其方法(如getBean())获取 Bean | 开发者实现该接口,Spring 自动调用其方法创建 Bean |
| 核心方法 | getBean(String name)、containsBean()等 | getObject()、getObjectType()、isSingleton() |
| 关系 | 是所有 Spring 容器的基础,包含 / 管理 FactoryBean | 是被 BeanFactory 管理的一种特殊 Bean |
二、详细解析 + 代码示例
1. BeanFactory:Spring IoC 容器的 “根”
BeanFactory是 Spring 最基础的 IoC 容器接口,定义了 IoC 容器的核心规范:负责定位、加载、实例化、配置 Bean,并提供 Bean 的获取和管理能力。
你可以把它理解为 “Bean 的仓库管理员”—— 所有 Bean 都由它管理,你要获取 Bean 时,只需告诉它 Bean 的名称 / 类型,它就会返回对应的实例。
核心特点:
- 是 ApplicationContext(我们常用的容器)的父接口,ApplicationContext 在其基础上扩展了国际化、事件发布、资源加载等功能;
- 采用延迟加载(懒加载):只有调用
getBean()时才实例化 Bean(ApplicationContext 默认预加载); - 所有 Spring 容器都实现了该接口(如
DefaultListableBeanFactory、XmlBeanFactory)。
代码示例:使用 BeanFactory 获取 Bean
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; // 普通Bean类 class User { private String name; // 构造器、getter/setter省略 public User(String name) { this.name = name; } @Override public String toString() { return "User{name='" + name + "'}"; } } public class BeanFactoryDemo { public static void main(String[] args) { // 1. 创建BeanFactory容器(加载xml配置,模拟传统方式) BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml")); // 2. 从容器中获取Bean(此时才实例化User) User user = (User) beanFactory.getBean("user"); System.out.println(user); // 输出:User{name='张三'} } } // beans.xml配置(放在resources目录下) /* <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="User"> <constructor-arg value="张三"/> </bean> </beans> */2. FactoryBean:自定义 Bean 创建的 “工厂”
FactoryBean是一个特殊的 Bean 接口—— 当 Spring 容器发现一个 Bean 实现了FactoryBean,不会直接返回这个 Bean 本身,而是调用它的getObject()方法,返回该方法创建的实例。
你可以把它理解为 “复杂 Bean 的定制化工厂”:当某个 Bean 的创建逻辑很复杂(比如需要连接数据库、初始化第三方组件、多步配置),直接通过 xml / 注解配置太繁琐时,就可以实现FactoryBean来封装创建逻辑。
核心方法:
| 方法名 | 作用 |
|---|---|
T getObject() | 核心方法,返回最终要使用的 Bean 实例 |
Class<?> getObjectType() | 返回getObject()创建的 Bean 的类型 |
boolean isSingleton() | 返回创建的 Bean 是否为单例(默认 true) |
代码示例:实现 FactoryBean 创建复杂 Bean
比如创建一个需要初始化的RedisConnectionBean(模拟复杂 Bean):
import org.springframework.beans.factory.FactoryBean; // 模拟复杂的Redis连接类 class RedisConnection { private String host; private int port; // 复杂初始化逻辑:比如建立连接、认证等 public RedisConnection(String host, int port) { this.host = host; this.port = port; System.out.println("初始化Redis连接:" + host + ":" + port); } @Override public String toString() { return "RedisConnection{host='" + host + "', port=" + port + "}"; } } // 实现FactoryBean,封装RedisConnection的创建逻辑 class RedisConnectionFactoryBean implements FactoryBean<RedisConnection> { private String host; private int port; // 配置参数(可通过xml/注解注入) public void setHost(String host) { this.host = host; } public void setPort(int port) { this.port = port; } // 核心:创建RedisConnection实例 @Override public RedisConnection getObject() throws Exception { // 这里可以写复杂的创建逻辑:比如读取配置、校验参数、初始化连接池等 return new RedisConnection(host, port); } // 返回创建的Bean类型 @Override public Class<?> getObjectType() { return RedisConnection.class; } // 单例模式(默认true) @Override public boolean isSingleton() { return true; } } // 测试使用FactoryBean public class FactoryBeanDemo { public static void main(String[] args) { // 1. 创建Spring容器 BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml")); // 2. 获取Bean:容器会调用RedisConnectionFactoryBean的getObject(),返回RedisConnection RedisConnection redisConn = (RedisConnection) beanFactory.getBean("redisConnection"); System.out.println(redisConn); // 输出:RedisConnection{host='127.0.0.1', port=6379} // 3. 若要获取FactoryBean本身(而非它创建的Bean),需在名称前加& RedisConnectionFactoryBean factoryBean = (RedisConnectionFactoryBean) beanFactory.getBean("&redisConnection"); System.out.println(factoryBean); // 输出FactoryBean实例本身 } } // beans.xml配置 /* <bean id="redisConnection" class="RedisConnectionFactoryBean"> <property name="host" value="127.0.0.1"/> <property name="port" value="6379"/> </bean> */三、关键补充:容易踩的坑
- 获取 FactoryBean 本身的方式:默认
beanFactory.getBean("xxx")返回的是FactoryBean创建的 Bean;若要获取FactoryBean实例本身,需在 Bean 名称前加&(如&redisConnection)。 - FactoryBean 的适用场景:
- 整合第三方组件(如 MyBatis 的
SqlSessionFactoryBean、Redis 的RedisTemplateFactoryBean); - 创建需要复杂初始化逻辑的 Bean(如连接池、线程池、分布式锁客户端);
- 动态创建 Bean(根据不同配置返回不同实例)。
- 整合第三方组件(如 MyBatis 的
- BeanFactory 的扩展:日常开发中很少直接使用
BeanFactory,而是用它的子接口ApplicationContext(包含 BeanFactory 所有功能,且支持注解、事件、国际化等)。
总结
- 角色本质不同:
BeanFactory是 Spring IoC 容器的核心接口(“容器”),管理所有 Bean;FactoryBean是特殊的 Bean(“工厂”),用于创建特定的复杂 Bean。 - 使用目的不同:
BeanFactory解决 “Bean 的统一管理” 问题;FactoryBean解决 “复杂 Bean 的定制化创建” 问题。 - 调用逻辑不同:开发者调用
BeanFactory的getBean()获取 Bean;Spring 容器调用FactoryBean的getObject()生成 Bean。