📌 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 个核心要点)
- JDK Comparator :函数式策略接口,Lambda + 链式。
- Spring ResourceLoader :按前缀分发策略,ClassPath / FileSystem / Url。
- Spring InstantiationStrategy :简单 vs Cglib 两种 Bean 创建策略。
- Spring 事务 :多数据源多策略 ,
@Transactional("...")切换。 - 借鉴价值 :消息发送 / 多数据源 / 日志 ,任何"多种算法可切换"都用策略。
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 个问题:
- 下单流程(创建订单→减库存→支付→通知)的通用骨架怎么抽?
- 模板方法 vs 策略 / 责任链怎么区分?
- Spring 的
AbstractApplicationContext.refresh()怎么用模板方法? - 模板方法 + 策略怎么组合?
并附完整的下单模板实战代码(含抽象类 + 具体子类 + 单元测试),可直接复制到 IDEA 跑。
觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