1. FactoryBean核心概念解析
在Spring框架中,FactoryBean是一个容易被初学者混淆的重要接口。与BeanFactory不同,FactoryBean是一种特殊的Bean类型,它的核心职责是作为其他对象的工厂。当我们需要创建复杂对象或需要精细控制Bean的实例化过程时,FactoryBean就显示出其独特价值。
1.1 FactoryBean与BeanFactory的区别
虽然名称相似,但FactoryBean和BeanFactory在Spring中扮演着完全不同的角色:
- BeanFactory:是Spring IoC容器的根接口,负责管理所有Bean的生命周期,是整个框架的基础设施
- FactoryBean:是一个特殊的Bean工厂接口,用于创建和管理其他Bean实例
这种命名上的相似性确实容易造成混淆,但记住一个简单的区分方法:BeanFactory是"工厂的工厂",而FactoryBean是"对象的工厂"。
1.2 FactoryBean的核心方法
FactoryBean接口定义了三个关键方法:
public interface FactoryBean<T> { // 返回由该FactoryBean创建的对象实例 T getObject() throws Exception; // 返回创建的对象的类型 Class<?> getObjectType(); // 指示getObject()返回的对象是否是单例 boolean isSingleton(); }这三个方法构成了FactoryBean的核心机制。getObject()是实际创建对象的地方,getObjectType()帮助Spring了解所创建对象的类型,而isSingleton()则控制对象的作用域。
2. FactoryBean的深入工作机制
2.1 FactoryBean的生命周期
FactoryBean本身也是一个由Spring管理的Bean,因此它具有完整的Bean生命周期。但需要注意的是,FactoryBean创建的对象的生命周期与FactoryBean本身是分离的:
- 实例化阶段:Spring容器创建FactoryBean实例
- 属性注入:如果FactoryBean有任何依赖,Spring会进行注入
- 初始化回调:执行InitializingBean.afterPropertiesSet()或自定义init方法
- 对象创建:当需要获取目标对象时,调用getObject()方法
- 销毁阶段:容器关闭时,执行DisposableBean.destroy()或自定义destroy方法
重要提示:Spring只会自动管理FactoryBean实例的生命周期,而不会自动管理getObject()返回对象的生命周期。如果返回的对象需要特殊清理,应该实现DisposableBean接口或定义destroy方法。
2.2 获取FactoryBean及其产品
Spring提供了特殊的语法来区分获取FactoryBean本身和它创建的对象:
// 获取FactoryBean创建的对象(默认行为) Object product = context.getBean("myFactoryBean"); // 获取FactoryBean实例本身(添加&前缀) FactoryBean<?> factory = (FactoryBean<?>) context.getBean("&myFactoryBean");这种设计使得我们可以灵活地访问工厂或其产品,根据实际需求选择。
3. FactoryBean的典型使用场景
3.1 动态对象创建
当我们需要根据运行时条件动态创建对象时,FactoryBean是理想选择。例如:
public class DynamicDataSourceFactoryBean implements FactoryBean<DataSource> { private String environment; @Override public DataSource getObject() throws Exception { if ("production".equals(environment)) { return createProductionDataSource(); } else { return createDevelopmentDataSource(); } } // 其他方法实现... }这种模式允许我们在Spring配置中保持简洁,同时将复杂的创建逻辑封装在FactoryBean内部。
3.2 遗留系统集成
当需要将非Spring管理的对象(如传统JDBC连接、第三方库实例等)集成到Spring容器中时,FactoryBean可以作为适配器:
public class LegacySystemAdapterFactoryBean implements FactoryBean<LegacyService> { @Override public LegacyService getObject() throws Exception { // 复杂的初始化逻辑 LegacyService service = LegacyServiceFactory.createInstance(); service.configure(...); return service; } // 其他方法实现... }3.3 代理对象创建
FactoryBean常用于创建AOP代理或其他装饰器模式实现:
public class ServiceProxyFactoryBean implements FactoryBean<Object> { private Object target; private String interfaceName; @Override public Object getObject() throws Exception { return Proxy.newProxyInstance( getClass().getClassLoader(), new Class<?>[] { Class.forName(interfaceName) }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) { // 前置处理 Object result = method.invoke(target, args); // 后置处理 return result; } }); } // 其他方法实现... }4. FactoryBean的高级特性与陷阱
4.1 循环引用问题
由于FactoryBean的getObject()方法可能在Spring初始化过程的早期被调用,这时如果尝试注入尚未完全初始化的依赖,会导致FactoryBeanNotInitializedException。解决这个问题的方法包括:
- 实现SmartFactoryBean接口,控制初始化时机
- 使用@Lazy延迟注入
- 重构设计,消除循环依赖
4.2 作用域控制
isSingleton()方法的返回值决定了getObject()是否总是返回同一个实例。但要注意:
- 返回true时,对象会被缓存,多次调用getObject()返回同一实例
- 返回false时,每次都会创建新实例,Spring不会缓存这些对象
public class PrototypeFactoryBean implements FactoryBean<Object> { @Override public boolean isSingleton() { return false; // 每次获取新实例 } // 其他方法实现... }4.3 内置FactoryBean实现
Spring提供了多种实用的FactoryBean实现:
- ListFactoryBean:创建List集合
- MapFactoryBean:创建Map集合
- SetFactoryBean:创建Set集合
- PropertyPathFactoryBean:访问嵌套属性
- MethodInvokingFactoryBean:调用方法并返回结果
虽然这些实现最初是为XML配置设计的,但在某些特殊场景下仍然有用:
@Configuration public class AppConfig { @Bean public ListFactoryBean sampleList() { ListFactoryBean factory = new ListFactoryBean(); factory.setTargetListClass(ArrayList.class); factory.setSourceList(Arrays.asList("item1", "item2", "item3")); return factory; } }5. FactoryBean实战经验与最佳实践
5.1 性能优化技巧
- 缓存策略:对于创建成本高的对象,在isSingleton()返回true的同时,在getObject()中实现缓存逻辑
- 延迟初始化:对于不立即需要的资源,实现SmartFactoryBean的isEagerInit()返回false
- 资源清理:确保实现DisposableBean或定义destroy方法释放资源
5.2 常见问题排查
- ClassCastException:确保getObjectType()返回正确的类型,避免Spring类型检查失败
- 过早初始化:检查是否在@PostConstruct方法中过早访问FactoryBean产品
- 作用域不符:确认isSingleton()返回值是否符合预期行为
5.3 测试策略
测试FactoryBean时需要考虑两方面:
public class MyFactoryBeanTest { @Test public void testFactoryBeanItself() { ApplicationContext ctx = ...; MyFactoryBean factory = ctx.getBean("&myFactoryBean", MyFactoryBean.class); // 测试工厂本身的属性等 } @Test public void testFactoryProduct() { ApplicationContext ctx = ...; Product product = ctx.getBean("myFactoryBean", Product.class); // 测试产品对象 } }5.4 现代Spring中的替代方案
虽然FactoryBean仍然有用,但在Spring 5.x+中,一些场景可以考虑替代方案:
- @Bean方法:对于简单工厂场景,使用@Bean方法更直观
- Supplier接口:结合Spring 5的ObjectProvider使用
- 自定义条件逻辑:使用@Conditional系列注解
然而,对于需要复杂初始化逻辑或动态决策的场景,FactoryBean仍然是首选方案。
6. 自定义FactoryBean实现示例
让我们通过一个完整的示例展示如何实现一个功能完善的FactoryBean:
public class JdbcTemplateFactoryBean implements FactoryBean<JdbcTemplate>, InitializingBean, DisposableBean { private DataSource dataSource; private boolean lazyInit = false; private JdbcTemplate jdbcTemplate; @Override public JdbcTemplate getObject() throws Exception { if (jdbcTemplate == null && !lazyInit) { afterPropertiesSet(); } return jdbcTemplate; } @Override public Class<?> getObjectType() { return JdbcTemplate.class; } @Override public boolean isSingleton() { return true; } @Override public void afterPropertiesSet() throws Exception { if (dataSource == null) { throw new IllegalStateException("DataSource must be set"); } this.jdbcTemplate = new JdbcTemplate(dataSource); } @Override public void destroy() throws Exception { if (jdbcTemplate != null) { // 执行任何必要的清理 } } // 标准的setter方法 public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public void setLazyInit(boolean lazyInit) { this.lazyInit = lazyInit; } }这个实现展示了几个关键点:
- 实现了完整的生命周期接口
- 支持延迟初始化
- 包含必要的空值检查
- 提供了资源清理机制
在实际项目中,FactoryBean的这种封装能力可以大大简化配置,同时保持灵活性。