#Spring 设计模式总结
候选人小唐在面试腾讯 P7 时,面试官问道:
"Spring 源码里用到了哪些设计模式?"
小唐说:"用到了工厂模式、代理模式...还有...单例模式?"
面试官追问:"每种模式在 Spring 中是怎么体现的?"
小唐开始支支吾吾。
【面试官心理】 这道题我用来测试候选人对 Spring 框架的全面理解程度。Spring 是 Java 工程师必须掌握的框架,能说出源码中设计模式的人,说明对 Spring 有深入研究。设计模式是 Java 面试的永恒话题,结合 Spring 源码来回答会更有说服力。
#一、核心问题 🔴
#1.1 问题拆解
第一层:模式识别
- "Spring 用到了哪些设计模式?"
- "每种模式分别在哪里体现?"
第二层:深度分析
- "Spring 是怎么实现单例模式的?"
- "Factory 模式在 Spring 中有几种体现?"
- "模板方法模式是怎么用的?"
第三层:实战价值
- "这些设计模式对我们写代码有什么指导意义?"
- "你在项目中用过这些模式吗?"
#1.2 标准回答
#P5 回答:六大核心模式
Spring 源码中使用了大量设计模式,最核心的有六种:
| 设计模式 | 在 Spring 中的体现 | 核心类/接口 |
|---|---|---|
| 单例模式 | Spring Bean 默认单例 | DefaultSingletonBeanRegistry |
| 工厂模式 | BeanFactory 系列 | BeanFactory、FactoryBean |
| 代理模式 | AOP 事务、AOP 切面 | JdkDynamicAopProxy、CglibAopProxy |
| 模板方法模式 | JdbcTemplate、HibernateTemplate | JdbcTemplate、RestTemplate |
| 观察者模式 | 事件监听机制 | ApplicationEvent、ApplicationListener |
| 策略模式 | 事务传播行为、资源获取策略 | TransactionManager |
#1.3 追问升级
追问 1:单例模式
Spring 的单例模式不是传统意义上的单例,而是"容器级单例":
// Spring 的单例注册表
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry {
// 缓存单例 Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 获取单例
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
// 注册单例
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
singletonObjects.put(beanName, singletonObject);
}
}
}和传统单例的区别:
| 对比 | 传统单例 | Spring 单例 |
|---|---|---|
| 数量 | 一个 JVM 一个 | 一个容器一个 |
| 线程安全 | 需要自己保证 | Spring 保证 |
| 延迟加载 | 饿汉/懒汉 | 可配置 |
| 销毁 | JVM 退出时 | 容器关闭时 |
// Spring 单例模式的优势:
// 1. 线程安全由 Spring 容器保证
// 2. 可以懒加载(prototype 单例除外)
// 3. 容易测试
// 4. 可以通过配置切换
// 可以通过 @Scope 切换作用域
@Service
@Scope("prototype") // 每个请求创建新实例
public class MyService { }追问 2:工厂模式
Spring 的工厂模式有三种形态:
// 形态1:简单工厂 - BeanFactory
// BeanFactory 是 Spring 容器的根接口
// 根据 name 获取 Bean,屏蔽了创建细节
// 形态2:工厂方法 - FactoryBean
// 对于复杂的 Bean 创建逻辑,实现 FactoryBean 接口
public class MyFactoryBean implements FactoryBean<MyObject> {
@Override
public MyObject getObject() {
// 复杂的创建逻辑
return new MyObject();
}
}
// 形态3:抽象工厂 - BeanFactory 层次结构
// BeanFactory 有多个子接口和实现类
ConfigurableListableBeanFactory
└─ DefaultListableBeanFactory
└─ XmlBeanFactory(已废弃)追问 3:代理模式
代理模式在 Spring 中无处不在:
// 代理模式在 Spring 中的三大应用场景:
// 1. AOP(面向切面编程)
// 核心类:JdkDynamicAopProxy、CglibAopProxy
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// 获取方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 执行拦截器链
return new CglibMethodInvocation().proceed();
}
}
// 2. Spring 事务
// TransactionInterceptor 代理了业务方法
// 在方法前后添加事务开启/提交/回滚逻辑
// 3. Spring Data JPA
// JpaRepositoryFactory 创建代理
// 为接口方法提供实现追问 4:模板方法模式
// JdbcTemplate 是模板方法模式的经典实现
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
// 模板方法
public <T> T execute(ConnectionCallback<T> action) {
Connection con = null;
try {
con = getDataSource().getConnection();
return action.doInConnection(con); // 调用回调
} catch (SQLException e) {
throw convertJdbcAccessException(e);
} finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
// 具体方法 - 使用模板方法
public List<Map<String, Object>> queryForList(String sql) {
return execute(connection -> {
PreparedStatement ps = connection.prepareStatement(sql);
return executeQuery(ps);
});
}
}模板方法模式结构:
JdbcTemplate.execute() // 模板方法,定义骨架
├─ 获取连接
├─ try {
│ doInConnection() // 抽象步骤,由子类实现
│ } finally {
│ 释放连接
│ }
子类实现:
└─ query()、update() 等 // 具体实现追问 5:观察者模式
// Spring 事件机制是观察者模式的实现
// 1. 事件(Subject)
public abstract class ApplicationEvent extends EventObject {
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
}
// 2. 监听器(Observer)
public interface ApplicationListener<E extends ApplicationEvent> {
void onApplicationEvent(E event);
}
// 3. 事件广播器(管理 Observer)
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> listener);
void removeApplicationListener(ApplicationListener<?> listener);
void multicastEvent(ApplicationEvent event);
}追问 6:策略模式
// 策略模式在 Spring 事务中的应用
// 定义策略接口
public interface TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition);
void commit(TransactionStatus status);
void rollback(TransactionStatus status);
}
// 具体策略实现
public class DataSourceTransactionManager implements TransactionManager {
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) {
// 数据源事务策略
}
}
public class JpaTransactionManager implements TransactionManager {
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) {
// JPA 事务策略
}
}
// 使用
@Bean
public TransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource);
}#二、延伸问题 🟡
#2.1 其他设计模式
适配器模式:
// Spring MVC 中的 HandlerAdapter
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler);
}
// Spring 根据不同的 Controller 类型选择不同的 Adapter
// RequestMappingHandlerAdapter、SimpleControllerHandlerAdapter 等装饰器模式:
// HttpServletRequestWrapper 装饰了 HttpServletRequest
public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
private byte[] content;
// 可以在读取 body 之前/之后做一些处理
}
// BufferedReader 装饰了 Reader
// BeanWrapper 装饰了 Bean责任链模式:
// FilterChain 是责任链模式
public interface FilterChain {
void doFilter(ServletRequest request, ServletResponse response);
}
// AOP 拦截器链
public class ReflectiveMethodInvocation implements MethodInvocation {
List<Object> interceptorsAndDynamicMethodMatchers;
public Object proceed() {
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinPoint();
}
// 依次调用下一个拦截器
return this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)
.invoke(this);
}
}建造者模式:
// MockMvc 的构建
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
// UriComponentsBuilder
UriComponents uri = UriComponentsBuilder.fromUriString("http://example.com")
.path("/api")
.queryParam("id", 1)
.build()
.expand("name")
.encode();#三、设计模式的启示
#3.1 从 Spring 学到的设计原则
| 原则 | Spring 体现 |
|---|---|
| 开闭原则 | 扩展通过 FactoryBean、BeanPostProcessor |
| 依赖倒置 | 面向接口编程,BeanFactory 接口定义 |
| 里氏替换 | 所有 TransactionManager 实现可互换 |
| 接口隔离 | 分离不同功能的接口 |
| 单一职责 | 每个类职责明确 |
| 迪米特法则 | BeanFactory 隐藏创建细节 |
#3.2 在项目中的应用
// 1. 使用模板方法模式封装重复逻辑
public abstract class BaseService<T> {
@Autowired
protected BaseRepository<T> repository;
public void save(T entity) {
beforeSave(entity);
repository.save(entity);
afterSave(entity);
}
protected void beforeSave(T entity) { } // 钩子方法
protected void afterSave(T entity) { }
}
// 2. 使用策略模式处理多种支付方式
@Service
public class PaymentStrategyFactory {
@Autowired
private Map<String, PaymentStrategy> strategies;
public PaymentStrategy getStrategy(String type) {
PaymentStrategy strategy = strategies.get(type);
if (strategy == null) {
throw new IllegalArgumentException("不支持的支付方式: " + type);
}
return strategy;
}
}
public interface PaymentStrategy {
void pay(Order order);
void refund(Order order);
}
// 3. 使用观察者模式解耦业务逻辑
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
public void createOrder() {
orderRepository.save(order);
publisher.publishEvent(new OrderCreatedEvent(order));
}
}#四、面试总结
Spring 设计模式是展示你对 Spring 理解深度的好机会。
P5 候选人能说出 2-3 种设计模式。 P6 候选人能说出 5-6 种,并能给出 Spring 中的具体体现。 P7 候选人能结合源码分析每种模式的实现,并能在项目中应用这些模式。
记住,面试中不是背设计模式的名字,而是展示你对 Spring 框架设计思想的理解。