目录
Spring 工厂模式创建 Bean 深度解析
本文系统讲解 Spring 中通过工厂创建 Bean 的实现机制,包含 3000 字以上的详细说明、实用代码示例和工程实践指南,适合从入门到精通的开发者学习。
工厂模式在 Spring 中的核心价值
对象创建解耦
- 将对象创建与使用逻辑分离
- 避免业务代码直接使用
new
关键字 - 遵循开闭原则(扩展开放/修改封闭)
复杂场景处理
- 多步骤初始化对象(如数据库连接池)
- 动态配置创建对象
- 无法直接实例化的抽象类/接口
第三方库整合
- 适配遗留系统
- 封装 SDK 的复杂对象创建
静态工厂方法详解
1. 完整工作流程
TargetObject
↓
StaticFactory
↓
SpringContainer
↓
调用静态方法 createXxx()
↓
执行创建逻辑
↓
返回对象实例
↓
管理生命周期
2. 实现步骤详解
目标类示例:
public class DatabaseConfig {
private String url;
private String username;
private int maxConnections;
// 强制使用工厂的私有构造器
private DatabaseConfig() {}
// 生产环境配置工厂方法
public static DatabaseConfig createProductionConfig() {
DatabaseConfig config = new DatabaseConfig();
config.url = "jdbc:mysql://prod-db:3306/appdb";
config.username = "prod_user";
config.maxConnections = 100;
return config;
}
// 测试环境配置工厂方法
public static DatabaseConfig createTestConfig() {
DatabaseConfig config = new DatabaseConfig();
config.url = "jdbc:h2:mem:testdb";
config.username = "test_user";
config.maxConnections = 10;
return config;
}
// getters...
}
XML 配置:
<!-- 生产环境配置 -->
<bean id="prodDbConfig" class="com.config.DatabaseConfig"
factory-method="createProductionConfig"/>
<!-- 测试环境配置 -->
<bean id="testDbConfig" class="com.config.DatabaseConfig"
factory-method="createTestConfig"/>
Java 注解配置:
@Configuration
public class DatabaseConfigProvider {
@Bean(name = "prodDbConfig")
public DatabaseConfig productionConfig() {
return DatabaseConfig.createProductionConfig();
}
@Bean(name = "testDbConfig")
@Profile("test")
public DatabaseConfig testConfig() {
return DatabaseConfig.createTestConfig();
}
}
3. 参数传递技巧
带参数工厂方法:
public class PaymentProcessor {
public static PaymentProcessor createProcessor(String type, String config) {
switch(type) {
case "ALIPAY": return new AlipayProcessor(config);
case "WECHAT": return new WechatProcessor(config);
default: throw new IllegalArgumentException("未知支付类型");
}
}
}
XML 参数配置:
<bean id="alipayProcessor" class="com.payment.PaymentProcessor"
factory-method="createProcessor">
<constructor-arg value="ALIPAY"/>
<constructor-arg value="key=123456;secret=abcdef"/>
</bean>
4. 实际应用案例
Java 核心类工厂使用:
<!-- 创建单例 Runtime 实例 -->
<bean id="runtime" class="java.lang.Runtime"
factory-method="getRuntime"/>
<!-- 创建不可修改集合 -->
<bean id="immutableList" class="java.util.Arrays"
factory-method="asList">
<constructor-arg>
<array value-type="java.lang.String">
<value>Item1</value>
<value>Item2</value>
</array>
</constructor-arg>
</bean>
三、实例工厂方法深度解析
1.完整工作流程
TargetObjectFactoryBean → SpringContainer → 实例化工厂对象 → 注入依赖 → 调用工厂方法 → 执行创建逻辑 → 返回目标对象 → 管理生命周期
2.详细实现步骤
工厂类实现:
public class ConnectionPoolFactory {
private String driverClassName;
private String jdbcUrl;
private int maxPoolSize = 10;
// 依赖注入方法
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
// 工厂方法
public DataSource createDataSource() throws Exception {
// 加载数据库驱动
Class.forName(driverClassName);
// 配置连接池
HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbcUrl);
config.setMaximumPoolSize(maxPoolSize);
// 返回数据源实例
return new HikariDataSource(config);
}
}
XML配置方式:
<!-- 配置工厂实例 -->
<bean id="poolFactory" class="com.factory.ConnectionPoolFactory">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="maxPoolSize" value="20"/>
</bean>
<!-- 通过工厂创建数据源 -->
<bean id="dataSource" factory-bean="poolFactory"
factory-method="createDataSource"/>
Java注解配置:
@Configuration
public class DataSourceConfig {
@Bean
public ConnectionPoolFactory poolFactory() {
ConnectionPoolFactory factory = new ConnectionPoolFactory();
factory.setDriverClassName("com.mysql.cj.jdbc.Driver");
factory.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
factory.setMaxPoolSize(20);
return factory;
}
@Bean
public DataSource dataSource(ConnectionPoolFactory factory) throws Exception {
return factory.createDataSource();
}
}
3. 高级技巧:工厂状态管理
public class PrototypeFactory {
// 工厂状态
private int creationCount = 0;
public Product createProduct() {
creationCount++;
Product product = new Product();
product.setSerialId("PROD-" + creationCount);
return product;
}
}
XML配置示例:
<bean id="prototypeFactory" class="com.factory.PrototypeFactory"/>
<bean id="product1" factory-bean="prototypeFactory"
factory-method="createProduct"/>
<bean id="product2" factory-bean="prototypeFactory"
factory-method="createProduct"/>
4. 真实案例:多数据源切换
public class DynamicDataSourceFactory {
private Map<String, DataSource> dataSources = new HashMap<>();
public void addDataSource(String key, DataSource dataSource) {
dataSources.put(key, dataSource);
}
public DataSource getDataSource(String key) {
return dataSources.get(key);
}
public AbstractRoutingDataSource createRoutingDataSource() {
AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceKey();
}
};
routingDataSource.setTargetDataSources(new HashMap<>(dataSources));
return routingDataSource;
}
}
XML配置:
<bean id="dsFactory" class="com.factory.DynamicDataSourceFactory">
<property name="dataSources">
<map>
<entry key="master" value-ref="masterDataSource"/>
<entry key="slave" value-ref="slaveDataSource"/>
</map>
</property>
</bean>
<bean id="routingDataSource" factory-bean="dsFactory"
factory-method="createRoutingDataSource"/>
四、静态工厂与实例工厂对比
特性 | 静态工厂 | 实例工厂 |
---|---|---|
工厂状态 | 无状态(静态方法) | 可维护状态(实例变量) |
配置复杂度 | 简单(直接调用) | 较复杂(需创建工厂实例) |
适用场景 | 工具类/无状态对象 | 需要配置的复杂对象 |
方法调用 | 类名.方法名() | 工厂实例.方法名() |
生命周期 | 无 | 受Spring容器管理 |
依赖注入 | 仅方法参数 | 工厂属性+方法参数 |
多例支持 | 每次调用创建新对象 | 可通过工厂状态控制 |
性能 | 高效(无额外实例) | 存在工厂实例开销 |
典型应用 | Collections工具类 | 连接池/线程池创建 |
五、最佳实践与高级技巧
-
工厂方法与 FactoryBean 结合
public class HybridFactory implements FactoryBean<DataSource>, InitializingBean {
private String configFile;
private Properties configProps;
public void setConfigFile(String configFile) {
this.configFile = configFile;
}
@Override
public void afterPropertiesSet() throws Exception {
// 加载配置文件
try (InputStream is = getClass().getResourceAsStream(configFile)) {
configProps = new Properties();
configProps.load(is);
}
}
@Override
public DataSource getObject() throws Exception {
// 使用配置创建数据源
HikariConfig config = new HikariConfig();
config.setJdbcUrl(configProps.getProperty("jdbc.url"));
config.setUsername(configProps.getProperty("jdbc.user"));
return new HikariDataSource(config);
}
// 其他 FactoryBean 方法实现...
}
2. 条件化创建技巧
public class EnvironmentAwareFactory {
@Value("${app.env}")
private String environment;
public Logger createLogger() {
return "prod".equals(environment) ? new ProdLogger() : new DevLogger();
}
}
3.解决循环依赖
public class ServiceFactory {
// 使用 ObjectFactory 延迟获取依赖
@Autowired
private ObjectFactory<ServiceA> serviceAProvider;
public ServiceB createServiceB() {
ServiceB serviceB = new ServiceB();
serviceB.setServiceA(serviceAProvider.getObject());
return serviceB;
}
}
4.性能优化策略
// 缓存工厂产品
public class CachedFactory {
private final Map<String, Object> cache = new ConcurrentHashMap<>();
public Object getComponent(String key) {
return cache.computeIfAbsent(key, k -> createExpensiveObject(k));
}
}
// 原型对象优化
public class PrototypeFactory {
@Lookup
public PrototypeBean createPrototype() {
return null; // 由Spring实现
}
}
六、常见问题解决方案
-
NoSuchMethodError 错误 原因:工厂方法签名不匹配 解决:检查参数类型和数量
-
工厂方法返回 null 原因:方法可能返回null 解决:确保方法返回有效对象
-
静态工厂类被实例化 原因:错误配置为普通bean 解决:添加私有构造器
-
实例工厂未初始化 原因:工厂bean未正确配置 解决:检查依赖注入
-
类型转换异常 原因:返回类型与声明不符 解决:使用泛型明确类型
七、Spring 官方集成案例
// JPA EntityManagerFactory
@Configuration
@EnableJpaRepositories
public class JpaConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource, JpaVendorAdapter vendorAdapter) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.example.domain");
return factory;
}
}
// AMQP连接工厂
@Bean
public CachingConnectionFactory connectionFactory() {
CachingConnectionFactory factory = new CachingConnectionFactory("rabbit.example.com");
factory.setUsername("guest");
factory.setPassword("guest");
return factory;
}
// RestTemplate工厂
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(10));
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
总结:工厂模式选择指南
场景 | 推荐方案 |
---|---|
简单无状态对象 | 静态工厂方法 |
需配置的复杂对象 | 实例工厂方法 |
精细生命周期控制 | FactoryBean接口 |
条件化创建 | 实例工厂+策略模式 |
集成第三方SDK | FactoryBean+Builder模式 |
高性能原型对象 | @Lookup方法注入 |
核心原则:
- 优先使用简单方案(静态工厂>实例工厂>FactoryBean)
- 保持工厂方法幂等性
- 复杂初始化逻辑放在工厂中
- 充分利用Spring生命周期管理
掌握这些模式可提升Spring应用的灵活性和可维护性,有效解决复杂对象创建问题。