"看Spring源码时,明明知道用到了设计模式,却分不清是哪种、为什么这么用?"
"设计模式和框架的关系到底是什么?总觉得是两张皮!"
这正是今天这篇文章要解决的核心问题------设计模式不是孤立的理论,而是Spring等顶级框架的设计灵魂。我们将以Spring核心模块为载体,手把手带你拆解6种高频设计模式在源码中的实战用法,帮你打通"理论→源码→实战"的任督二脉,从此看源码不懵、写代码有思路!
一、先明确:为什么要从Spring源码学设计模式?
很多人学设计模式陷入了"纸上谈兵"的误区:背熟了23种模式的结构,却连最常用的Spring框架里藏了多少模式都不知道。其实,Spring的核心功能,本质上就是设计模式的"组合拳":
- 你每天用的@Autowired ,背后是工厂模式+单例模式在支撑;
- 切面编程AOP ,核心是代理模式的灵活运用;
- 容器事件通知 ,底层就是观察者模式的经典实现。
学习建议很简单:不要"为了找模式而看源码",而是"通过源码理解模式的适用场景和演化逻辑"。这篇文章,我们就按这个思路来拆解。
二、核心拆解:Spring源码中的6大设计模式实战
我们精选了Spring中最核心、最典型的6种设计模式,按"模块重要性"排序。每组拆解都包含「模式定位→源码解读→模式演化→实战借鉴」,确保你看完就能用!
1. 工厂模式(工厂方法+抽象工厂):IOC容器的"Bean生产线"
模式定位:核心用于IOC容器(BeanFactory体系),解决"Bean创建逻辑复杂、依赖关系难管理"的问题,将Bean的创建权从业务代码转移到容器,实现创建与使用的解耦。
源码核心片段(简化版):
java
// 抽象工厂(BeanFactory):定义Bean创建的核心接口
public interface BeanFactory {
// 核心方法:获取Bean(工厂方法的核心)
Object getBean(String name) throws BeansException;
}
// 具体工厂(DefaultListableBeanFactory):实现Bean创建逻辑
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory {
// 存储Bean定义信息
private final BeanDefinitionMap beanDefinitionMap = new ConcurrentHashMap<>(256);
@Override
public Object getBean(String name) throws BeansException {
// 1. 检查Bean是否已创建(单例缓存)
Object sharedInstance = getSingleton(name);
if (sharedInstance != null) {
return sharedInstance;
}
// 2. 加载Bean定义
BeanDefinition bd = getBeanDefinition(name);
// 3. 创建Bean(核心:封装创建逻辑)
return createBean(name, bd);
}
}
// 抽象工厂的扩展(ApplicationContext):组合多个具体工厂
public interface ApplicationContext extends BeanFactory {
// 扩展功能:国际化、事件发布等
}
模式演化分析:Spring没有严格区分工厂方法和抽象工厂,而是做了灵活扩展:
- BeanFactory对应"抽象工厂",定义了Bean创建的统一接口;
- DefaultListableBeanFactory对应"具体工厂",实现了Bean的创建逻辑;
- ApplicationContext作为"超级工厂",组合了BeanFactory、ResourceLoader等多个工厂的功能,形成层级化工厂体系。
实战借鉴:项目中创建复杂对象(如数据源、RPC客户端)时,可借鉴这种"抽象工厂+具体工厂"的结构:
- 定义抽象工厂接口,统一对象创建入口;
- 不同环境(开发/测试/生产)对应不同的具体工厂;
- 用"超级工厂"封装多个子工厂,提供一站式服务。
2. 代理模式(JDK动态代理+CGLIB代理):AOP的"无侵入魔法"
模式定位:核心用于AOP模块,解决"横切逻辑(日志、权限、事务)与业务逻辑耦合"的问题,通过代理对象封装横切逻辑,实现无侵入式扩展。
源码核心片段(简化版):
java
// 代理工厂:创建代理对象的核心类
public class ProxyFactory {
private Object target; // 目标对象(业务类)
private Advice advice; // 横切逻辑(如事务、日志)
public Object getProxy() {
// 1. 若目标对象实现接口,用JDK动态代理
if (target.getClass().getInterfaces().length > 0) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.before(method); // 横切逻辑:方法前执行
Object result = method.invoke(target, args); // 执行业务方法
advice.after(method); // 横切逻辑:方法后执行
return result;
}
}
);
} else {
// 2. 若目标对象无接口,用CGLIB代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
advice.before(method);
Object result = proxy.invokeSuper(obj, args);
advice.after(method);
return result;
}
});
return enhancer.create();
}
}
}
模式演化分析:Spring对代理模式的扩展核心是"双代理机制":
- JDK动态代理:基于接口实现,性能好,适合有接口的场景;
- CGLIB代理:基于子类继承实现,无接口也能用,适合复杂类;
- 自动切换:ProxyFactory会根据目标对象是否有接口,自动选择合适的代理方式,兼顾灵活性和性能。
实战借鉴:项目中需要扩展功能但不想修改原有代码时,可借鉴这种"双代理"思路:
- 简单场景用JDK动态代理,复杂场景用CGLIB;
- 将横切逻辑封装成"Advice",通过代理工厂统一织入;
- 避免代理过度:只有横切逻辑才用代理,简单扩展直接用装饰者模式。
3. 观察者模式:Spring事件机制的"消息中转站"
模式定位:核心用于Spring事件机制(ApplicationEvent体系),解决"容器内组件间通信耦合"的问题,实现事件发布者与订阅者的解耦。
源码核心片段(简化版):
java
// 抽象主题(事件发布者)
public interface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
}
// 具体主题(容器本身)
public class AbstractApplicationContext implements ApplicationContext, ApplicationEventPublisher {
// 存储所有观察者(事件监听器)
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
@Override
public void publishEvent(ApplicationEvent event) {
// 通知所有观察者
for (ApplicationListener<?> listener : applicationListeners) {
((ApplicationListener<ApplicationEvent>) listener).onApplicationEvent(event);
}
}
// 注册观察者
public void addApplicationListener(ApplicationListener<?> listener) {
this.applicationListeners.add(listener);
}
}
// 抽象观察者(事件监听器)
public interface ApplicationListener<E extends ApplicationEvent> {
void onApplicationEvent(E event);
}
// 具体事件(自定义事件)
public class UserRegisterEvent extends ApplicationEvent {
private String username;
public UserRegisterEvent(Object source, String username) {
super(source);
this.username = username;
}
}
模式演化分析:Spring对观察者模式的扩展体现在"事件分层+异步支持":
- 事件分层:ApplicationEvent有多个子类(如ContextRefreshedEvent、UserRegisterEvent),支持不同类型的事件;
- 异步监听:通过@Async注解,可实现观察者的异步执行,避免阻塞发布者;
- 自动注册:监听器无需手动注册,容器会自动扫描并添加。
实战借鉴:项目中组件间通信时,可借鉴这种"事件驱动"思路:
- 定义统一的事件父类,按业务类型拆分具体事件;
- 发布者只负责发布事件,不关心谁来处理;
- 关键业务用同步监听,非关键业务用异步监听,提升性能。
4. 单例模式:Spring Bean的"唯一身份标识"
模式定位:核心用于IOC容器的Bean作用域管理,确保单例Bean(默认作用域)在整个容器中只有一个实例,避免重复创建浪费资源。
源码核心片段(简化版):
java
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
// 存储单例Bean的缓存(核心:确保唯一)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 存储正在创建的Bean,解决循环依赖
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
@Override
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 1. 先从缓存获取,存在则直接返回
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 2. 标记为正在创建
beforeSingletonCreation(beanName);
try {
// 3. 调用工厂创建Bean
singletonObject = singletonFactory.getObject();
} finally {
// 4. 取消正在创建的标记
afterSingletonCreation(beanName);
}
// 5. 存入缓存,后续直接获取
addSingleton(beanName, singletonObject);
}
return singletonObject;
}
}
// 存入单例缓存
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
}
}
}
模式演化分析:Spring对单例模式的扩展核心是"懒加载+循环依赖解决":
- 懒加载:默认情况下,单例Bean在第一次获取时才创建(而非容器启动时),节省内存;
- 循环依赖解决:通过singletonFactories缓存"正在创建的Bean",实现A依赖B、B依赖A的循环依赖处理;
- 线程安全:用ConcurrentHashMap+同步锁,确保多线程环境下Bean的唯一性。
实战借鉴:项目中需要全局唯一实例(如配置中心、连接池)时,可借鉴这种思路:
- 用ConcurrentHashMap做缓存,确保线程安全和唯一性;
- 支持懒加载,避免启动时创建过多对象;
- 谨慎使用单例:有状态的对象(如用户上下文)不要用单例,避免线程安全问题。
5. 装饰者模式:BeanPostProcessor的"功能增强器"
模式定位:核心用于IOC容器的Bean增强(BeanPostProcessor体系),解决"Bean创建后需要动态添加功能"的问题,如属性注入、初始化回调、AOP织入等。
源码核心片段(简化版):
java
// 抽象装饰者(Bean后置处理器)
public interface BeanPostProcessor {
// Bean初始化前增强
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// Bean初始化后增强
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
// 具体装饰者(Autowired注解处理器)
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 增强功能:解析@Autowired注解,注入依赖
injectAutowiredDependencies(bean);
return bean;
}
private void injectAutowiredDependencies(Object bean) {
// 核心逻辑:查找@Autowired注解的字段/方法,注入对应的Bean
}
}
// 具体装饰者(AOP织入处理器)
public class AnnotationAwareAspectJAutoProxyCreator implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 增强功能:判断Bean是否需要AOP,若需要则创建代理对象
return wrapIfNecessary(bean, beanName);
}
}
模式演化分析:Spring对装饰者模式的扩展体现在"链式增强+灵活组合":
- 链式增强:容器中有多个BeanPostProcessor,会按顺序依次对Bean进行增强,形成"装饰链";
- 功能拆分:不同的增强功能对应不同的BeanPostProcessor(如Autowired处理、AOP织入),职责清晰;
- 动态扩展:用户可自定义BeanPostProcessor,轻松给Bean添加自定义功能。
实战借鉴:项目中需要动态增强对象功能时,可借鉴这种"链式装饰"思路:
- 定义统一的增强接口(类似BeanPostProcessor);
- 不同增强功能对应不同的实现类,避免一个类承担过多职责;
- 按优先级排序增强器,形成链式处理流程。
6. 模板方法模式:JdbcTemplate的"代码简化神器"
模式定位:核心用于JDBC模块(JdbcTemplate),解决"JDBC操作代码冗余、重复"的问题,封装固定骨架(如获取连接、关闭资源),让用户只需关注核心业务逻辑(SQL执行、结果处理)。
源码核心片段(简化版):
java
// 抽象父类(模板类):封装JDBC操作的固定骨架
public abstract class JdbcAccessor {
private DataSource dataSource;
// 固定方法:获取数据库连接
protected Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 固定方法:关闭资源
protected void close(Connection conn, Statement stmt, ResultSet rs) {
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
// 异常处理
}
}
}
// 具体模板类:实现模板方法
public class JdbcTemplate extends JdbcAccessor {
// 模板方法:封装固定流程
public <T> T query(String sql, RowMapper<T> rowMapper) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 固定步骤1:获取连接
conn = getConnection();
// 固定步骤2:创建Statement
stmt = conn.createStatement();
// 固定步骤3:执行SQL
rs = stmt.executeQuery(sql);
// 变化步骤:处理结果(由用户实现)
return rowMapper.mapRow(rs);
} catch (SQLException e) {
// 固定步骤4:异常处理
handleException(e);
} finally {
// 固定步骤5:关闭资源
close(conn, stmt, rs);
}
return null;
}
}
// 变化步骤的实现(由用户提供)
public interface RowMapper<T> {
T mapRow(ResultSet rs) throws SQLException;
}
模式演化分析:Spring对模板方法模式的扩展核心是"回调函数+功能扩展":
- 回调函数:用RowMapper、PreparedStatementSetter等接口作为"回调",让用户实现变化步骤,灵活度高;
- 功能扩展:JdbcTemplate提供了query、update、execute等多个模板方法,覆盖JDBC的所有核心操作;
- 异常统一处理:模板类统一处理SQLException,用户无需重复写异常处理代码。
实战借鉴:项目中存在"固定流程+变化步骤"的场景(如API调用、文件处理)时,可借鉴这种思路:
- 抽象类封装固定流程(如API调用的"建立连接→发送请求→关闭连接");
- 用接口定义变化步骤(如请求参数组装、响应结果处理);
- 统一处理异常、日志等公共逻辑,减少冗余代码。
三、实战升华:从Spring源码学模式的3个关键技巧
看完上面的拆解,你会发现Spring使用设计模式的思路非常灵活,绝非"照搬书本"。总结3个核心技巧,帮你快速复用:
-
模式组合优于单一使用:Spring很少单独用一种模式,比如IOC容器=工厂模式+单例模式+装饰者模式,AOP=代理模式+模板方法模式。实际项目中,也可根据场景组合多种模式;
-
不被模式结构束缚:Spring不会严格遵循模式的"标准结构",比如BeanFactory既是抽象工厂,又包含工厂方法的逻辑。核心是"解决问题",而非"符合模式定义";
-
聚焦核心思想而非细节:不管是工厂模式还是代理模式,核心都是"封装变化"。抓住这个核心,就能灵活调整模式的实现方式。
四、结尾:从"看懂"到"会用"的最后一步
今天这篇文章,我们通过Spring核心模块,拆解了6种设计模式的实战用法。其实,设计模式的学习没有捷径------先懂理论,再看源码,最后落地到项目。
下一步,建议你按这个流程实践:
- 打开Spring源码,找到BeanFactory、ProxyFactory等核心类,对照文章再看一遍;
- 在自己的项目中,尝试用"模板方法模式"简化重复代码,或用"代理模式"实现功能扩展;
- 遇到复杂场景时,思考"Spring会怎么设计",借鉴其模式组合的思路。
记住:设计模式不是"银弹",而是"工具箱"。掌握它们,不是为了炫技,而是为了写出更优雅、更易维护的代码。