首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >FactoryBean 和BeanFactory的傻傻的总是分不清?

FactoryBean 和BeanFactory的傻傻的总是分不清?

作者头像
java金融
发布2025-07-16 17:39:54
发布2025-07-16 17:39:54
9800
代码可运行
举报
文章被收录于专栏:java金融java金融
运行总次数:0
代码可运行

引言

记得很久以前经常被问到这样一个面试题"FactoryBean 和BeanFactory它们有啥区别"。在 Spring 框架中,BeanFactoryFactoryBean 是两个核心概念,虽然名称相似,但它们的角色和功能完全不同。

1. 定义与角色

维度

BeanFactory

FactoryBean

角色

Spring 的 IoC 容器核心接口,负责管理所有 Bean 的生命周期(创建、配置、依赖注入)。

一个 特殊 Bean 接口,用于动态创建复杂对象(如代理对象、连接池、动态代理等)。

功能

提供容器基础能力(如 getBean()、containsBean() 等)。

通过 getObject() 方法返回实际需要的 Bean 实例。

接口方法

getBean()、containsBean()、isSingleton() 等。

getObject()、getObjectType()、isSingleton()。

典型实现

DefaultListableBeanFactory、ApplicationContext 等。

SqlSessionFactoryBean(MyBatis)、ProxyFactoryBean(AOP)等。


2. 核心区别

特性

BeanFactory

FactoryBean

获取对象的方式

直接返回容器中注册的 Bean 实例(如 getBean("beanName"))。

默认返回 getObject() 的结果(如 getBean("factoryBeanName"))。

访问自身的方式

直接通过 getBean("beanName") 获取。

需通过 &beanName 前缀获取(如 getBean("&factoryBeanName"))。

是否单例

容器默认管理 Bean 的作用域(如单例、原型)。

通过 isSingleton() 方法定义创建对象的作用域。

使用场景

管理所有 Bean 的基础设施(如依赖注入、生命周期管理)。

封装复杂对象的创建逻辑(如动态代理、数据库连接池)。


3. 使用场景与示例

(1) BeanFactory 的使用

作用:作为 Spring 容器的根接口,负责管理所有 Bean 的生命周期。

示例

代码语言:javascript
代码运行次数:0
运行
复制
// 通过 BeanFactory 获取 Bean
BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = factory.getBean("userService", UserService.class);
(2) FactoryBean 的使用

作用:通过自定义 getObject() 方法创建复杂对象。

示例

代码语言:javascript
代码运行次数:0
运行
复制
// 定义 FactoryBean
public class MyConnectionFactory implements FactoryBean<Connection> {
    @Override
    public Connection getObject() throws Exception {
        // 返回数据库连接
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb");
    }

    @Override
    public Class<?> getObjectType() {
        return Connection.class;
    }

    @Override
    public boolean isSingleton() {
        return true; // 是否为单例
    }
}

// 配置到 Spring 容器
@Configuration
public class AppConfig {
    @Bean
    public FactoryBean<Connection> connectionFactory() {
        return new MyConnectionFactory();
    }
}

// 使用
@Autowired
private Connection connection; // 实际注入的是 getObject() 返回的 Connection

在 Spring 框架中,FactoryBean 被广泛用于集成第三方中间件或框架,通过封装复杂对象的创建逻辑,简化配置并提高灵活性。以下是几个常见中间件使用 FactoryBean 的示例:

1. MyBatis 的 SqlSessionFactoryBean

作用: 创建 MyBatis 的 SqlSessionFactory 实例,集成数据库配置、映射文件扫描等逻辑。

代码示例

代码语言:javascript
代码运行次数:0
运行
复制
<!-- Spring 配置文件中定义 SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>

实现原理

  • SqlSessionFactoryBean 实现了 FactoryBean<SqlSessionFactory>
  • getObject() 方法内部调用 MyBatis 的 SqlSessionFactoryBuilder 创建 SqlSessionFactory
  • • 支持延迟加载和复杂配置(如多数据源、事务管理器)。

2. OpenFeign 的 FeignClientFactoryBean

作用: 动态创建 Feign 客户端(RESTful API 调用代理对象)。

代码示例

代码语言:javascript
代码运行次数:0
运行
复制
@Configuration
public class FeignConfig {
    @Bean
    public FactoryBean<MyServiceClient> myServiceClient() {
        FeignClientFactoryBean factory = new FeignClientFactoryBean();
        factory.setUrl("http://example.com/api");
        factory.setType(MyServiceClient.class);
        return factory;
    }
}

