顾乔芝士网

持续更新的前后端开发技术栈

三十四、Spring中的简单工厂模式深度解析

Spring 的简单工厂模式通过 BeanFactory 和工厂方法配置,将对象创建逻辑从业务代码中解耦。它不仅是 Spring IoC 容器的基石(如 getBean() 方法),也是灵活管理多环境配置(如多数据源、国际化)的核心手段。尽管简单工厂模式在扩展性上存在局限,但在 Spring 的配置驱动和条件化 Bean 机制加持下,依然能实现高度灵活的对象治理。掌握工厂方法与容器生命周期的协同,是构建可维护 Spring 应用的关键技能。

1. Spring 简单工厂模式的核心特点

集中式对象创建:通过一个工厂类统一管理对象的创建逻辑,隐藏实例化细节。

条件分支控制:根据输入参数(如名称、类型)动态选择具体实现类。

与 IoC 容器集成:Spring 通过 BeanFactory 和静态/实例工厂方法实现类似简单工厂的功能。

配置驱动:通过 XML 或注解定义工厂逻辑,无需硬编码条件判断。


2. Spring 版本与源码获取

版本:Spring Framework 5.3.26(长期支持版本)

源码下载

Maven 依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.26</version>
</dependency>

直接下载地址:Spring Framework 5.3.26 Release

调试技巧

  • 关键断点位置:DefaultListableBeanFactory.getBean() → createBean() → instantiateBean()。
  • 观察静态工厂方法调用栈:SimpleInstantiationStrategy.instantiate()。

3. 源码级实现剖析

简单工厂像一个“自动售货机”,投币(输入参数)后,机器根据商品编号(条件)自动分配对应饮料(对象实例)。

// Spring 内置静态工厂示例:Calendar 对象创建
public abstract class Calendar {
    public static Calendar getInstance() {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault());
    }
    // 根据时区和地区选择具体实现类(如 GregorianCalendar)
    private static Calendar createCalendar(TimeZone zone, Locale locale) {
        // 条件分支选择具体实现
        if (locale.getUnicodeLocaleType("ca") == null) {
            return new GregorianCalendar(zone, locale);
        }
        // 其他日历类型分支...
    }
}

// Spring 工厂方法配置对应实现
public class StaticCalendarFactory {
    public static Calendar createCalendar() {
        return Calendar.getInstance();
    }
}

4. 简单工厂模式的多维度应用

配置方式对比

  • XML 静态工厂
<bean id="calendar" 
      class="org.springframework.beans.factory.config.StaticCalendarFactory"
      factory-method="createCalendar"/>
  • XML 实例工厂
<bean id="carFactory" class="com.example.CarFactory"/>
<bean id="tesla" factory-bean="carFactory" factory-method="createCar">
    <constructor-arg value="tesla"/>
</bean>
  • 注解配置
@Configuration
public class AppConfig {
    @Bean
    public Car tesla() {
        return CarFactory.createCar("tesla"); // 静态工厂方法
    }
}

Spring 内置工厂类

工厂类

作用

StaticListableBeanFactory

基于静态 Map 存储 Bean 定义的简单工厂

PropertiesBeanDefinitionReader

从 Properties 文件读取 Bean 定义的工厂

StaticMethodMatcherPointcutAdvisor

通过静态方法创建 AOP 通知的工厂


5. 简单工厂模式 vs 其他模式

场景

简单工厂模式

工厂方法模式

抽象工厂模式

创建逻辑复杂度

单一工厂类,条件分支创建对象

每个产品一个工厂类

每个产品族一个工厂类

扩展性

需修改工厂类添加新产品

新增产品只需扩展工厂接口

新增产品族需扩展抽象工厂

Spring 典型应用

BeanFactory.getBean() 按名称创建对象

FactoryBean 接口实现

无直接对应,需自定义实现


6. 实际应用场景

多数据源动态切换

public class DataSourceFactory {
    public static DataSource getDataSource(String env) {
        return env.equals("prod") ? 
            new HikariProdDataSource() : new BasicDevDataSource();
    }
}

国际化消息解析

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>messages_#{systemProperties['user.language']}</value>
        </list>
    </property>
</bean>

条件化 Bean 创建

@Bean
@ConditionalOnClass(name = "com.example.RedisClient")
public CacheService redisCache() {
    return new RedisCacheService(); // 存在 Redis 客户端时创建
}

7. 源码调试与陷阱规避

调试步骤

  • 在 BeanFactory.getBean() 方法设置断点,观察根据 Bean 名称创建实例的过程。
  • 跟踪静态工厂方法调用:在 SimpleInstantiationStrategy.instantiate() 中查看方法反射调用。

常见陷阱

  • 工厂方法单例问题:静态工厂默认返回单例,需结合 @Scope 注解控制作用域。
  • 循环依赖:工厂方法中直接 new 对象可能导致 Spring 无法管理依赖(应通过容器获取 Bean)。
  • 条件分支冗余:过多 if-else 应重构为策略模式或 Map 映射。

8. 性能与最佳实践

优点

  • 集中管理对象创建逻辑,降低代码冗余。
  • 通过配置实现对象切换,符合开闭原则。

优化建议

  • 避免硬编码条件:将分支逻辑外置到配置文件或数据库。
  • 工厂方法轻量化:不在工厂中执行业务逻辑(如 IO 操作)。
  • 结合缓存机制:对频繁创建的对象使用单例或原型作用域。


欢迎讨论!

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言