大白话说Java设计模式-27-策略模式(源码剖析篇)

📌 PDF :AI人工智能 --- RAG知识库实战项目

大白话说Java设计模式-27-策略模式(源码剖析篇):JDK / Spring 中的策略实现

📌 一句话本质:策略在源码里不是"算法切换"的形象化,而是"接口 + 多种实现 + 容器管理"的工业级架构。

🏷️ 标签:策略模式 / Comparator / ResourceLoader / InstantiationStrategy 🎯 适合:中高级后端 / 想读懂主流框架源码的工程师


目录

  • 一、为什么读策略源码?一张地图先看清
  • [二、JDK 源码剖析:Comparator 排序策略](#二、JDK 源码剖析:Comparator 排序策略)
  • [三、Spring 源码剖析:ResourceLoader 资源策略](#三、Spring 源码剖析:ResourceLoader 资源策略)
  • [四、Spring 源码剖析:InstantiationStrategy 实例化策略](#四、Spring 源码剖析:InstantiationStrategy 实例化策略)
  • [五、Spring 源码剖析:PlatformTransactionManager 事务策略](#五、Spring 源码剖析:PlatformTransactionManager 事务策略)
  • 六、为什么框架作者这么设计?
  • [七、借鉴到我们项目:3 个"抄作业"实践](#七、借鉴到我们项目:3 个"抄作业"实践)
  • [八、本篇小结 + 下一模式预告](#八、本篇小结 + 下一模式预告)

一、为什么读策略源码?一张地图先看清

策略模式在 JDK 和 Spring 里出现得最经典 ------Comparator / ResourceLoader / InstantiationStrategy 都是策略思想。

源码地图

类别 框架 / 中间件 策略接口 策略实现
JDK java.util Comparator 自然排序 / 反向排序 / 自定义
JDK java.io Flushable 多种 flush 实现
Spring core.io ResourceLoader ClassPath / FileSystem / Url
Spring beans.factory.support InstantiationStrategy CglibSubclassing / SimpleInstantiation
Spring transaction PlatformTransactionManager DataSource / Jpa / Redis 事务
Servlet jakarta.servlet Filter 多个 Filter Chain

我们按"Comparator → ResourceLoader → InstantiationStrategy → 事务"的顺序来剖析。


二、JDK 源码剖析:Comparator 排序策略

2.1 Comparator:策略接口

源码位置

  • OpenJDK 17
  • src/java.base/share/classes/java/util/Comparator.java

核心源码

java 复制代码
/**
 * ✅ 策略接口:比较器
 */
@FunctionalInterface
public interface Comparator<T> {

    /**
     * ✅ 策略方法:比较两个对象
     */
    int compare(T o1, T o2);

    /**
     * 默认方法:反序策略
     */
    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

    /**
     * 默认方法:then 链式
     */
    default Comparator<T> thenComparing(Comparator<? super T> other) {
        return (Comparator<T> & Serializable)
            (c1, c2) -> {
                int res = compare(c1, c2);
                return (res != 0) ? res : other.compare(c1, c2);
            };
    }
}

关键点

关键点 解释
compare() 策略方法
reversed() 反序策略
thenComparing() 链式策略
@FunctionalInterface Lambda 友好

2.2 Collections.sort():策略调用方

核心源码

java 复制代码
/**
 * ✅ 策略调用方:排序时传入策略
 */
public class Collections {

    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }
}

完整调用链

复制代码
Collections.sort(list, comparator)
        ↓
list.sort(comparator)
        ↓
Arrays.sort(...)
        ↓
TimSort.sort(...)
        ↓
c.compare(a, b)  // 调策略

2.3 经典策略实现

java 复制代码
/**
 * ✅ 策略实现 1:按价格升序
 */
public class PriceAscComparator implements Comparator<Goods> {
    @Override
    public int compare(Goods g1, Goods g2) {
        return g1.getPrice().compareTo(g2.getPrice());
    }
}

/**
 * ✅ 策略实现 2:按价格降序
 */
public class PriceDescComparator implements Comparator<Goods> {
    @Override
    public int compare(Goods g1, Goods g2) {
        return g2.getPrice().compareTo(g1.getPrice());
    }
}

/**
 * ✅ 策略实现 3:按销量
 */
public class SalesComparator implements Comparator<Goods> {
    @Override
    public int compare(Goods g1, Goods g2) {
        return g1.getSales().compareTo(g2.getSales());
    }
}

// 使用
List<Goods> goods = ...;
Collections.sort(goods, new PriceAscComparator());   // 按价格升序
Collections.sort(goods, new PriceDescComparator());  // 按价格降序
Collections.sort(goods, new SalesComparator());      // 按销量

2.4 Lambda 策略(现代写法)

java 复制代码
/**
 * ✅ Lambda 策略
 */
goods.sort((g1, g2) -> g1.getPrice().compareTo(g2.getPrice()));
goods.sort(Comparator.comparing(Goods::getPrice));
goods.sort(Comparator.comparing(Goods::getPrice).reversed());
goods.sort(Comparator.comparing(Goods::getPrice)
        .thenComparing(Goods::getSales));

2.5 Comparator 的"作者选择"

设计点 选择 原因
函数式接口 @FunctionalInterface 支持 Lambda
链式组合 thenComparing() 策略组合
反序策略 reversed() 复用已有策略
null 处理 nullsFirst/Last() 健壮性

三、Spring 源码剖析:ResourceLoader 资源策略

3.1 ResourceLoader:策略接口

源码位置

  • Spring Framework 6.1.x
  • spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java

核心源码

java 复制代码
/**
 * ✅ 策略接口:资源加载
 */
public interface ResourceLoader {

    /**
     * 资源位置前缀
     */
    String CLASSPATH_URL_PREFIX = "classpath:";

    /**
     * ✅ 策略方法:获取资源
     */
    Resource getResource(String location);

    /**
     * 类加载器
     */
    @Nullable
    ClassLoader getClassLoader();
}

3.2 DefaultResourceLoader:默认策略

核心源码

java 复制代码
/**
 * ✅ 默认策略:DefaultResourceLoader
 */
public class DefaultResourceLoader implements ResourceLoader {

    @Nullable
    private ClassLoader classLoader;

    @Override
    public Resource getResource(String location) {
        // ✅ 策略分发:根据前缀选不同策略
        for (ProtocolResolver protocolResolver : this.protocolResolvers) {
            Resource resource = protocolResolver.resolve(location, this);
            if (resource != null) {
                return resource;
            }
        }

        if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(
                location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        else {
            try {
                URL url = new URL(location);
                return (ResourceUtils.isFileURL(url) 
                        ? new FileUrlResource(url) 
                        : new UrlResource(url));
            }
            catch (MalformedURLException ex) {
                return new FileSystemResource(location);
            }
        }
    }
}

关键点

关键点 解释
classpath: ClassPathResource
http:// UrlResource
file: FileUrlResource
其他 FileSystemResource

3.3 Resource 策略族

复制代码
Resource(策略接口)
  ├── ClassPathResource(classpath: 前缀)
  ├── FileSystemResource(file: 前缀 / 无前缀)
  ├── UrlResource(http:// / https:// / ftp://)
  ├── ByteArrayResource(字节数组)
  └── InputStreamResource(输入流)

3.4 完整资源加载调用链

复制代码
ResourceLoader.getResource("classpath:app.properties")
        ↓
DefaultResourceLoader.getResource()
        ↓ 前缀判断
ClassPathResource
        ↓
ClassLoader.getResource("app.properties")
        ↓
InputStream

3.5 ResourceLoader 的"作者选择"

设计点 选择 原因
前缀分发 classpath: / http:// 灵活
默认策略 DefaultResourceLoader 兜底
协议扩展 ProtocolResolver 可扩展
类加载器 注入 解耦

四、Spring 源码剖析:InstantiationStrategy 实例化策略

4.1 InstantiationStrategy:策略接口

源码位置

  • Spring Framework 6.1.x
  • spring-beans/src/main/java/org/springframework/beans/factory/support/InstantiationStrategy.java

核心源码

java 复制代码
/**
 * ✅ 策略接口:实例化
 */
public interface InstantiationStrategy {

    /**
     * ✅ 策略方法:实例化 Bean
     */
    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, 
                       BeanFactory owner) throws BeansException;

    /**
     * 工厂方法实例化
     */
    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, 
                       BeanFactory owner, Constructor<?> ctor, Object... args) 
            throws BeansException;

    /**
     * 带方法实例化
     */
    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, 
                       BeanFactory owner, @Nullable Object factoryBean, 
                       Method factoryMethod, Object... args) throws BeansException;
}

4.2 两种核心策略

SimpleInstantiationStrategy

java 复制代码
/**
 * ✅ 简单策略:JDK 反射
 */
public class SimpleInstantiationStrategy implements InstantiationStrategy {

    @Override
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, 
                              BeanFactory owner) {
        // 1️⃣ 没有 lookup-method / replaced-method
        // 2️⃣ 用 Constructor.newInstance()
        Constructor<?> constructorToUse = ...;
        return BeanUtils.instantiateClass(constructorToUse);
    }
}

CglibSubclassingInstantiationStrategy

java 复制代码
/**
 * ✅ Cglib 策略:方法注入
 */
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {

    @Override
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, 
                              BeanFactory owner) {
        // 1️⃣ 有 lookup-method / replaced-method
        // 2️⃣ 用 Cglib 动态子类
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

4.3 完整 Bean 创建调用链

复制代码
AbstractAutowireCapableBeanFactory.createBeanInstance()
        ↓
getInstantiationStrategy().instantiate(bd, beanName, owner)
        ↓
SimpleInstantiationStrategy(普通 Bean)
   或
CglibSubclassingInstantiationStrategy(lookup-method)
        ↓
Constructor.newInstance()(反射)
   或
Cglib 动态子类

4.4 InstantiationStrategy 的"作者选择"

设计点 选择 原因
简单 vs Cglib 两种策略 性能 vs 能力
抽象基类 extends SimpleInstantiationStrategy 复用
反射统一 BeanUtils.instantiateClass() 简化

五、Spring 源码剖析:PlatformTransactionManager 事务策略

5.1 PlatformTransactionManager:策略接口

源码位置

  • Spring Framework 6.1.x
  • spring-tx/src/main/java/org/springframework/transaction/PlatformTransactionManager.java

核心源码

java 复制代码
/**
 * ✅ 策略接口:事务管理
 */
public interface PlatformTransactionManager extends TransactionManager {

    /**
     * ✅ 策略方法:获取事务
     */
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) 
            throws TransactionException;

    /**
     * 策略方法:提交
     */
    void commit(TransactionStatus status) throws TransactionException;

    /**
     * 策略方法:回滚
     */
    void rollback(TransactionStatus status) throws TransactionException;
}

5.2 多种事务策略

复制代码
PlatformTransactionManager(策略接口)
  ├── DataSourceTransactionManager(JDBC 事务)
  ├── JpaTransactionManager(JPA 事务)
  ├── HibernateTransactionManager(Hibernate 事务)
  ├── RedisTransactionManager(Redis 事务)
  ├── KafkaTransactionManager(Kafka 事务)
  └── JmsTransactionManager(JMS 事务)

5.3 @Transactional 怎么用策略?

核心源码(简化版):

java 复制代码
/**
 * ✅ 策略使用方:@Transactional 注解
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

    /**
     * ✅ 关键:可以指定事务管理器(策略)
     */
    @AliasFor("transactionManager")
    String value() default "";

    String transactionManager() default "";
}

// 使用
@Transactional("dataSourceTxManager")  // 用 JDBC 策略
public void jdbcUpdate() { ... }

@Transactional("jpaTxManager")         // 用 JPA 策略
public void jpaUpdate() { ... }

关键点

关键点 解释
@Transactional 策略选择注解
transactionManager 策略名字
多数据源 用不同策略

5.4 PlatformTransactionManager 的"作者选择"

设计点 选择 原因
多数据源 多个 TransactionManager 灵活
注解选策略 @Transactional("...") 解耦
模板方法 TransactionTemplate 复用
传播机制 7 种传播行为 强大

六、为什么框架作者这么设计?

读源码看的是"实现",悟的是"设计哲学"。

6.1 框架作者选策略的 4 个核心考虑

序号 考虑 举例
算法多 多种排序、多种资源加载
可扩展 加新算法不动老代码
客户端不关心 排序时只传 Comparator
运行时切换 Spring ResourceLoader 按前缀切换

6.2 策略 vs 模板方法:源码里怎么选?

场景 选哪个 原因
多种算法可切换 策略 灵活
算法骨架固定 模板方法 复用
客户端选算法 策略 主动
框架自动选 工厂 + 策略 自动

6.3 框架作者不选策略的 3 种情况

序号 场景 原因
算法只有 1 种 没意义
算法之间有依赖 用责任链
算法有状态 用状态模式

6.4 策略在企业级应用的 3 种典型用法

复制代码
用法 1:支付策略
       4 种支付渠道可切换
       → 加新支付只加 Strategy

用法 2:优惠策略
       满减 / 折扣 / 立减可叠加
       → 多种 Strategy 组合

用法 3:物流策略
       标准 / 加急 / 次日达
       → 业务方选 Strategy

七、借鉴到我们项目:3 个"抄作业"实践

7.1 实践 1:消息发送策略

场景:大白商城短信/邮件/推送。

完整实现

java 复制代码
/**
 * 借鉴 JDK Comparator:消息发送策略
 */
public interface MessageSenderStrategy {

    void send(String to, String content);

    String getType();
}

@Component
public class SmsSender implements MessageSenderStrategy {
    @Override
    public void send(String to, String content) {
        log.info("【短信】发送, to={}, content={}", to, content);
    }
    @Override
    public String getType() { return "sms"; }
}

@Component
public class EmailSender implements MessageSenderStrategy {
    @Override
    public void send(String to, String content) {
        log.info("【邮件】发送, to={}, content={}", to, content);
    }
    @Override
    public String getType() { return "email"; }
}

@Component
public class PushSender implements MessageSenderStrategy {
    @Override
    public void send(String to, String content) {
        log.info("【推送】发送, to={}, content={}", to, content);
    }
    @Override
    public String getType() { return "push"; }
}

@Service
public class MessageContext {

    private final Map<String, MessageSenderStrategy> senderMap = new HashMap<>();

    @Autowired
    public MessageContext(List<MessageSenderStrategy> senders) {
        senders.forEach(s -> senderMap.put(s.getType(), s));
    }

    public void send(String type, String to, String content) {
        senderMap.get(type).send(to, content);
    }
}

7.2 实践 2:多数据源事务策略

场景:大白商城 MySQL + Redis + Kafka 多数据源。

完整实现

java 复制代码
/**
 * 借鉴 Spring PlatformTransactionManager:多数据源事务
 */
public interface MultiTxManager {
    void begin();
    void commit();
    void rollback();
}

@Component("mysqlTx")
public class MysqlTxManager implements MultiTxManager {
    @Autowired private DataSource dataSource;
    private Connection conn;

    @Override
    public void begin() {
        conn = dataSource.getConnection();
        conn.setAutoCommit(false);
    }
    @Override
    public void commit() {
        conn.commit();
    }
    @Override
    public void rollback() {
        conn.rollback();
    }
}

@Component("redisTx")
public class RedisTxManager implements MultiTxManager {
    @Override public void begin() { /* Redis MULTI */ }
    @Override public void commit() { /* Redis EXEC */ }
    @Override public void rollback() { /* Redis DISCARD */ }
}

@Service
public class MultiTxContext {
    private final Map<String, MultiTxManager> txMap = new HashMap<>();

    @Autowired
    public MultiTxContext(List<MultiTxManager> managers) {
        // 注入后按 Bean 名注册
    }

    public MultiTxManager get(String name) {
        return txMap.get(name);
    }
}

7.3 实践 3:日志策略

场景:大白商城多渠道日志(控制台/文件/ELK)。

完整实现

java 复制代码
/**
 * 借鉴 Spring ResourceLoader:日志策略
 */
public interface LogStrategy {
    void log(String level, String message);

    String getType();
}

@Component
public class ConsoleLogStrategy implements LogStrategy {
    @Override
    public void log(String level, String message) {
        System.out.println("[" + level + "] " + message);
    }
    @Override
    public String getType() { return "console"; }
}

@Component
public class FileLogStrategy implements LogStrategy {
    @Override
    public void log(String level, String message) {
        // 写文件
    }
    @Override
    public String getType() { return "file"; }
}

@Component
public class ElkLogStrategy implements LogStrategy {
    @Override
    public void log(String level, String message) {
        // 推送到 ELK
    }
    @Override
    public String getType() { return "elk"; }
}

收益

优化点 效果
消息发送 加新渠道只加 1 个 Strategy
多数据源事务 统一管理多个 Tx
日志多渠道 一键切换

八、本篇小结 + 下一模式预告

8.1 本篇小结(5 个核心要点)

  1. JDK Comparator :函数式策略接口,Lambda + 链式
  2. Spring ResourceLoader :按前缀分发策略,ClassPath / FileSystem / Url
  3. Spring InstantiationStrategy简单 vs Cglib 两种 Bean 创建策略。
  4. Spring 事务多数据源多策略@Transactional("...") 切换。
  5. 借鉴价值消息发送 / 多数据源 / 日志任何"多种算法可切换"都用策略

8.2 一句话总结

策略在源码里不是"算法切换"的形象化,而是"接口 + 多种实现 + 容器管理"的工业级架构 。Comparator 排序、ResourceLoader 加载、InstantiationStrategy 创建 Bean、PlatformTransactionManager 管事务------学策略,先学 Comparator 和 ResourceLoader

8.3 知识脑图

复制代码
策略源码剖析
├── JDK
│   ├── Comparator(排序)
│   ├── Runnable(线程任务)
│   └── Flushable(IO 刷新)
├── Spring
│   ├── ResourceLoader(资源加载)
│   ├── InstantiationStrategy(Bean 实例化)
│   ├── PlatformTransactionManager(事务管理)
│   └── ApplicationContext(容器)
└── 借鉴价值
    ├── 消息发送策略
    ├── 多数据源事务
    └── 日志多渠道

8.4 下一模式预告

第 28 篇【模板方法模式 - 业务实战篇】:大白商城下单骨架的"算法模板"

下一篇我们会实战模板方法模式,回答 4 个问题:

  1. 下单流程(创建订单→减库存→支付→通知)的通用骨架怎么抽?
  2. 模板方法 vs 策略 / 责任链怎么区分?
  3. Spring 的 AbstractApplicationContext.refresh() 怎么用模板方法?
  4. 模板方法 + 策略怎么组合?

并附完整的下单模板实战代码(含抽象类 + 具体子类 + 单元测试),可直接复制到 IDEA 跑


觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯

相关推荐
Rain的Java大神之路1 小时前
介绍一下分布式事务
java·分布式·后端·spring·spring cloud·架构·springcloud
吴声子夜歌2 小时前
Java面试题——基础(一)
java·开发语言
南城以南溫暖如初1472 小时前
外卖CPS实战指南:从技术选型到运营落地全流程解析
java·spring boot·mysql·架构·vue
傻啦嘿哟3 小时前
英雄联盟皮肤爬虫:爬取全皮肤价格与特效,做比价工具
java·c++·爬虫
码匠许师傅4 小时前
【C++ 面试真题】24. 聊聊 C++ 的时间日期处理
java·c++·面试
mqiqe5 小时前
AgentScope Java 2.0 Agent 状态存储(AgentStateStore)深度解析:构建可恢复、可扩展的智能体运行时
java·运维·网络
zhifou1234565 小时前
java 17升级安装
java·开发语言
用户3721574261355 小时前
如何使用 Java 将 Markdown 转换为 PDF(含自定义设置)
java
用户3721574261356 小时前
如何使用 Java 在 Word 文档中添加和删除水印:分步指南
java
王中阳Go7 小时前
老板用AI三天写到90%,让我明天上线:Java 团队怎么接这10%的烂摊子?
java