实现原理

  • FeignClientFactoryBean 封装了 Feign 的 TargetEncoder/Decoder 配置。
  • getObject() 返回动态代理的 Feign 客户端实例。
  • • 支持自定义拦截器、重试策略等。

3. Redis 的 RedisConnectionFactoryBean

作用: 创建 Redis 连接池(如 JedisConnectionFactoryLettuceConnectionFactory)。

代码示例

代码语言:javascript
代码运行次数:0
运行
复制
<!-- Spring 配置文件中定义 RedisConnectionFactoryBean -->
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="localhost"/>
    <property name="port" value="6379"/>
</bean>

实现原理

  • JedisConnectionFactory 本身实现了 FactoryBean<RedisConnection>
  • getObject() 返回 RedisConnection 实例(如 JedisConnection)。
  • • 支持连接池配置(如最大连接数、超时时间)。

4. RocketMQ 的 RocketMQTemplate

作用: 封装 RocketMQ 生产者和消费者的创建逻辑。

代码示例

代码语言:javascript
代码运行次数:0
运行
复制
@Configuration
public class RocketMQConfig {
    @Bean
    public RocketMQTemplate rocketMQTemplate() {
        RocketMQTemplate template = new RocketMQTemplate();
        template.setProducer(new DefaultMQProducer("my-producer-group"));
        template.setConsumer(new DefaultMQPushConsumer("my-consumer-group"));
        return template;
    }
}

实现原理

  • RocketMQTemplate 通过 FactoryBean 模式初始化生产者和消费者。
  • getObject() 返回配置好的 RocketMQTemplate 实例。
  • • 支持消息发送、监听器注册等操作。

5. Quartz 的 SchedulerFactoryBean

作用: 创建 Quartz 调度器(Scheduler),集成任务调度逻辑。

代码示例

代码语言:javascript
代码运行次数:0
运行
复制
<!-- Spring 配置文件中定义 SchedulerFactoryBean -->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="myCronTrigger"/>
        </list>
    </property>
</bean>

实现原理

  • SchedulerFactoryBean 封装了 Quartz 的 SchedulerFactory 配置。
  • getObject() 返回 Scheduler 实例。
  • • 支持动态注册任务和触发器。

6. Dubbo 的 ServiceBean

作用: 发布 Dubbo 服务,封装服务暴露和注册逻辑。

代码示例

代码语言:javascript
代码运行次数:0
运行
复制
<!-- Spring 配置文件中定义 Dubbo ServiceBean -->
<bean id="dubboService" class="com.alibaba.dubbo.config.ServiceBean">
    <property name="interface" value="com.example.MyService"/>
    <property name="ref" ref="myServiceImpl"/>
</bean>

实现原理

  • ServiceBean 实现了 FactoryBean<Exporter>
  • getObject() 返回服务导出器(Exporter),完成服务注册和暴露。
  • • 支持负载均衡、容错策略等 Dubbo 特性。

7. Kafka 的 KafkaTemplate

作用: 封装 Kafka 生产者和消费者的创建逻辑。

代码示例

代码语言:javascript
代码运行次数:0
运行
复制
@Configuration
public class KafkaConfig {
    @Bean
    public KafkaTemplate<String, String> kafkaTemplate() {
        return new KafkaTemplate<>(new ProducerFactory<>());
    }
}

实现原理

  • KafkaTemplate 通过 FactoryBean 模式初始化生产者工厂。
  • getObject() 返回配置好的 KafkaTemplate 实例。
  • • 支持消息发送、消费者监听等操作。

总结对比

中间件

FactoryBean 类型

作用领域

核心方法作用

MyBatis

SqlSessionFactoryBean

数据库访问

创建 SqlSessionFactory

OpenFeign

FeignClientFactoryBean

RESTful 客户端

创建 Feign 动态代理

Redis

JedisConnectionFactory

缓存/键值存储

创建 Redis 连接池

RocketMQ

RocketMQTemplate

消息队列

封装生产者/消费者逻辑

Quartz

SchedulerFactoryBean

定时任务调度

创建调度器并注册任务

Dubbo

ServiceBean

微服务 RPC

发布服务并注册到注册中心

Kafka

KafkaTemplate

消息队列

