Spring源码中的设计模式实战:从IOC到AOP,看懂框架设计的底层逻辑
哈喽,各位程序员伙伴~ 👋
上一篇《设计模式高频对比合集》发布后,“学会了模式对比,但实际写项目还是不知道怎么用啊!”
“看Spring源码时,明明知道用到了设计模式,却分不清是哪种、为什么这么用?”
“设计模式和框架的关系到底是什么?总觉得是两张皮!”
这正是今天这篇推文要解决的核心问题——设计模式不是孤立的理论,而是Spring等顶级框架的设计灵魂。我们将以Spring核心模块为载体,手把手带你拆解6种高频设计模式在源码中的实战用法,帮你打通“理论→源码→实战”的任督二脉,从此看源码不懵、写代码有思路!
一、先明确:为什么要从Spring源码学设计模式?
很多人学设计模式陷入了“纸上谈兵”的误区:背熟了23种模式的结构,却连最常用的Spring框架里藏了多少模式都不知道。其实,Spring的核心功能,本质上就是设计模式的“组合拳”——
-
你每天用的
@Autowired,背后是工厂模式+单例模式在支撑; -
切面编程AOP,核心是代理模式的灵活运用;
-
容器事件通知,底层就是观察者模式的经典实现。
学习建议很简单:不要“为了找模式而看源码”,而是“通过源码理解模式的适用场景和演化逻辑”。这篇文章,我们就按这个思路来拆解。
二、核心拆解:Spring源码中的6大设计模式实战
我们精选了Spring中最核心、最典型的6种设计模式,按“模块重要性”排序。每组拆解都包含「模式定位→源码解读→模式演化→实战借鉴」,确保你看完就能用!
1. 工厂模式(工厂方法+抽象工厂):IOC容器的“Bean生产线”
模式定位:核心用于IOC容器(BeanFactory体系),解决“Bean创建逻辑复杂、依赖关系难管理”的问题,将Bean的创建权从业务代码转移到容器,实现创建与使用的解耦。
源码核心片段(简化版):
// 抽象工厂(BeanFactory):定义Bean创建的核心接口public interface BeanFactory {// 核心方法:获取Bean(工厂方法的核心)Object getBean(String name) throws BeansException;}// 具体工厂(DefaultListableBeanFactory):实现Bean创建逻辑public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory {// 存储Bean定义信息private final BeanDefinitionMap beanDefinitionMap = new ConcurrentHashMap<>(256);@Overridepublic 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模块,解决“横切逻辑(日志、权限、事务)与业务逻辑耦合”的问题,通过代理对象封装横切逻辑,实现无侵入式扩展。
源码核心片段(简化版):
// 代理工厂:创建代理对象的核心类public classProxyFactory{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() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throwsThrowable{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() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxyproxy) throwsThrowable{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体系),解决“容器内组件间通信耦合”的问题,实现事件发布者与订阅者的解耦。
源码核心片段(简化版):
// 抽象主题(事件发布者)public interface ApplicationEventPublisher {void publishEvent(ApplicationEvent event);}// 具体主题(容器本身)public class AbstractApplicationContext implements ApplicationContext, ApplicationEventPublisher {// 存储所有观察者(事件监听器)private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();@Overridepublic 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(默认作用域)在整个容器中只有一个实例,避免重复创建浪费资源。
源码核心片段(简化版):
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);@Overridepublic Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {// 1. 先从缓存获取,存在则直接返回Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {// 2. 标记为正在创建beforeSingletonCreation(beanName);try {// 3. 调用工厂创建BeansingletonObject = 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织入等。
源码核心片段(简化版):
// 抽象装饰者(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 {@Overridepublic 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 {@Overridepublic 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执行、结果处理)。
源码核心片段(简化版):
// 抽象父类(模板类):封装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:创建Statementstmt = conn.createStatement();// 固定步骤3:执行SQLrs = 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等核心类,对照文章再看一遍;
-
在自己的项目中,尝试用“模板方法模式”简化重复代码,或用“代理模式”实现功能扩展;
-
收藏本文和配套的拆解图,后续看源码时随时查阅。
下一篇,我们将聚焦面试场景,推出《设计模式面试高频50题(含答案)》,帮你轻松应对设计模式相关面试题!
评论区聊聊:你在看Spring源码时,最疑惑的是哪个设计模式的使用? 👇 点赞+收藏,关注我们,后续干货不错过!
夜雨聆风
