创建型模式实战:单例、工厂模式解析与 Spring 集成

23 阅读5分钟

创建型模式实战:单例、工厂模式解析与 Spring 集成

一、单例模式:全局唯一实例的正确打开方式

1.1 核心定义与应用场景

定义:确保一个类仅有一个实例,并提供全局访问点核心价值

  • 避免资源重复创建(如数据库连接池、线程池)

  • 全局状态管理(如配置中心、日志管理器)

Spring 场景

  • Bean 默认作用域为单例(@Scope("singleton"))

  • 应用上下文ApplicationContext本身是单例

1.2 五种实现方式对比

1.2.1 饿汉式(线程安全,立即加载)
// 优点:简单可靠,类加载时创建实例  
// 缺点:可能造成资源浪费(未使用时也会创建)  
public class HungrySingleton {  
    private static final HungrySingleton instance = new HungrySingleton();  
    private HungrySingleton() {}  
    public static HungrySingleton getInstance() { return instance; }  
}  
1.2.2 懒汉式(非线程安全,延迟加载)
// 反模式:多线程下可能创建多个实例  
public class LazySingleton {  
    private static LazySingleton instance;  
    private LazySingleton() {}  
    public static LazySingleton getInstance() {  
        if (instance == null) {  
            instance = new LazySingleton(); // 非原子操作  
        }  
        return instance;  
    }  
}  
1.2.3 双重检查锁定(线程安全,延迟加载)
// 正确实现:volatile禁止指令重排  
public class DoubleCheckSingleton {  
    private static volatile DoubleCheckSingleton instance;  
    private DoubleCheckSingleton() {}  
    public static DoubleCheckSingleton getInstance() {  
        if (instance == null) {  
            synchronized (DoubleCheckSingleton.class) {  
                if (instance == null) {  
                    instance = new DoubleCheckSingleton();  
                }  
            }  
        }  
        return instance;  
    }  
}  
1.2.4 枚举单例(最简实现,线程安全)
// 优点:天然支持序列化/反序列化安全  
public enum EnumSingleton {  
    INSTANCE;  
    public void doSomething() { /* 业务逻辑 */ }  
}  
1.2.5 Spring Bean 单例(容器管理)
// 声明单例Bean(默认作用域)  
@Service  
public class SpringSingletonService {  
    // 依赖注入支持  
    private final DataSource dataSource;  
    @Autowired  
    public SpringSingletonService(DataSource dataSource) {  
        this.dataSource = dataSource;  
    }  
}  

1.3 线程安全与性能对比

实现方式线程安全延迟加载序列化安全Spring 集成
饿汉式手动实现
双重检查锁定否(需额外处理)推荐方式
枚举单例不适用
Spring Bean内置支持

二、工厂模式:对象创建逻辑的封装与扩展

2.1 三种子模式对比解析

2.1.1 简单工厂(静态工厂)

场景:创建逻辑简单,无需扩展

// 日志工厂  
public class LoggerFactory {  
    public static Logger createLogger(String type) {  
        if ("file".equals(type)) {  
            return new FileLogger();  
        } else if ("console".equals(type)) {  
            return new ConsoleLogger();  
        }  
        throw new IllegalArgumentException("不支持的日志类型");  
    }  
}  
2.1.2 工厂方法(多态工厂)

场景:需要支持多种产品类型扩展

2.1.3 抽象工厂(产品族创建)

场景:创建相关联的产品族(如数据库连接 + 操作对象)

// 抽象工厂接口  
public interface DatabaseFactory {  
    Connection createConnection();  
    Statement createStatement();  
}  
// MySQL工厂实现  
public class MySQLFactory implements DatabaseFactory {  
    public Connection createConnection() { /* 创建MySQL连接 */ }  
    public Statement createStatement() { /* 创建MySQL Statement */ }  
}  

2.2 Spring 中的工厂模式实践