封装生产者/消费者逻辑

  • 解耦配置与逻辑:通过 FactoryBean 将复杂初始化逻辑封装,Spring 容器只需管理 Bean 的声明。
  • 支持动态创建:可根据运行时条件(如环境变量、配置参数)动态生成不同对象。
  • 统一资源管理:集中管理中间件的连接池、配置参数,便于维护和扩展。

4. 获取 FactoryBean 本身

默认行为getBean("factoryBeanName") 返回的是 FactoryBean.getObject() 的结果。

获取 FactoryBean 实例本身:需在 Bean 名称前加 & 前缀。

代码语言:javascript
代码运行次数:0
运行
复制
// 获取 FactoryBean 创建的 Bean
Connection connection = context.getBean("connectionFactory", Connection.class);

// 获取 FactoryBean 实例本身
MyConnectionFactory factoryBean = (MyConnectionFactory) context.getBean("&connectionFactory");

5. 常见问题与解决方案

问题1:混淆 BeanFactory 和 FactoryBean 的功能
  • 解决方案:明确 BeanFactory 是容器,FactoryBean 是创建 Bean 的工具。
问题2:期望获取 FactoryBean 实例却得到其创建的 Bean

示例

代码语言:javascript
代码运行次数:0
运行
复制
// 错误:获取的是 Encryptor 实例,而非 FactoryBean
Encryptor encryptor = factory.getBean("encryptor");

// 正确:添加 "&" 前缀获取 FactoryBean
FactoryBean factoryBean = factory.getBean("&encryptor");
问题3:未正确实现 getObjectType() 导致类型检查失败
  • 修复:确保 getObjectType() 返回准确的类型信息。

6. 高级应用场景

(1) 动态代理生成
代码语言:javascript
代码运行次数:0
运行
复制
public class ServiceProxyFactoryBean implements FactoryBean<MyService> {
    @Override
    public MyService getObject() {
        return (MyService) Proxy.newProxyInstance(
            getClass().getClassLoader(),
            new Class[]{MyService.class},
            (proxy, method, args) -> {
                System.out.println("Before method: " + method.getName());
                return method.invoke(new MyServiceImpl(), args);
            });
    }
}
(2) 延迟初始化
代码语言:javascript
代码运行次数:0
运行
复制
public class LazyInitFactoryBean implements FactoryBean<ExpensiveBean> {
    private ExpensiveBean instance;

    @Override
    public ExpensiveBean getObject() {
        if (instance == null) {
            instance = new ExpensiveBean(); // 延迟初始化
        }
        return instance;
    }
}

7. 总结

维度

BeanFactory

FactoryBean

本质

Spring 容器的根接口,管理所有 Bean 的生命周期。

一个特殊 Bean,用于封装复杂对象的创建逻辑。

获取方式

getBean("beanName") 返回容器中的 Bean 实例。

getBean("factoryBeanName") 返回 getObject() 的结果,getBean("&factoryBeanName") 返回 FactoryBean 本身。

典型用途

Spring 容器的基础功能(如依赖注入、生命周期管理)。

创建动态代理、连接池、复杂对象等。

  • BeanFactorySpring 容器本身,负责管理所有 Bean。
  • FactoryBean容器中的一个 Bean,负责 生产其他 Bean
  • &beanName 是访问 FactoryBean 本身的“密钥”。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java金融 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 定义与角色
  • 2. 核心区别
  • 3. 使用场景与示例
    • (1) BeanFactory 的使用
    • (2) FactoryBean 的使用
  • 1. MyBatis 的 SqlSessionFactoryBean
  • 2. OpenFeign 的 FeignClientFactoryBean
  • 3. Redis 的 RedisConnectionFactoryBean
  • 4. RocketMQ 的 RocketMQTemplate
  • 5. Quartz 的 SchedulerFactoryBean
  • 6. Dubbo 的 ServiceBean
  • 7. Kafka 的 KafkaTemplate
  • 总结对比
  • 4. 获取 FactoryBean 本身
  • 5. 常见问题与解决方案
    • 问题1:混淆 BeanFactory 和 FactoryBean 的功能
    • 问题2:期望获取 FactoryBean 实例却得到其创建的 Bean
    • 问题3:未正确实现 getObjectType() 导致类型检查失败
  • 6. 高级应用场景
    • (1) 动态代理生成
    • (2) 延迟初始化
  • 7. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档