副标题:一字之差,天壤之别! 🤯
🎬 开场白:谁是谁?
嘿,小伙伴们!👋 今天我们要解开Spring中一个让人头疼的谜题——FactoryBean和BeanFactory的区别!
这两个名字只差一个字的顺序,但作用完全不同!就像:
- 🍕 披萨店(BeanFactory)→ 提供披萨的地方
- 🧑🍳 披萨师傅(FactoryBean)→ 制作披萨的人
千万别搞混了! 不然面试官会以为你是来搞笑的!😅
📚 第一幕:BeanFactory - Bean工厂
什么是BeanFactory?
BeanFactory是Spring IOC容器的最顶层接口,它的职责是:
- 管理Bean的生命周期 🔄
- 提供Bean的依赖注入 💉
- 管理Bean的作用域 🎯
public interface BeanFactory {
// 根据名称获取Bean
Object getBean(String name);
// 根据类型获取Bean
<T> T getBean(Class<T> requiredType);
// 根据名称和类型获取Bean
<T> T getBean(String name, Class<T> requiredType);
// 判断是否包含Bean
boolean containsBean(String name);
// 判断是否单例
boolean isSingleton(String name);
// 判断是否原型
boolean isPrototype(String name);
// 获取Bean类型
Class<?> getType(String name);
// 获取Bean别名
String[] getAliases(String name);
}
生活比喻:超市(BeanFactory)
超市(BeanFactory)
├── 货架A:存放面包(Bean)🍞
├── 货架B:存放牛奶(Bean)🥛
├── 货架C:存放水果(Bean)🍎
└── 货架D:存放零食(Bean)🍪
顾客来了:
"老板,给我来个面包!" → 从货架A拿出面包
"老板,给我来瓶牛奶!" → 从货架B拿出牛奶
BeanFactory就是这个"超市",负责管理和提供所有商品(Bean)!
BeanFactory的继承体系
BeanFactory (最基础接口)
↓
ListableBeanFactory (可列举Bean)
↓
HierarchicalBeanFactory (支持层级结构)
↓
ConfigurableBeanFactory (可配置)
↓
ConfigurableListableBeanFactory (组合)
↓
DefaultListableBeanFactory (默认实现)
↓
ApplicationContext (应用上下文)
BeanFactory的使用
public class BeanFactoryDemo {
public static void main(String[] args) {
// 创建BeanFactory
DefaultListableBeanFactory beanFactory =
new DefaultListableBeanFactory();
// 手动注册Bean定义
BeanDefinition beanDefinition =
BeanDefinitionBuilder
.genericBeanDefinition(UserService.class)
.setScope("singleton")
.getBeanDefinition();
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 获取Bean
UserService userService = beanFactory.getBean(UserService.class);
userService.doSomething();
// 检查Bean是否存在
boolean exists = beanFactory.containsBean("userService");
System.out.println("Bean是否存在:" + exists);
// 检查是否单例
boolean singleton = beanFactory.isSingleton("userService");
System.out.println("是否单例:" + singleton);
}
}
🎪 第二幕:FactoryBean - Bean工厂
什么是FactoryBean?
FactoryBean是一个特殊的Bean,它本身是一个工厂,用来创建其他Bean!
public interface FactoryBean<T> {
// 返回由FactoryBean创建的Bean实例
T getObject() throws Exception;
// 返回FactoryBean创建的Bean类型
Class<?> getObjectType();
// 返回的Bean是否为单例
default boolean isSingleton() {
return true;
}
}
生活比喻:披萨师傅(FactoryBean)
披萨店里有一位特殊的师傅(FactoryBean)🧑🍳
老板(BeanFactory):
"师傅,做个披萨!"
披萨师傅(FactoryBean):
"好嘞,我这就给你做一个特别的披萨!"
[复杂的制作过程...]
"披萨做好了!" 🍕
顾客拿到的是**披萨(getObject()返回的对象)**,
而不是披萨师傅本人!
但如果你想见师傅本人,可以说:"&披萨师傅"
FactoryBean实战案例
案例1:简单的FactoryBean
@Component
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
private String color;
@Override
public Car getObject() throws Exception {
System.out.println("🏭 FactoryBean正在制造汽车...");
// 复杂的创建逻辑
Car car = new Car();
car.setBrand(brand != null ? brand : "Tesla");
car.setColor(color != null ? color : "Black");
car.setProductionDate(new Date());
// 可以进行复杂的初始化
car.initialize();
System.out.println("✅ 汽车制造完成:" + car);
return car;
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return true; // 每次返回同一个Car实例
}
// getters and setters...
}
@Data
public class Car {
private String brand;
private String color;
private Date productionDate;
public void initialize() {
System.out.println("🔧 初始化汽车系统...");
// 复杂的初始化逻辑
}
}
使用FactoryBean
@SpringBootTest
public class FactoryBeanTest {
@Autowired
private ApplicationContext context;
@Test
public void testFactoryBean() {
// 获取Car对象(FactoryBean创建的对象)
Car car = context.getBean("carFactoryBean", Car.class);
System.out.println("🚗 获取到Car:" + car);
// 获取FactoryBean本身(注意&前缀)
CarFactoryBean factoryBean =
context.getBean("&carFactoryBean", CarFactoryBean.class);
System.out.println("🏭 获取到FactoryBean:" + factoryBean);
// 验证类型
System.out.println("car是Car类型?" + (car instanceof Car));
System.out.println("factoryBean是CarFactoryBean类型?" +
(factoryBean instanceof CarFactoryBean));
}
}
输出:
🏭 FactoryBean正在制造汽车...
🔧 初始化汽车系统...
✅ 汽车制造完成:Car(brand=Tesla, color=Black, productionDate=...)
🚗 获取到Car:Car(brand=Tesla, color=Black, productionDate=...)
🏭 获取到FactoryBean:CarFactoryBean@12345678
car是Car类型?true
factoryBean是CarFactoryBean类型?true
&前缀的魔法
// 不加&:获取FactoryBean创建的对象
Car car = context.getBean("carFactoryBean", Car.class);
// 加&:获取FactoryBean本身
CarFactoryBean factoryBean =
context.getBean("&carFactoryBean", CarFactoryBean.class);
记忆口诀:
不加& → 产品(Product)🍕
加上& → 工厂(Factory)🏭
🎯 第三幕:核心区别对比
对比表
| 对比项 | BeanFactory | FactoryBean |
|---|---|---|
| 定位 | IOC容器 | 特殊的Bean |
| 职责 | 管理所有Bean | 创建特定Bean |
| 层级 | 容器顶层接口 | 普通Bean |
| 使用场景 | Spring框架内部使用 | 应用开发使用 |
| 获取方式 | 直接使用 | 通过&前缀获取 |
| 比喻 | 超市 🏪 | 披萨师傅 🧑🍳 |
关系图
┌─────────────────────────────────────┐
│ BeanFactory(容器) │
│ │
│ ┌─────────────────────────┐ │
│ │ 普通Bean │ │
│ │ - UserService │ │
│ │ - OrderService │ │
│ └─────────────────────────┘ │
│ │
│ ┌─────────────────────────┐ │
│ │ FactoryBean(特殊Bean) │ │
│ │ ├─ getObject() → Car │ │
│ │ └─ FactoryBean本身 │ │
│ └─────────────────────────┘ │
│ │
└─────────────────────────────────────┘
🔧 第四幕:FactoryBean的高级用法
案例1:创建代理对象
@Component
public class ProxyFactoryBean implements FactoryBean<UserService> {
@Autowired
private UserService target; // 目标对象
@Override
public UserService getObject() throws Exception {
System.out.println("🎭 创建UserService的代理对象");
return (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
(proxy, method, args) -> {
System.out.println("⏱️ 方法执行前:" + method.getName());
long start = System.currentTimeMillis();
Object result = method.invoke(target, args);
long end = System.currentTimeMillis();
System.out.println("⏱️ 方法执行后:" + (end - start) + "ms");
return result;
}
);
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
案例2:创建连接池
@Component
public class DataSourceFactoryBean implements FactoryBean<DataSource> {
@Value("${db.url}")
private String url;
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Value("${db.pool.size:10}")
private int poolSize;
@Override
public DataSource getObject() throws Exception {
System.out.println("🗄️ 创建数据源连接池...");
HikariConfig config = new HikariConfig();
config.setJdbcUrl(url);
config.setUsername(username);
config.setPassword(password);
config.setMaximumPoolSize(poolSize);
config.setMinimumIdle(2);
config.setConnectionTimeout(30000);
HikariDataSource dataSource = new HikariDataSource(config);
System.out.println("✅ 数据源创建完成,连接池大小:" + poolSize);
return dataSource;
}
@Override
public Class<?> getObjectType() {
return DataSource.class;
}
@Override
public boolean isSingleton() {
return true; // 数据源单例
}
}
案例3:创建复杂配置对象
@Component
public class RedisClientFactoryBean implements FactoryBean<RedisClient> {
@Value("${redis.host:localhost}")
private String host;
@Value("${redis.port:6379}")
private int port;
@Value("${redis.password:}")
private String password;
@Value("${redis.database:0}")
private int database;
@Value("${redis.timeout:3000}")
private int timeout;
@Override
public RedisClient getObject() throws Exception {
System.out.println("📮 创建Redis客户端...");
RedisClient client = new RedisClient();
client.setHost(host);
client.setPort(port);
if (!password.isEmpty()) {
client.setPassword(password);
}
client.setDatabase(database);
client.setTimeout(timeout);
// 初始化连接
client.connect();
// 执行健康检查
if (!client.ping()) {
throw new IllegalStateException("Redis连接失败!");
}
System.out.println("✅ Redis客户端创建成功:" + host + ":" + port);
return client;
}
@Override
public Class<?> getObjectType() {
return RedisClient.class;
}
@PreDestroy
public void destroy() {
System.out.println("🗑️ 关闭Redis连接");
}
}
🎨 第五幕:Spring内置的FactoryBean
1. ProxyFactoryBean
@Configuration
public class ProxyConfig {
@Bean
public ProxyFactoryBean userServiceProxy(UserService userService) {
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
proxyFactory.setTarget(userService);
proxyFactory.setInterfaces(UserService.class);
// 添加增强
proxyFactory.addAdvice((MethodInterceptor) invocation -> {
System.out.println("🎯 调用方法:" + invocation.getMethod().getName());
return invocation.proceed();
});
return proxyFactory;
}
}
2. LocalSessionFactoryBean(MyBatis/Hibernate)
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath*:mapper/**/*.xml")
);
return factoryBean;
}
}
3. JndiObjectFactoryBean
@Configuration
public class JndiConfig {
@Bean
public JndiObjectFactoryBean dataSource() {
JndiObjectFactoryBean factoryBean = new JndiObjectFactoryBean();
factoryBean.setJndiName("java:comp/env/jdbc/myDataSource");
factoryBean.setResourceRef(true);
factoryBean.setProxyInterface(DataSource.class);
return factoryBean;
}
}
🎪 第六幕:实战应用场景
场景1:动态创建不同类型的对象
@Component
public class AnimalFactoryBean implements FactoryBean<Animal> {
@Value("${animal.type:dog}")
private String animalType;
@Override
public Animal getObject() throws Exception {
System.out.println("🐾 创建动物:" + animalType);
switch (animalType.toLowerCase()) {
case "dog":
return new Dog();
case "cat":
return new Cat();
case "bird":
return new Bird();
default:
throw new IllegalArgumentException("未知的动物类型:" + animalType);
}
}
@Override
public Class<?> getObjectType() {
return Animal.class;
}
}
interface Animal {
void speak();
}
class Dog implements Animal {
@Override
public void speak() {
System.out.println("🐕 汪汪汪!");
}
}
class Cat implements Animal {
@Override
public void speak() {
System.out.println("🐱 喵喵喵!");
}
}
class Bird implements Animal {
@Override
public void speak() {
System.out.println("🐦 叽叽喳喳!");
}
}
场景2:加载外部资源
@Component
public class ConfigLoaderFactoryBean implements FactoryBean<Properties> {
@Value("${config.file.path}")
private String configFilePath;
@Override
public Properties getObject() throws Exception {
System.out.println("📄 加载配置文件:" + configFilePath);
Properties properties = new Properties();
try (InputStream is = new FileInputStream(configFilePath)) {
properties.load(is);
}
System.out.println("✅ 加载了 " + properties.size() + " 个配置项");
return properties;
}
@Override
public Class<?> getObjectType() {
return Properties.class;
}
}
场景3:单例到原型的转换
@Component
public class PrototypeFactoryBean implements FactoryBean<PrototypeObject> {
@Override
public PrototypeObject getObject() throws Exception {
// 每次都创建新对象
return new PrototypeObject();
}
@Override
public Class<?> getObjectType() {
return PrototypeObject.class;
}
@Override
public boolean isSingleton() {
return false; // 返回false,每次创建新对象
}
}
⚠️ 第七幕:常见坑点
坑点1:忘记&前缀
// ❌ 错误:获取的是Car对象,不是FactoryBean
CarFactoryBean factoryBean =
context.getBean("carFactoryBean", CarFactoryBean.class);
// 报错:类型不匹配!
// ✅ 正确:使用&前缀获取FactoryBean本身
CarFactoryBean factoryBean =
context.getBean("&carFactoryBean", CarFactoryBean.class);
坑点2:getObjectType()返回null
// ❌ 错误
public class BadFactoryBean implements FactoryBean<Car> {
@Override
public Class<?> getObjectType() {
return null; // 不要返回null!
}
}
// ✅ 正确
public class GoodFactoryBean implements FactoryBean<Car> {
@Override
public Class<?> getObjectType() {
return Car.class; // 明确返回类型
}
}
坑点3:循环依赖问题
// ❌ 可能产生循环依赖
@Component
public class AFactoryBean implements FactoryBean<A> {
@Autowired
private B b; // 依赖B
@Override
public A getObject() {
return new A(b);
}
}
@Component
public class BFactoryBean implements FactoryBean<B> {
@Autowired
private A a; // 依赖A
@Override
public B getObject() {
return new B(a);
}
}
// ✅ 解决方案:延迟注入
@Component
public class AFactoryBean implements FactoryBean<A> {
@Lazy
@Autowired
private B b;
@Override
public A getObject() {
return new A(b);
}
}
🎯 第八幕:最佳实践
✅ 1. 明确使用场景
使用FactoryBean的场景:
- 创建过程复杂
- 需要动态决定创建什么对象
- 需要对创建的对象进行额外处理
- 第三方库集成
不要用FactoryBean的场景:
- 简单对象创建
- 普通Bean就能满足需求
✅ 2. 实现DisposableBean接口
@Component
public class ResourceFactoryBean
implements FactoryBean<Resource>, DisposableBean {
private Resource resource;
@Override
public Resource getObject() throws Exception {
resource = createResource();
return resource;
}
@Override
public void destroy() throws Exception {
// 清理资源
if (resource != null) {
resource.close();
System.out.println("🗑️ 资源已释放");
}
}
}
✅ 3. 提供清晰的文档
/**
* UserService的FactoryBean
*
* 这个FactoryBean用于创建UserService的代理对象,
* 会自动添加性能监控和日志记录功能。
*
* 配置示例:
* <pre>
* @Autowired
* private UserService userService; // 获取代理对象
*
* @Autowired
* @Qualifier("&userServiceFactoryBean")
* private UserServiceFactoryBean factoryBean; // 获取工厂本身
* </pre>
*/
@Component
public class UserServiceFactoryBean implements FactoryBean<UserService> {
// ...
}
🎉 总结
核心要点记忆
BeanFactory = 容器(管理者) 🏪
└─ 管理所有Bean
└─ 提供依赖注入
└─ 控制生命周期
FactoryBean = 特殊Bean(创建者) 🧑🍳
└─ 创建复杂对象
└─ 封装创建逻辑
└─ 使用&前缀获取自己
一句话记忆
BeanFactory是"大老板"🏪,管理所有Bean;
FactoryBean是"小师傅"🧑🍳,专门制作特殊Bean!
对比总结表
| 特性 | BeanFactory | FactoryBean |
|---|---|---|
| 身份 | IOC容器接口 | 特殊Bean |
| 作用 | 管理Bean | 创建Bean |
| 获取方式 | 直接使用 | 需要&前缀 |
| 使用频率 | 框架内部 | 应用开发 |
| 比喻 | 超市 🏪 | 披萨师傅 🧑🍳 |
🚀 课后作业
- 初级: 实现一个简单的FactoryBean,创建配置对象
- 中级: 实现一个动态的FactoryBean,根据配置创建不同类型的对象
- 高级: 实现一个FactoryBean,创建带有AOP增强的对象
📚 参考资料
- Spring Framework官方文档 - FactoryBean
- 《Spring源码深度解析》
- Spring源码 - org.springframework.beans.factory包
最后的彩蛋: 🎁
面试必杀技:
面试官:"说说BeanFactory和FactoryBean的区别?"
你:"BeanFactory是Spring的IOC容器,就像超市🏪,负责管理所有商品;FactoryBean是一个特殊的Bean,就像披萨师傅🧑🍳,专门制作复杂的披萨。获取FactoryBean本身需要加&前缀,不加&获取的是它创建的对象。"
面试官:"👍 回答得很形象!"
记住这句话:
"不加&拿产品,加上&见工厂!" 🎯
关注我,下期更精彩! 🌟
掌握双Bean,面试不慌! 💪✨
#Spring #BeanFactory #FactoryBean #面试必考 #最佳实践