目录
-
- 前言
- 摘要
- [1. 引言](#1. 引言)
-
- [1.1 为什么学习设计模式](#1.1 为什么学习设计模式)
- [1.2 设计模式分类](#1.2 设计模式分类)
- [1.3 Spring框架概述](#1.3 Spring框架概述)
- [2. 模板方法模式](#2. 模板方法模式)
-
- [2.1 模式定义](#2.1 模式定义)
- [2.2 UML结构](#2.2 UML结构)
- [2.3 Spring中的模板方法模式](#2.3 Spring中的模板方法模式)
-
- [2.3.1 JdbcTemplate源码分析](#2.3.1 JdbcTemplate源码分析)
- [2.3.2 使用示例](#2.3.2 使用示例)
- [2.4 Spring中其他模板方法应用](#2.4 Spring中其他模板方法应用)
- [3. 工厂模式](#3. 工厂模式)
-
- [3.1 模式定义](#3.1 模式定义)
- [3.2 三种工厂模式对比](#3.2 三种工厂模式对比)
- [3.3 Spring中的工厂模式](#3.3 Spring中的工厂模式)
-
- [3.3.1 BeanFactory源码分析](#3.3.1 BeanFactory源码分析)
- [3.3.2 FactoryBean接口](#3.3.2 FactoryBean接口)
- [3.4 Spring中其他工厂模式应用](#3.4 Spring中其他工厂模式应用)
- [4. 适配器模式](#4. 适配器模式)
-
- [4.1 模式定义](#4.1 模式定义)
- [4.2 UML结构](#4.2 UML结构)
- [4.3 Spring中的适配器模式](#4.3 Spring中的适配器模式)
-
- [4.3.1 HandlerAdapter源码分析](#4.3.1 HandlerAdapter源码分析)
- [4.3.2 DispatcherServlet调用流程](#4.3.2 DispatcherServlet调用流程)
- [4.4 Spring中其他适配器模式应用](#4.4 Spring中其他适配器模式应用)
- [5. 策略模式](#5. 策略模式)
-
- [5.1 模式定义](#5.1 模式定义)
- [5.2 UML结构](#5.2 UML结构)
- [5.3 Spring中的策略模式](#5.3 Spring中的策略模式)
-
- [5.3.1 ResourceLoader源码分析](#5.3.1 ResourceLoader源码分析)
- [5.3.2 使用示例](#5.3.2 使用示例)
- [5.4 Spring中其他策略模式应用](#5.4 Spring中其他策略模式应用)
- [6. 代理模式](#6. 代理模式)
-
- [6.1 模式定义](#6.1 模式定义)
- [6.2 代理模式类型](#6.2 代理模式类型)
- [6.3 Spring中的代理模式](#6.3 Spring中的代理模式)
-
- [6.3.1 Spring AOP源码分析](#6.3.1 Spring AOP源码分析)
- [6.3.2 使用示例](#6.3.2 使用示例)
- [7. 观察者模式](#7. 观察者模式)
-
- [7.1 模式定义](#7.1 模式定义)
- [7.2 UML结构](#7.2 UML结构)
- [7.3 Spring中的观察者模式](#7.3 Spring中的观察者模式)
-
- [7.3.1 ApplicationEvent源码分析](#7.3.1 ApplicationEvent源码分析)
- [7.3.2 使用示例](#7.3.2 使用示例)
- [7.4 Spring中其他观察者模式应用](#7.4 Spring中其他观察者模式应用)
- [8. 责任链模式](#8. 责任链模式)
-
- [8.1 模式定义](#8.1 模式定义)
- [8.2 UML结构](#8.2 UML结构)
- [8.3 Spring中的责任链模式](#8.3 Spring中的责任链模式)
-
- [8.3.1 HandlerInterceptor源码分析](#8.3.1 HandlerInterceptor源码分析)
- [8.3.2 使用示例](#8.3.2 使用示例)
- [9. 总结](#9. 总结)
-
- [9.1 设计模式总结](#9.1 设计模式总结)
- [9.2 设计模式使用原则](#9.2 设计模式使用原则)
- [9.3 思考题](#9.3 思考题)
- 参考资料
前言
作为一名Java开发者,我在阅读Spring源码时常常惊叹于其精妙的设计。Spring框架之所以能够成为Java企业级开发的事实标准,除了功能强大之外,其优秀的架构设计也是关键因素。而设计模式正是Spring架构设计的灵魂所在。
本文是我多年框架源码阅读和学习设计模式的总结,将系统性地介绍模板方法、工厂、适配器、策略、代理、观察者等经典设计模式在Spring框架中的实际应用。通过分析Spring源码中的设计模式实现,帮助读者深入理解设计模式的精髓,提升架构设计能力。
摘要
本文深入剖析经典设计模式在Spring框架中的实际应用,涵盖模板方法模式、工厂模式、适配器模式、策略模式、代理模式、观察者模式、责任链模式等核心设计模式。每种模式都从定义、UML结构、Spring源码实现、应用场景四个维度进行详细讲解。通过本文的学习,读者将掌握如何在真实项目中正确运用设计模式,理解框架设计的底层思想,提升代码的可维护性和可扩展性。
通过本文你将学到:
- 8种经典设计模式的定义与结构
- Spring框架中设计模式的源码实现
- 设计模式的实际应用场景与最佳实践
- 如何在项目中正确运用设计模式
1. 引言

图:设计模式在Spring框架中的应用概览
1.1 为什么学习设计模式
设计模式是软件开发中经过验证的解决方案,是前辈们智慧的结晶。学习设计模式有以下几个重要意义:
| 收益 | 说明 |
|---|---|
| 提升代码质量 | 设计模式是经过实践检验的优秀设计,能够显著提升代码的可读性、可维护性和可扩展性 |
| 促进团队沟通 | 设计模式提供了一套通用的术语,团队成员可以用"工厂模式"、"观察者模式"等术语快速交流设计思想 |
| 深入理解框架 | 主流框架大量使用设计模式,理解设计模式有助于深入理解框架源码 |
| 面试必备 | 设计模式是中高级面试的必考内容,掌握设计模式是职业发展的必经之路 |
1.2 设计模式分类
根据GoF(Gang of Four)的分类,设计模式分为三大类:
设计模式
创建型模式
工厂方法模式
抽象工厂模式
单例模式
建造者模式
原型模式
结构型模式
适配器模式
装饰器模式
代理模式
外观模式
桥接模式
组合模式
享元模式
行为型模式
模板方法模式
策略模式
观察者模式
责任链模式
命令模式
迭代器模式
状态模式
备忘录模式
访问者模式
中介者模式
解释器模式
1.3 Spring框架概述
Spring框架是一个轻量级的Java企业级开发框架,其核心设计理念是IoC(控制反转)和AOP(面向切面编程)。Spring框架大量运用了设计模式,是学习设计模式的绝佳素材。
设计模式应用
Spring核心模块
Core Container
核心容器
AOP
面向切面编程
Web
Web层
Data Access
数据访问
工厂模式
代理模式
模板方法模式
策略模式
2. 模板方法模式
2.1 模式定义
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。
2.2 UML结构
<<abstract>>
AbstractClass
+templateMethod() : void
#primitiveOperation1() : void
#primitiveOperation2() : void
#hookMethod() : void
ConcreteClassA
#primitiveOperation1() : void
#primitiveOperation2() : void
ConcreteClassB
#primitiveOperation1() : void
#primitiveOperation2() : void
#hookMethod() : void
角色说明:
| 角色 | 说明 |
|---|---|
| AbstractClass | 抽象类,定义模板方法和抽象方法 |
| ConcreteClass | 具体实现类,实现抽象方法 |
| templateMethod | 模板方法,定义算法骨架 |
| primitiveOperation | 原语操作,由子类实现 |
| hookMethod | 钩子方法,子类可选实现 |
2.3 Spring中的模板方法模式
Spring中大量使用了模板方法模式,最典型的就是JdbcTemplate、RedisTemplate、RestTemplate等以Template结尾的类。
2.3.1 JdbcTemplate源码分析
java
// JdbcTemplate的核心查询方法
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
// 模板方法:定义查询的算法骨架
@Override
@Nullable
public <T> T query(PreparedStatementCreator psc, @Nullable PreparedStatementSetter pss,
ResultSetExtractor<T> rse) throws DataAccessException {
// 1. 获取数据库连接
// 2. 创建PreparedStatement
// 3. 设置参数
// 4. 执行查询
// 5. 处理结果集
// 6. 关闭资源
Connection con = DataSourceUtils.getConnection(obtainDataSource());
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = psc.createPreparedStatement(con);
if (pss != null) {
pss.setValues(ps);
}
rs = ps.executeQuery();
return rse.extractData(rs);
} finally {
// 关闭资源(模板方法处理)
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(ps);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
// 抽象方法:由回调接口实现
public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException {
return query(new SimplePreparedStatementCreator(sql), null, rse);
}
public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
query(sql, new RowCallbackHandlerResultSetExtractor(rch));
}
public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));
}
}
上述代码展示了JdbcTemplate的核心查询方法。模板方法模式体现在:query方法定义了数据库查询的完整流程(获取连接→创建语句→设置参数→执行查询→处理结果→关闭资源),而具体的结果处理逻辑则通过ResultSetExtractor、RowCallbackHandler、RowMapper等回调接口交给调用者实现。这样,开发者只需要关注业务逻辑,而不用处理繁琐的资源管理和异常处理。
2.3.2 使用示例
java
// 使用JdbcTemplate查询数据
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
// 使用RowMapper处理结果集
public User findById(Long id) {
String sql = "SELECT id, username, email, created_at FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);
}
// 使用Lambda表达式简化
public User findByIdSimple(Long id) {
String sql = "SELECT id, username, email, created_at FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
user.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
return user;
}, id);
}
// 批量查询
public List<User> findAll() {
String sql = "SELECT id, username, email, created_at FROM users";
return jdbcTemplate.query(sql, new UserRowMapper());
}
}
// 自定义RowMapper
public class UserRowMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
user.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
return user;
}
}
2.4 Spring中其他模板方法应用
| 类名 | 说明 | 模板方法 | 回调接口 |
|---|---|---|---|
| JdbcTemplate | JDBC操作模板 | query/update | RowMapper, ResultSetExtractor |
| RedisTemplate | Redis操作模板 | execute | RedisCallback |
| RestTemplate | HTTP请求模板 | exchange | ResponseExtractor |
| TransactionTemplate | 事务操作模板 | execute | TransactionCallback |
| HibernateTemplate | Hibernate操作模板 | execute | HibernateCallback |
3. 工厂模式
3.1 模式定义
工厂模式(Factory Pattern)是最常用的创建型设计模式之一,它提供了一种创建对象的最佳方式。工厂模式分为三种:简单工厂、工厂方法和抽象工厂。
3.2 三种工厂模式对比
抽象工厂
Client
AbstractFactory
ConcreteFactory1
ConcreteFactory2
ProductA1
ProductB1
ProductA2
ProductB2
工厂方法
Client
Factory
ConcreteFactoryA
ConcreteFactoryB
ProductA
ProductB
简单工厂
Client
SimpleFactory
ProductA
ProductB
| 模式类型 | 说明 | 适用场景 |
|---|---|---|
| 简单工厂 | 一个工厂类根据参数创建不同产品 | 产品种类较少,创建逻辑简单 |
| 工厂方法 | 每个产品有专门的工厂类 | 产品种类较多,需要扩展 |
| 抽象工厂 | 创建一系列相关的产品族 | 需要创建产品族,如不同风格的UI组件 |
3.3 Spring中的工厂模式
3.3.1 BeanFactory源码分析
Spring的核心容器BeanFactory就是工厂模式的典型应用。
java
// BeanFactory接口定义
public interface BeanFactory {
// 核心方法:根据名称获取Bean
Object getBean(String name) throws BeansException;
// 根据名称和类型获取Bean
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
// 根据类型获取Bean
<T> T getBean(Class<T> requiredType) throws BeansException;
// 根据名称获取Bean,提供构造参数
Object getBean(String name, Object... args) throws BeansException;
// 根据类型获取Bean,提供构造参数
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 检查是否包含指定Bean
boolean containsBean(String name);
// 检查是否是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 检查是否是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 获取Bean的类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 获取Bean的别名
String[] getAliases(String name);
}
java
// AbstractBeanFactory中的getBean实现
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
// 核心方法:获取Bean的模板方法
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType,
@Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
// 1. 转换Bean名称(处理别名、&前缀等)
String beanName = transformedBeanName(name);
Object beanInstance;
// 2. 先检查单例缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// 3. 检查是否存在循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 4. 检查父工厂
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
// 5. 标记Bean正在创建
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 6. 先创建依赖的Bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
getBean(dep);
}
}
// 7. 创建Bean实例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
Object prototypeInstance = createBean(beanName, mbd, args);
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
// 其他Scope
String scopeName = mbd.getScope();
Scope scope = this.scopes.get(scopeName);
Object scopedInstance = scope.get(beanName, () -> {
return createBean(beanName, mbd, args);
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
} catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
// 抽象方法:由子类实现具体的创建逻辑
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException;
}
上述源码展示了Spring BeanFactory的核心实现。doGetBean方法是获取Bean的模板方法,它定义了获取Bean的完整流程:转换名称→检查缓存→处理依赖→创建实例。而具体的创建逻辑则由createBean抽象方法交给子类实现。这是工厂方法模式的典型应用。
3.3.2 FactoryBean接口
Spring还提供了FactoryBean接口,允许开发者自定义Bean的创建逻辑:
java
// FactoryBean接口定义
public interface FactoryBean<T> {
// 返回由FactoryBean创建的Bean实例
T getObject() throws Exception;
// 返回Bean的类型
Class<?> getObjectType();
// 是否是单例
default boolean isSingleton() {
return true;
}
}
// 自定义FactoryBean示例
@Component
public class UserFactoryBean implements FactoryBean<User> {
@Value("${user.default.username}")
private String defaultUsername;
@Override
public User getObject() throws Exception {
// 自定义创建逻辑
User user = new User();
user.setUsername(defaultUsername);
user.setCreatedAt(LocalDateTime.now());
return user;
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
3.4 Spring中其他工厂模式应用
| 类名 | 说明 | 模式类型 |
|---|---|---|
| BeanFactory | Bean工厂,Spring核心容器 | 工厂方法 |
| FactoryBean | 自定义Bean工厂 | 工厂方法 |
| ObjectFactory | 延迟获取Bean的工厂 | 工厂方法 |
| AnnotationConfigApplicationContext | 基于注解配置的应用上下文 | 抽象工厂 |
| ClassPathXmlApplicationContext | 基于XML配置的应用上下文 | 抽象工厂 |
4. 适配器模式
4.1 模式定义
适配器模式(Adapter Pattern)是一种结构型设计模式,它将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
4.2 UML结构
<<interface>>
Target
+request() : void
Adaptee
+specificRequest() : void
Adapter
-adaptee: Adaptee
+request() : void
Client
-target: Target
角色说明:
| 角色 | 说明 |
|---|---|
| Target | 目标接口,客户期望的接口 |
| Adaptee | 被适配者,需要被适配的类 |
| Adapter | 适配器,将Adaptee适配到Target |
| Client | 客户端,通过Target接口调用 |
4.3 Spring中的适配器模式
4.3.1 HandlerAdapter源码分析
Spring MVC中的HandlerAdapter是适配器模式的典型应用。Spring MVC支持多种类型的处理器(Controller、HttpRequestHandler、Servlet等),通过适配器模式统一了处理器的调用方式。
java
// HandlerAdapter接口定义
public interface HandlerAdapter {
// 判断是否支持该处理器
boolean supports(Object handler);
// 处理请求
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception;
// 获取LastModified
long getLastModified(HttpServletRequest request, Object handler);
}
java
// RequestMappingHandlerAdapter:处理@RequestMapping注解的方法
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
// 调用Controller方法
return invokeHandlerMethod(request, response, handlerMethod);
}
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod =
createInvocableHandlerMethod(handlerMethod);
// 设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
// 设置返回值处理器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 执行方法调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
}
}
// HttpRequestHandlerAdapter:处理HttpRequestHandler
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof HttpRequestHandler;
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
// SimpleControllerHandlerAdapter:处理Controller接口
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof Controller;
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
}
上述源码展示了Spring MVC中HandlerAdapter的适配器模式实现。不同类型的处理器(Controller、HttpRequestHandler、HandlerMethod)有不同的调用方式,但通过HandlerAdapter接口的适配,DispatcherServlet可以统一调用所有类型的处理器。这是适配器模式的典型应用。
4.3.2 DispatcherServlet调用流程
java
// DispatcherServlet核心分发方法
public class DispatcherServlet extends FrameworkServlet {
@Nullable
protected ModelAndView doDispatch(HttpServletRequest request, HttpServletResponse response)
throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
try {
ModelAndView mv = null;
// 1. 获取处理器映射
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return null;
}
// 2. 获取处理器适配器(适配器模式)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 执行前置拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return null;
}
// 4. 通过适配器调用处理器
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 5. 执行后置拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
return mv;
} catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
throw ex;
}
}
// 获取适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]");
}
}
4.4 Spring中其他适配器模式应用
| 类名 | 说明 | 被适配对象 |
|---|---|---|
| HandlerAdapter | 处理器适配器 | Controller、HttpRequestHandler、HandlerMethod |
| MethodArgumentResolver | 方法参数解析器 | 各种类型的参数 |
| HandlerExceptionResolver | 异常处理器适配器 | 不同类型的异常 |
| MessageConverter | 消息转换器 | JSON、XML等不同格式 |
| LocaleResolver | 地区解析器 | 不同方式的地区获取 |
5. 策略模式
5.1 模式定义
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以互相替换。策略模式让算法独立于使用它的客户端而变化。
5.2 UML结构
<<interface>>
Strategy
+algorithm() : void
ConcreteStrategyA
+algorithm() : void
ConcreteStrategyB
+algorithm() : void
Context
-strategy: Strategy
+setStrategy(Strategy) : void
+executeStrategy() : void
5.3 Spring中的策略模式
5.3.1 ResourceLoader源码分析
Spring的资源加载机制使用了策略模式,支持多种资源类型的加载。
java
// Resource接口:资源的抽象
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
boolean isFile();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
ReadableByteChannel readableChannel() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
// ResourceLoader接口:资源加载策略
public interface ResourceLoader {
String CLASSPATH_URL_PREFIX = "classpath:";
// 根据位置获取资源
Resource getResource(String location);
// 获取类加载器
ClassLoader getClassLoader();
}
// DefaultResourceLoader:默认资源加载器
public class DefaultResourceLoader implements ResourceLoader {
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
// 策略1:处理URL协议
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
// 策略2:处理classpath:前缀
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()),
getClassLoader());
}
// 策略3:处理文件系统路径
try {
URL url = new URL(location);
return (Resource) new UrlResource(url);
} catch (MalformedURLException ex) {
// 策略4:作为文件系统路径处理
return getResourceByPath(location);
}
}
}
上述代码展示了Spring资源加载的策略模式实现。ResourceLoader接口定义了资源加载的策略,DefaultResourceLoader根据不同的资源位置(classpath:、file:、http:等)选择不同的加载策略。这是策略模式的典型应用。
5.3.2 使用示例
java
// 使用ResourceLoader加载不同类型的资源
@Service
public class ResourceService {
@Autowired
private ResourceLoader resourceLoader;
public void loadResources() throws IOException {
// 加载classpath资源
Resource classpathResource = resourceLoader.getResource("classpath:config.properties");
System.out.println("Classpath资源: " + classpathResource.getDescription());
// 加载文件系统资源
Resource fileResource = resourceLoader.getResource("file:/tmp/data.txt");
System.out.println("文件资源: " + fileResource.getDescription());
// 加载URL资源
Resource urlResource = resourceLoader.getResource("https://example.com/data.json");
System.out.println("URL资源: " + urlResource.getDescription());
// 读取资源内容
try (InputStream is = classpathResource.getInputStream()) {
String content = new String(is.readAllBytes(), StandardCharsets.UTF_8);
System.out.println("内容: " + content);
}
}
}
5.4 Spring中其他策略模式应用
| 类名 | 说明 | 策略接口 |
|---|---|---|
| ResourceLoader | 资源加载 | Resource |
| InstantiationStrategy | Bean实例化策略 | InstantiationStrategy |
| TypeConverter | 类型转换策略 | TypeConverter |
| AopProxy | AOP代理策略 | AopProxy |
| CacheManager | 缓存管理策略 | Cache |
6. 代理模式
6.1 模式定义
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式分为静态代理和动态代理两种。
6.2 代理模式类型
代理模式
静态代理
动态代理
JDK动态代理
CGLIB代理
编译时生成代理类
基于接口
反射生成代理类
基于继承
字节码生成代理类
| 代理类型 | 说明 | 优缺点 |
|---|---|---|
| 静态代理 | 代理类在编译时就存在 | 简单但代码冗余,每个类都需要单独的代理类 |
| JDK动态代理 | 运行时动态生成代理类 | 基于接口,被代理类必须实现接口 |
| CGLIB代理 | 通过字节码技术生成代理类 | 基于继承,可以代理没有接口的类 |
6.3 Spring中的代理模式
Spring AOP是代理模式的典型应用,它通过动态代理实现了横切关注点的模块化。
6.3.1 Spring AOP源码分析
java
// AopProxy接口:AOP代理的抽象
public interface AopProxy {
// 获取代理对象
Object getProxy();
// 获取代理对象(指定类加载器)
Object getProxy(ClassLoader classLoader);
}
// JdkDynamicAopProxy:JDK动态代理实现
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport config) {
Assert.notNull(config, "AdvisedSupport must not be null");
this.advised = config;
}
@Override
public Object getProxy() {
return getProxy(getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取所有接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
// 创建JDK动态代理
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object target = this.advised.getTargetSource().getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 没有拦截器,直接调用目标方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
return AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {
// 创建方法调用对象,执行拦截器链
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
return invocation.proceed();
}
}
}
// CglibAopProxy:CGLIB代理实现
class CglibAopProxy implements AopProxy, Serializable {
private final AdvisedSupport advised;
@Override
public Object getProxy(ClassLoader classLoader) {
// 创建Enhancer
Enhancer enhancer = createEnhancer();
enhancer.setClassLoader(classLoader);
enhancer.setSuperclass(this.advised.getTargetClass());
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 设置回调
Callback[] callbacks = getCallbacks();
enhancer.setCallbacks(callbacks);
// 创建代理对象
return enhancer.create();
}
}
上述源码展示了Spring AOP的代理模式实现。AopProxy接口定义了代理的抽象,JdkDynamicAopProxy和CglibAopProxy分别是JDK动态代理和CGLIB代理的实现。Spring会根据目标类是否实现接口自动选择代理方式。
6.3.2 使用示例
java
// 自定义切面
@Aspect
@Component
public class LoggingAspect {
// 定义切点:所有Service层的public方法
@Pointcut("execution(public * com.example.service.*.*(..))")
public void serviceMethod() {}
// 前置通知
@Before("serviceMethod()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("[LOG] 调用方法: " + methodName + ", 参数: " + Arrays.toString(args));
}
// 后置通知
@AfterReturning(pointcut = "serviceMethod()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("[LOG] 方法返回: " + methodName + ", 结果: " + result);
}
// 异常通知
@AfterThrowing(pointcut = "serviceMethod()", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("[LOG] 方法异常: " + methodName + ", 异常: " + ex.getMessage());
}
// 环绕通知
@Around("serviceMethod()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("[LOG] 方法执行时间: " + (endTime - startTime) + "ms");
return result;
} catch (Exception ex) {
System.out.println("[LOG] 方法执行异常: " + ex.getMessage());
throw ex;
}
}
}
7. 观察者模式
7.1 模式定义
观察者模式(Observer Pattern)是一种行为型设计模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
7.2 UML结构
观察者3 观察者2 观察者1 被观察者 观察者3 观察者2 观察者1 被观察者 notify() notify() notify()
7.3 Spring中的观察者模式
7.3.1 ApplicationEvent源码分析
Spring的事件机制是观察者模式的典型应用,通过ApplicationEvent和ApplicationListener实现了事件的发布和监听。
java
// ApplicationEvent:事件基类
public abstract class ApplicationEvent extends EventObject {
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
// ApplicationListener:事件监听器接口
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 处理事件
void onApplicationEvent(E event);
}
// ApplicationEventPublisher:事件发布接口
@FunctionalInterface
public interface ApplicationEventPublisher {
// 发布事件
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
7.3.2 使用示例
java
// 自定义事件
public class UserRegisteredEvent extends ApplicationEvent {
private final Long userId;
private final String username;
private final String email;
public UserRegisteredEvent(Object source, Long userId, String username, String email) {
super(source);
this.userId = userId;
this.username = username;
this.email = email;
}
public Long getUserId() { return userId; }
public String getUsername() { return username; }
public String getEmail() { return email; }
}
// 事件发布者
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username, String email, String password) {
// 1. 保存用户
User user = new User();
user.setUsername(username);
user.setEmail(email);
user.setPassword(passwordEncoder.encode(password));
userRepository.save(user);
// 2. 发布用户注册事件
eventPublisher.publishEvent(new UserRegisteredEvent(this, user.getId(), username, email));
}
}
// 事件监听器1:发送欢迎邮件
@Component
public class WelcomeEmailListener {
@EventListener
public void onUserRegistered(UserRegisteredEvent event) {
System.out.println("发送欢迎邮件到: " + event.getEmail());
// emailService.sendWelcomeEmail(event.getEmail(), event.getUsername());
}
}
// 事件监听器2:初始化用户数据
@Component
public class UserInitListener {
@EventListener
public void onUserRegistered(UserRegisteredEvent event) {
System.out.println("初始化用户数据: " + event.getUserId());
// userInitService.initUserData(event.getUserId());
}
}
// 事件监听器3:发送积分
@Component
public class PointsListener {
@EventListener
@Async // 异步处理
public void onUserRegistered(UserRegisteredEvent event) {
System.out.println("赠送新用户积分: " + event.getUserId());
// pointsService.grantNewUserPoints(event.getUserId());
}
}
7.4 Spring中其他观察者模式应用
| 类名 | 说明 | 事件类型 |
|---|---|---|
| ContextRefreshedEvent | 容器刷新事件 | ApplicationContext初始化完成 |
| ContextClosedEvent | 容器关闭事件 | ApplicationContext关闭 |
| RequestHandledEvent | 请求处理事件 | HTTP请求处理完成 |
| AuthenticationSuccessEvent | 认证成功事件 | 用户登录成功 |
8. 责任链模式
8.1 模式定义
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
8.2 UML结构
无法处理
无法处理
无法处理
无法处理
可以处理
可以处理
可以处理
Client
Handler1
Handler2
Handler3
...
null
处理完成
8.3 Spring中的责任链模式
8.3.1 HandlerInterceptor源码分析
Spring MVC的拦截器机制使用了责任链模式。
java
// HandlerInterceptor接口:拦截器
public interface HandlerInterceptor {
// 前置处理
default boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
return true;
}
// 后置处理
default void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
// 完成处理
default void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, @Nullable Exception ex) throws Exception {
}
}
// HandlerExecutionChain:拦截器链
public class HandlerExecutionChain {
private final Object handler;
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
// 执行前置拦截器
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
}
return true;
}
// 执行后置拦截器
void applyPostHandle(HttpServletRequest request, HttpServletResponse response,
@Nullable ModelAndView mv) throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
// 执行完成拦截器
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
@Nullable Exception ex) {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
8.3.2 使用示例
java
// 登录拦截器
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !tokenService.validateToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"code\":401,\"message\":\"未登录\"}");
return false;
}
return true;
}
}
// 日志拦截器
@Component
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;
System.out.println("[LOG] " + request.getMethod() + " " + request.getRequestURI() +
" 耗时: " + duration + "ms");
}
}
// 配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Autowired
private LoggingInterceptor loggingInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor)
.addPathPatterns("/**");
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**", "/api/auth/login");
}
}
9. 总结
本文系统性地介绍了模板方法、工厂、适配器、策略、代理、观察者、责任链等设计模式在Spring框架中的实际应用。
9.1 设计模式总结
| 设计模式 | Spring应用 | 核心思想 |
|---|---|---|
| 模板方法 | JdbcTemplate, TransactionTemplate | 定义算法骨架,延迟部分步骤到子类 |
| 工厂方法 | BeanFactory, FactoryBean | 定义创建对象的接口,让子类决定实例化哪个类 |
| 适配器 | HandlerAdapter, MessageConverter | 将一个类的接口转换成客户期望的另一个接口 |
| 策略 | ResourceLoader, InstantiationStrategy | 定义一系列算法,使它们可以互相替换 |
| 代理 | Spring AOP | 为其他对象提供代理以控制对这个对象的访问 |
| 观察者 | ApplicationEvent, ApplicationListener | 定义对象间一对多的依赖关系 |
| 责任链 | HandlerInterceptor, Filter | 使多个对象都有机会处理请求 |
9.2 设计模式使用原则
| 原则 | 说明 |
|---|---|
| 开闭原则 | 对扩展开放,对修改关闭 |
| 单一职责 | 一个类只负责一项职责 |
| 依赖倒置 | 依赖于抽象,不依赖于具体 |
| 接口隔离 | 使用多个隔离的接口,不使用单一的总接口 |
| 里氏替换 | 子类可以替换父类出现在父类能够出现的任何地方 |
| 迪米特法则 | 一个对象应该对其他对象保持最少的了解 |
| 组合复用 | 尽量使用组合而非继承 |
9.3 思考题
-
在你的项目中,哪些场景可以使用模板方法模式来消除重复代码?
-
Spring为什么选择使用JDK动态代理和CGLIB两种代理方式?它们的适用场景分别是什么?
-
观察者模式和发布-订阅模式有什么区别?Spring的事件机制属于哪种?