1. FactoryBean的本质与设计初衷
FactoryBean是Spring框架中一个特殊的接口,它的存在打破了传统Bean实例化的单一模式。与普通Bean直接由Spring容器通过反射实例化不同,FactoryBean本质上是一个能生产对象的工厂。这种设计源于两个核心需求:
第一,当Bean的实例化过程过于复杂时,传统的XML或注解配置方式会变得臃肿且难以维护。比如MyBatis的SqlSessionFactory,需要配置数据源、mapper文件位置、类型别名等多达十余项参数。通过实现FactoryBean接口,可以用Java代码灵活控制实例化逻辑,将复杂配置封装在工厂内部。
第二,第三方库的集成往往需要特殊处理。以Dubbo的ReferenceBean为例,它需要处理服务发现、负载均衡、集群容错等分布式逻辑,这些无法通过简单配置实现。FactoryBean提供了接入这些外部系统的标准方式。
关键理解:FactoryBean是Spring对工厂方法模式的实现,它的核心价值在于将对象创建过程从容器转移到自定义逻辑中。
2. 核心方法与运行机制解析
2.1 三方法契约详解
FactoryBean接口定义的三个方法构成了完整的工厂协议:
public interface FactoryBean<T> { T getObject() throws Exception; // 生产目标对象 Class<?> getObjectType(); // 声明产品类型 default boolean isSingleton() { // 控制产品作用域 return true; } }getObject()是核心生产方法,其实现需要注意:
- 每次调用可能返回新实例(视isSingleton返回值而定)
- 允许返回null(需用@Nullable标注)
- 可以抛出检查异常
getObjectType()的特殊性常被误解:
@Component public class MyFactory implements FactoryBean<Foo> { @Override public Class<?> getObjectType() { return Bar.class; // 实际返回类型可与泛型参数不同 } }这里虽然泛型声明为Foo,但通过getObjectType()声明实际生产的是Bar类型。Spring容器会以此方法返回值作为类型匹配依据。
2.2 命名访问的特殊规则
FactoryBean在容器中的访问遵循特殊命名约定:
getBean("myFactory")返回工厂产品getBean("&myFactory")返回工厂本身
这种设计带来一个典型陷阱:
@Autowired private MyFactory myFactory; // 注入的实际上是产品对象! @Autowired private FactoryBean<Foo> myFactory; // 这样才会注入工厂3. 典型应用场景深度剖析
3.1 AOP代理创建机制
Spring AOP的核心实现ProxyFactoryBean是FactoryBean的经典应用:
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware { public Object getObject() { return getProxy(); // 动态生成代理对象 } }其配置示例:
<bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="userService"/> <property name="interceptorNames"> <list> <value>loggingInterceptor</value> </list> </property> </bean>3.2 MyBatis集成实现
SqlSessionFactoryBean展示了如何封装复杂初始化逻辑:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean { private DataSource dataSource; private String mapperLocations; public SqlSessionFactory getObject() throws Exception { SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); return builder.build(createSqlSessionFactoryConfiguration()); } private Configuration createSqlSessionFactoryConfiguration() { // 构建包含数据源、缓存等复杂配置的Configuration对象 } }3.3 动态策略模式实现
通过FactoryBean可以实现运行时策略切换:
public class StrategyFactoryBean implements FactoryBean<Processor> { @Value("${system.strategy}") private String strategyName; public Processor getObject() { switch(strategyName) { case "A": return new FastProcessor(); case "B": return new SafeProcessor(); default: throw new IllegalArgumentException(); } } }4. 高级应用与性能优化
4.1 延迟初始化模式
结合SmartFactoryBean实现智能初始化控制:
public class LazyFactoryBean implements SmartFactoryBean<ExpensiveObject> { public boolean isEagerInit() { return false; // 延迟到首次请求时初始化 } public ExpensiveObject getObject() { return new ExpensiveObject(loadHeavyResources()); } }4.2 对象池实现
通过FactoryBean管理对象池:
public class PooledFactoryBean implements FactoryBean<Connection>, DisposableBean { private final BlockingQueue<Connection> pool = new LinkedBlockingQueue<>(10); public Connection getObject() throws InterruptedException { return pool.take(); // 从池中获取 } public void returnObject(Connection conn) { pool.offer(conn); // 返回到池中 } }4.3 缓存优化策略
public class CachedFactoryBean implements FactoryBean<ReportGenerator> { private volatile ReportGenerator cachedInstance; public synchronized ReportGenerator getObject() { if (cachedInstance == null) { cachedInstance = createNewInstance(); } return cachedInstance; } private ReportGenerator createNewInstance() { // 执行耗时的初始化操作 } }5. 常见问题排查指南
5.1 循环依赖问题
当FactoryBean与其他Bean存在循环依赖时,需要特别注意:
@Component public class ServiceA { @Autowired private ProductB productB; // 依赖FactoryBean生产的产品 } @Component public class FactoryB implements FactoryBean<ProductB> { @Autowired private ServiceA serviceA; // 与ServiceA形成循环 public ProductB getObject() { return new ProductB(serviceA); } }解决方案:
- 使用@Lazy延迟注入
- 通过Setter方法而非字段注入
- 实现SmartFactoryBean的isEagerInit()返回false
5.2 类型匹配异常
典型错误场景:
@Configuration public class Config { @Bean public FactoryBean<CharSequence> stringFactory() { return new StringFactoryBean(); } } @Autowired private String text; // 注入失败!容器中实际是CharSequence类型解决方法:
- 在getObjectType()中精确声明返回类型
- 使用具体类型而非接口进行注入
5.3 作用域失效问题
当isSingleton()返回false时,需注意:
public class PrototypeFactory implements FactoryBean<Thread> { public boolean isSingleton() { return false; } public Thread getObject() { return new Thread(); } } @Autowired private Thread thread1; @Autowired private Thread thread2; // thread1和thread2实际上是同一个实例!原因:Spring对FactoryBean产品的处理有特殊逻辑,解决方案:
- 使用ObjectProvider延迟获取
- 通过方法注入而非字段注入
6. 源码级实现原理
6.1 容器集成流程
在AbstractBeanFactory中处理FactoryBean的核心逻辑:
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // 处理&前缀请求 if (BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } // 处理普通FactoryBean产品请求 if (beanInstance instanceof FactoryBean) { return getObjectFromFactoryBean((FactoryBean<?>) beanInstance, name, beanName); } return beanInstance; }6.2 产品对象缓存机制
FactoryBeanRegistrySupport中的关键实现:
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(); protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String name) { if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (this.factoryBeanObjectCache) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { object = doGetObjectFromFactoryBean(factory, name); this.factoryBeanObjectCache.put(beanName, object); } return object; } } return doGetObjectFromFactoryBean(factory, name); }6.3 与BeanPostProcessor的交互
FactoryBean与后置处理器的执行顺序:
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
- FactoryBean.getObject()
- BeanPostProcessor.postProcessAfterInitialization
这种顺序导致的一个实际影响:对FactoryBean产品应用的BeanPostProcessor需要在getObject()内部手动处理。
7. 最佳实践与性能考量
7.1 线程安全实现建议
对于非单例FactoryBean的线程安全处理:
public class ThreadSafeFactory implements FactoryBean<Counter> { private final AtomicInteger idGenerator = new AtomicInteger(); public Counter getObject() { return new Counter(idGenerator.incrementAndGet()); } public boolean isSingleton() { return false; } }7.2 资源清理模式
实现DisposableBean正确处理资源释放:
public class ResourceFactory implements FactoryBean<Connection>, DisposableBean { private Connection connection; public Connection getObject() throws SQLException { if (connection == null) { connection = DriverManager.getConnection(url); } return connection; } public void destroy() throws SQLException { if (connection != null) { connection.close(); } } }7.3 性能优化技巧
- 对于昂贵对象,采用双重检查锁实现延迟加载:
public class ExpensiveObjectFactory implements FactoryBean<Expensive> { private volatile Expensive instance; public Expensive getObject() { Expensive local = instance; if (local == null) { synchronized (this) { local = instance; if (local == null) { instance = local = createExpensiveInstance(); } } } return local; } }- 避免在getObject()中执行耗时操作,推荐采用异步初始化:
public class AsyncFactory implements FactoryBean<Data>, InitializingBean { private CompletableFuture<Data> future; public void afterPropertiesSet() { future = CompletableFuture.supplyAsync(this::loadData); } public Data getObject() throws Exception { return future.get(); // 阻塞直到数据加载完成 } }在SpringBoot项目中,FactoryBean的自动装配需要特别注意类型处理。一个常见的陷阱是直接注入工厂产品而丢失了FactoryBean本身的元数据。正确的做法是通过ObjectProvider或特定类型注入:
@Autowired private ObjectProvider<MyProduct> productProvider; // 安全获取方式 @Autowired private MyFactoryBean factoryBean; // 直接注入工厂本身