在Spring框架的设计哲学中,FactoryBean代表着一种精妙的工厂模式实现——它不是普通的Bean,而是能够生产Bean的工厂。这种设计使得开发者可以介入Spring容器的对象创建过程,实现比简单依赖注入更复杂的实例化逻辑。
FactoryBean接口完美诠释了工厂模式的三大核心要素:
与传统的工厂模式不同,FactoryBean通过实现这三个接口方法,将自身无缝融入Spring的IoC容器体系。当Spring容器检测到某个Bean实现了FactoryBean接口时,它会智能地调用getObject()方法而非直接实例化Bean本身,这种机制使得FactoryBean成为Spring中实现复杂对象创建的"秘密武器"。
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
这个方法定义了工厂生产的核心逻辑。在Spring容器初始化时,如果BeanDefinition中的beanClass实现了FactoryBean接口,容器会通过反射实例化FactoryBean后,调用其getObject()方法获取实际需要的对象。值得注意的是,这个方法允许抛出受检异常,这为复杂对象的创建提供了容错空间。
该方法返回工厂生产对象的类型信息,在Spring的类型匹配和自动装配中起着关键作用。特别在泛型场景下,准确的类型信息能确保依赖注入的正确性。Spring会在以下场景调用此方法:
通过这个布尔方法,FactoryBean可以声明其生产的对象是单例还是原型。当返回true时,Spring会将getObject()返回的对象缓存到单例池中;返回false则每次都会调用getObject()创建新实例。这种设计使得FactoryBean既能实现传统工厂模式,也能支持更灵活的原型模式。
Spring容器通过特殊的命名约定来处理FactoryBean:
这种机制在AbstractBeanFactory中实现,关键代码如下:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
object = getObjectFromFactoryBean(factory, beanName, !mbd.isSingleton());
}
return object;
}
FactoryBean在Spring容器的生命周期中表现出独特行为:
这种分阶段处理使得FactoryBean既能作为普通Bean被管理,又能作为工厂生产其他对象。
在Spring的实际运行中,FactoryBean的这种设计使得它成为整合第三方库的桥梁。比如当MyBatis需要将SqlSessionFactory交给Spring管理时,正是通过SqlSessionFactoryBean这个FactoryBean实现类完成的,这种设计既保持了MyBatis的独立性,又实现了与Spring容器的无缝集成。
在MyBatis与Spring的深度整合中,SqlSessionFactoryBean堪称FactoryBean设计模式应用的典范。这个看似简单的工厂类背后,隐藏着Spring对复杂对象创建过程的精妙封装艺术。
在传统MyBatis standalone模式下,构建SqlSessionFactory需要繁琐的XML配置:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath*:mapper/**/*.xml"/>
</bean>
而通过SqlSessionFactoryBean的封装,开发者可以用纯Java配置实现相同功能:
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/**/*.xml"));
return factoryBean;
}
这种转变不仅仅是语法糖,更是对象创建逻辑的范式迁移。SqlSessionFactoryBean通过实现FactoryBean接口,将原本需要数十行代码的初始化过程,简化为几个简单的setter方法调用。
深入SqlSessionFactoryBean源码,可以看到其getObject()方法实现了典型的分层处理逻辑:
这种分层设计使得每个阶段的配置都可以通过setter方法独立控制,例如通过setTypeAliasesPackage()配置别名扫描,通过setPlugins()添加MyBatis插件。这种设计完美体现了"开闭原则"——需要扩展新功能时无需修改FactoryBean的核心逻辑。
SqlSessionFactoryBean最精妙之处在于对MyBatis核心特性的无缝集成。在getObject()方法返回的SqlSessionFactory中,已经预置了:
这些复杂功能对使用者完全透明,开发者只需关注业务相关的Mapper接口定义。这种封装程度使得MyBatis在Spring环境中几乎达到"零配置"的体验,例如自动将Mapper接口注册为Spring Bean:
@MapperScan("com.example.mapper")
public class AppConfig {
// 无需单独声明每个Mapper接口
}
SqlSessionFactoryBean在错误处理方面展现了工业级代码的严谨性。其getObject()方法包含细致的异常转换逻辑,将MyBatis原始的IOException、XMLParseException等转换为Spring的NestedRuntimeException,确保异常信息既包含底层细节,又符合Spring的统一异常处理体系。这种设计使得开发者可以在@Transactional注解中无缝处理MyBatis的数据库异常。
在2025年的MyBatis 3.6+版本中,SqlSessionFactoryBean新增了几个关键优化:
这些优化使得在微服务架构下,包含数百个Mapper接口的应用启动时间从原来的10+秒缩短到2秒以内。
通过FactoryBean的封装,SqlSessionFactory创建的事务管理器可以与Spring的@Transactional注解完美协作。其核心秘密在于:
这种集成使得开发者可以像使用Spring JDBC那样自然地使用MyBatis,却无需关心底层连接管理细节。
在Spring Boot 3.x环境中,SqlSessionFactoryBean进一步与现代条件装配机制结合。通过@ConditionalOnMissingBean等条件注解,可以实现:
@Bean
@ConditionalOnClass(SqlSessionFactory.class)
@ConditionalOnMissingBean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
// 仅当不存在其他SqlSessionFactory时自动配置
}
这种模式使得库开发者可以提供默认配置,同时允许应用开发者随时覆盖默认实现。
通过SqlSessionFactoryBean这个典型案例,我们可以看到FactoryBean模式在复杂对象创建场景中的独特价值:它既保持了配置的简洁性,又提供了足够的扩展点;既封装了技术细节,又保留了必要的控制权。这种平衡艺术正是Spring框架设计哲学的精髓所在。
在Spring框架的IoC容器体系中,FactoryBean与BeanFactory这两个名称相似的接口常常让开发者感到困惑。虽然它们都带有"工厂"的概念,但在设计定位和使用方式上却有着本质的区别。理解这两者的差异,是掌握Spring高级特性的关键一步。
BeanFactory作为Spring框架最基础的IoC容器接口,承担着Bean生命周期管理的核心职责。它是整个依赖注入机制的基础设施,定义了getBean()、containsBean()等基础方法,负责实例化、配置和管理应用程序中的各种Bean对象。在2025年的Spring 6.x版本中,BeanFactory接口体系依然保持着其核心地位,虽然大多数应用会直接使用更高级的ApplicationContext,但其底层实现仍然基于BeanFactory的规范。
而FactoryBean则是一种特殊类型的Bean,本质上是一个能够生产其他对象的工厂Bean。它通过实现FactoryBean接口,将复杂对象的创建逻辑封装在getObject()方法中。这种设计使得开发者可以通过标准的Bean定义方式,在IoC容器中配置复杂的对象创建过程。例如在Spring集成MyBatis时,SqlSessionFactoryBean就是通过这种机制将繁琐的SqlSessionFactory构建过程简化为声明式配置。
从源码层面看,BeanFactory定义了约15个核心方法,主要包括:
Object getBean(String name)
<T> T getBean(Class<T> requiredType)
boolean containsBean(String name)
Class<?> getType(String name)
这些方法构成了IoC容器最基础的服务能力,关注的是Bean的获取与管理。
而FactoryBean接口则精简得多,仅定义了三个关键方法:
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
这三个方法共同完成了工厂模式的核心功能:getObject()负责实际产品的创建,getObjectType()声明产品类型,isSingleton()控制产品的作用域。这种简洁的设计使得FactoryBean实现类可以专注于对象创建逻辑的封装。
在实际使用中,这两者的获取方式也体现了它们的本质区别。当从BeanFactory中获取普通Bean时,直接使用beanName即可:
Object regularBean = beanFactory.getBean("myBean");
但如果要获取FactoryBean生产的对象,容器会自动调用其getObject()方法。若要获取FactoryBean本身而非其产品,则需要在beanName前添加"&"前缀:
Object factoryProduct = beanFactory.getBean("myFactoryBean");
FactoryBean<?> factoryBean = (FactoryBean<?>) beanFactory.getBean("&myFactoryBean");
这个特殊语法在Spring框架中保持了一致性,从早期的2.x版本到2025年的最新版本都遵循这一约定。它直观地反映了FactoryBean的双重身份:不加前缀时作为工厂,加上前缀时作为普通Bean。
从设计模式的角度分析,BeanFactory体现了容器模式的思想,它管理着大量对象的生命周期,类似于一个对象池。而FactoryBean则是工厂方法模式(Factory Method Pattern)的实现,将对象创建的具体过程延迟到子类中决定。
值得注意的是,FactoryBean的实现往往还结合了其他设计模式。例如MyBatis的SqlSessionFactoryBean就采用了建造者模式(Builder Pattern)来构造SqlSessionFactory,通过XML配置将复杂的构建过程分解为多个步骤。这种模式组合展现了Spring框架在设计上的灵活性。
BeanFactory作为基础设施,其应用场景贯穿整个Spring应用的生命周期。在2025年的云原生环境中,BeanFactory的扩展实现如GenericApplicationContext等,仍然是Spring Cloud组件集成的基础。
而FactoryBean则更多出现在需要复杂初始化的场景中:
在Spring的扩展机制中,BeanFactory通过BeanFactoryPostProcessor接口允许开发者对容器配置进行后处理。而FactoryBean本身就是一个扩展点,开发者可以通过实现这个接口来创建自定义的工厂逻辑。
Spring 6.x在保持这些核心机制稳定的同时,优化了对FactoryBean的处理流程。例如,在循环依赖的处理中,对FactoryBean的解析阶段进行了更精细的控制,使得复杂工厂Bean的初始化过程更加可靠。
从性能角度看,BeanFactory的核心方法如getBean()经过了二十多年的优化,在2025年的版本中已经达到了极高的效率。而FactoryBean的性能则主要取决于getObject()方法的实现质量。优秀的FactoryBean实现应当:
在Spring的最新版本中,对FactoryBean的调用过程加入了更多缓存机制,使得频繁获取工厂产品时的性能损耗降到最低。
在实际开发中,容易出现的混淆包括:
最佳实践建议:
随着Spring框架的演进,虽然出现了更多声明式的配置方式(如Java Config),但FactoryBean仍然在某些复杂场景下保持着不可替代的价值。理解它与BeanFactory的本质区别,有助于开发者在适当的场景选择正确的工具。
在Spring框架的面试中,FactoryBean相关的考察点往往集中在两个核心问题上:FactoryBean与BeanFactory的本质区别,以及如何正确获取FactoryBean实例本身。这两个问题看似简单,却能准确考察候选人对Spring IoC容器底层机制的理解深度。
许多初学者容易混淆FactoryBean和BeanFactory这两个名称相似但功能完全不同的接口。实际上,它们是Spring框架中工厂模式的两个不同实现维度:
getObject()
:工厂方法,返回实际要创建的对象getObjectType()
:声明工厂生产的产品类型isSingleton()
:控制产品是否为单例在实际开发中,我们可能需要获取两种不同的对象:FactoryBean生产的产品对象,或者FactoryBean本身。Spring通过特殊的命名规则区分这两种情况:
// 获取SqlSessionFactory实例(FactoryBean的产品)
SqlSessionFactory sqlSessionFactory =
applicationContext.getBean("sqlSessionFactory");
// 获取SqlSessionFactoryBean实例本身
FactoryBean<?> factoryBean =
(FactoryBean<?>) applicationContext.getBean("&sqlSessionFactory");
这个问题常常作为上述知识点的延伸考察,主要涉及以下实际场景:
MyFactoryBean factory = (MyFactoryBean) ctx.getBean("&myBean");
if(factory.isSingleton()) {
// 处理单例场景的特殊逻辑
}
SchedulerFactoryBean schedulerFactory =
(SchedulerFactoryBean) context.getBean("&scheduler");
schedulerFactory.setAutoStartup(false);
问题1:FactoryBean.getObject()每次调用都会创建新实例吗? 这取决于isSingleton()的返回值。当返回true时,Spring会缓存第一次getObject()的结果;返回false则每次都会调用getObject()。但要注意,即使返回false,FactoryBean实例本身仍然是单例。
问题2:@Autowired注入的是FactoryBean还是其产品? Spring默认注入的是工厂产品,这是符合大多数场景的合理设计。如果需要注入FactoryBean本身,可以通过以下方式:
@Autowired
@Qualifier("&myFactoryBean")
private MyFactoryBean factoryBean;
问题3:FactoryBean与@Bean注解方法有何异同? 两者都能封装复杂对象的创建逻辑,但FactoryBean作为接口实现类:
理解AbstractBeanFactory中的以下代码片段,能帮助应对更深入的面试追问:
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;
}
这段代码清晰地展现了Spring如何通过beanName是否带有"&"前缀来决定返回工厂实例还是其产品对象。在性能优化方面,Spring会对FactoryBean产品进行缓存(当isSingleton()返回true时),这个细节在讨论Spring容器性能特征时值得关注。
在Spring生态系统中,FactoryBean的高级应用场景远比表面看起来丰富。通过巧妙运用这个设计模式,开发者能够解决许多传统Bean定义方式难以处理的复杂场景。
FactoryBean特别适合用于创建动态代理对象。以2025年Spring 6.3版本为例,我们可以构建一个通用的服务代理工厂:
public class ServiceProxyFactoryBean implements FactoryBean<Object> {
private Class<?> serviceInterface;
private String targetServiceName;
@Override
public Object getObject() throws Exception {
// 使用JDK动态代理创建服务接口实现
return Proxy.newProxyInstance(
serviceInterface.getClassLoader(),
new Class<?>[] {serviceInterface},
(proxy, method, args) -> {
Object target = applicationContext.getBean(targetServiceName);
return method.invoke(target, args);
});
}
// 其他必要方法实现...
}
这种模式在微服务架构中尤为实用,可以统一处理服务调用前的认证、日志等横切关注点,同时保持接口调用的透明性。
结合Spring的@Conditional机制,FactoryBean可以实现更智能的对象创建逻辑。例如,根据不同的环境变量创建不同的数据源实现:
public class AdaptiveDataSourceFactory implements FactoryBean<DataSource>, EnvironmentAware {
private Environment env;
@Override
public DataSource getObject() throws Exception {
String dbType = env.getProperty("db.type");
if ("oracle".equalsIgnoreCase(dbType)) {
return buildOracleDataSource();
} else {
return buildMySQLDataSource();
}
}
// 环境感知方法实现...
}
对于需要昂贵系统资源的对象,FactoryBean提供了完美的延迟加载方案。2025年最新Spring版本增强了对虚拟线程的支持,使得这种模式更加高效:
public class ResourceIntensiveFactory implements FactoryBean<ExpensiveResource> {
private ExpensiveResource instance;
@Override
public synchronized ExpensiveResource getObject() throws Exception {
if (instance == null) {
instance = VirtualThread.start(() -> {
// 在虚拟线程中执行耗时初始化
return initializeResource();
}).join();
}
return instance;
}
// 资源初始化逻辑...
}
在处理复杂对象图时,FactoryBean可以封装整个构建过程。以构建一个完整的消息处理管道为例:
public class MessagePipelineFactory implements FactoryBean<MessagePipeline> {
@Autowired private List<MessageFilter> filters;
@Autowired private MessageSerializer serializer;
@Override
public MessagePipeline getObject() throws Exception {
MessagePipeline pipeline = new MessagePipeline();
filters.stream()
.sorted(Comparator.comparingInt(MessageFilter::getOrder))
.forEach(pipeline::addFilter);
pipeline.setSerializer(serializer);
return pipeline;
}
// 其他方法实现...
}
结合字节码生成库如ByteBuddy,FactoryBean可以实现真正的动态类型创建。这种技术在2025年的Spring生态中越来越常见:
public class DynamicDtoFactory implements FactoryBean<Object> {
private Class<?> dtoInterface;
@Override
public Object getObject() throws Exception {
return new ByteBuddy()
.subclass(Object.class)
.implement(dtoInterface)
.method(ElementMatchers.any())
.intercept(InvocationHandlerAdapter.of(new DtoInvocationHandler()))
.make()
.load(getClass().getClassLoader())
.getLoaded()
.newInstance();
}
// 动态DTO处理方法...
}
在Spring Boot应用中,FactoryBean可以与@ConfigurationProperties深度结合,创建类型安全的配置对象:
@ConfigurationProperties(prefix = "app.mail")
public class MailConfigFactory implements FactoryBean<MailService> {
private String host;
private int port;
private String username;
@Override
public MailService getObject() throws Exception {
return new MailService(host, port, username);
}
// 配置属性getter/setter...
}
对于高频调用的FactoryBean,2025年的最佳实践建议:
@RefreshScope
public class CloudAwareFactory implements FactoryBean<CloudClient> {
@Value("${cloud.endpoint}")
private String endpoint;
// 支持配置热更新的客户端实现...
}
这些高级应用展示了FactoryBean在复杂场景下的强大灵活性。从动态代理到条件化创建,从资源管理到性能优化,FactoryBean模式持续演进,在Spring生态中扮演着不可替代的角色。
[1] : https://blog.csdn.net/weixin_51786043/article/details/148202104
[2] : https://developer.aliyun.com/article/1617787
[3] : https://www.cnblogs.com/yichunguo/p/13922189.html
[4] : https://cloud.tencent.com/developer/article/2497197