Spring 工厂模式创建 Bean 深度解析

目录

Spring 工厂模式创建 Bean 深度解析

工厂模式在 Spring 中的核心价值

对象创建解耦

复杂场景处理

第三方库整合

静态工厂方法详解

1. 完整工作流程

2. 实现步骤详解

3. 参数传递技巧

4. 实际应用案例

三、实例工厂方法深度解析

1.完整工作流程

2.详细实现步骤

3. 高级技巧:工厂状态管理

4. 真实案例:多数据源切换

四、静态工厂与实例工厂对比

五、最佳实践与高级技巧

工厂方法与 FactoryBean 结合

2. 条件化创建技巧

3.解决循环依赖

4.性能优化策略

六、常见问题解决方案

七、Spring 官方集成案例

总结:工厂模式选择指南


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工具类连接池/线程池创建

 


五、最佳实践与高级技巧

  1. 工厂方法与 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接口
条件化创建实例工厂+策略模式
集成第三方SDKFactoryBean+Builder模式
高性能原型对象@Lookup方法注入

核心原则:

  1. 优先使用简单方案(静态工厂>实例工厂>FactoryBean)
  2. 保持工厂方法幂等性
  3. 复杂初始化逻辑放在工厂中
  4. 充分利用Spring生命周期管理

掌握这些模式可提升Spring应用的灵活性和可维护性,有效解决复杂对象创建问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值