写点什么

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

  • 2025-06-18
    福建
  • 本文字数:3707 字

    阅读完需:约 12 分钟

引言


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


1. 定义与角色



2. 核心区别



3. 使用场景与示例


(1) BeanFactory 的使用


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

  • 示例

// 通过 BeanFactory 获取 BeanBeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");UserService userService = factory.getBean("userService", UserService.class);
复制代码


(2) FactoryBean 的使用


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

  • 示例

// 定义 FactoryBeanpublic 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 容器@Configurationpublic class AppConfig { @Bean public FactoryBean<Connection> connectionFactory() { return new MyConnectionFactory(); }}
// 使用@Autowiredprivate Connection connection; // 实际注入的是 getObject() 返回的 Connection
复制代码


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


1. MyBatis 的 SqlSessionFactoryBean


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

代码示例

<!-- 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 调用代理对象)。

代码示例

@Configurationpublic 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 的 Target 和 Encoder/Decoder 配置。

  • getObject() 返回动态代理的 Feign 客户端实例。

  • 支持自定义拦截器、重试策略等。


3. Redis 的 RedisConnectionFactoryBean


作用:创建 Redis 连接池(如 JedisConnectionFactory 或 LettuceConnectionFactory)。

代码示例

<!-- 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 生产者和消费者的创建逻辑。

代码示例

@Configurationpublic 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),集成任务调度逻辑。

代码示例

<!-- 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 服务,封装服务暴露和注册逻辑。

代码示例

<!-- 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 生产者和消费者的创建逻辑。

代码示例

@Configurationpublic class KafkaConfig {    @Bean    public KafkaTemplate<String, String> kafkaTemplate() {        return new KafkaTemplate<>(new ProducerFactory<>());    }}
复制代码


实现原理

  • KafkaTemplate 通过 FactoryBean 模式初始化生产者工厂。

  • getObject() 返回配置好的 KafkaTemplate 实例。

  • 支持消息发送、消费者监听等操作。


总结对比



  • 解耦配置与逻辑:通过 FactoryBean 将复杂初始化逻辑封装,Spring 容器只需管理 Bean 的声明。

  • 支持动态创建:可根据运行时条件(如环境变量、配置参数)动态生成不同对象。

  • 统一资源管理:集中管理中间件的连接池、配置参数,便于维护和扩展。


4. 获取 FactoryBean 本身


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

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


// 获取 FactoryBean 创建的 BeanConnection connection = context.getBean("connectionFactory", Connection.class);
// 获取 FactoryBean 实例本身MyConnectionFactory factoryBean = (MyConnectionFactory) context.getBean("&connectionFactory");
复制代码


5. 常见问题与解决方案


问题 1:混淆 BeanFactory 和 FactoryBean 的功能

  • 解决方案:明确 BeanFactory 是容器,FactoryBean 是创建 Bean 的工具。


问题 2:期望获取 FactoryBean 实例却得到其创建的 Bean

  • 示例

// 错误:获取的是 Encryptor 实例,而非 FactoryBeanEncryptor encryptor = factory.getBean("encryptor");
// 正确:添加 "&" 前缀获取 FactoryBeanFactoryBean factoryBean = factory.getBean("&encryptor");
复制代码


问题 3:未正确实现 getObjectType() 导致类型检查失败

  • 修复:确保 getObjectType() 返回准确的类型信息。


6. 高级应用场景


(1) 动态代理生成


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) 延迟初始化

public class LazyInitFactoryBean implements FactoryBean<ExpensiveBean> {    private ExpensiveBean instance;
@Override public ExpensiveBean getObject() { if (instance == null) { instance = new ExpensiveBean(); // 延迟初始化 } return instance; }}
复制代码


7. 总结



  • BeanFactory 是 Spring 容器本身,负责管理所有 Bean。

  • FactoryBean 是 容器中的一个 Bean,负责 生产其他 Bean

  • &beanName 是访问 FactoryBean 本身的“密钥”。


文章转载自:java金融

原文链接:https://www.cnblogs.com/root429/p/18933245

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
FactoryBean 和BeanFactory的傻傻的总是分不清?_spring_不在线第一只蜗牛_InfoQ写作社区