2.2.1 BeanFactory 核心实现
// 工厂方法模式  
public interface BeanFactory {  
    <T> T getBean(Class<T> requiredType);  
}  
// 具体工厂:DefaultListableBeanFactory  
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory  
        implements BeanDefinitionRegistry {  
    @Override  
    public <T> T getBean(Class<T> requiredType) {  
        return doGetBean(requiredType.getName(), requiredType, null, false);  
    }  
}  
2.2.2 工厂 Bean 扩展点
// 自定义工厂Bean  
public class DataSourceFactoryBean implements FactoryBean<DataSource> {  
    private String url;  
    private String username;  
    public void setUrl(String url) { this.url = url; }  
    public DataSource getObject() {  
        return DriverManager.getConnection(url, username, "password");  
    }  
    public Class<?> getObjectType() { return DataSource.class; }  
}  
// Spring配置  
<bean id="dataSource" class="DataSourceFactoryBean">  
    <property name="url" value="jdbc:mysql://localhost:3306/test" />  
</bean>  

2.3 适用场景决策树

graph TD  
   A[是否需要封装对象创建逻辑?] -->|是| B{是否需要支持扩展?}  
   B -->|简单扩展| C[工厂方法模式]  
   B -->|复杂产品族| D[抽象工厂模式]  
   A -->|否| E[是否需要静态便捷访问?]  
   E -->|是| F[简单工厂模式]  
   E -->|否| G[直接创建对象]  

三、企业级应用避坑指南

3.1 单例模式常见陷阱

  1. 序列化安全问题
protected Object readResolve() { return instance; }  
    • 反例:未实现readResolve()导致反序列化创建新实例
    • 解决方案:枚举单例或重写反序列化方法
  1. Spring 单例与线程安全
    • 误区:单例 Bean 存储成员变量导致线程安全问题
    • 最佳实践:Bean 保持无状态,依赖注入的对象为线程安全类型

3.2 工厂模式过度设计预警

  1. 简单场景复杂化
    • 反例:将简单对象(如Date)的创建用工厂模式封装
    • 原则:当创建逻辑包含复杂条件判断或资源管理时再使用
  1. 产品接口膨胀
    • 反例:抽象工厂包含过多不相关产品接口
    • 解决方案:拆分为多个工厂或使用构建者模式

四、微服务场景中的模式应用

4.1 单例模式在配置中心的应用

// 分布式配置中心单例  
public class ConfigCenter {  
    private static final ConfigCenter instance;  
    private final Map<String, String> configs;  
    private ConfigCenter() {  
        configs = loadFromNacos(); // 从Nacos加载配置  
    }  
    // 双重检查锁定实现  
    public static ConfigCenter getInstance() { /* ... */ }  
}  

4.2 工厂模式在服务实例创建中的应用

// 微服务客户端工厂  
public class MicroServiceClientFactory {  
    public static <T> T createClient(Class<T> serviceClass) {  
        String serviceName = serviceClass.getAnnotation(FeignClient.class).value();  
        return Feign.builder()  
                .encoder(new JacksonEncoder())  
                .decoder(new JacksonDecoder())  
                .target(serviceClass, "http://" + serviceName);  
    }  
}  

五、总结:创建型模式的本质

创建型模式的核心是分离对象创建逻辑,通过封装、继承、多态解决以下问题:

  1. 对象创建复杂性:隐藏具体实现细节(如单例的线程安全逻辑)

  2. 扩展性需求:支持新类型扩展而不修改现有代码(工厂方法模式)

  3. 全局唯一性:确保关键资源仅有一个实例(单例模式)

下一篇我们将继续探索创建型模式的另外两种:建造者模式(复杂对象构建)和原型模式(对象克隆与性能优化),并解析它们在 MyBatis、JPA 等框架中的实际应用。

这篇博客通过以下设计强化技术深度与实战价值:

  1. 实现对比:详细解析五种单例模式的线程安全与适用场景,提供 Spring Bean 单例的正确使用方式

  2. 模式演进:通过工厂模式三种子模式的类图与代码示例,展示从简单到复杂的设计演进过程

  3. 框架集成:深入 Spring BeanFactory 源码,演示工厂模式在容器中的核心作用

  4. 避坑指南:针对单例序列化安全、工厂模式过度设计等常见问题提供解决方案