乐于分享
好东西不私藏

Spring源码中的设计模式实战:从IOC到AOP,看懂框架设计的底层逻辑

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 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模块,解决“横切逻辑(日志、权限、事务)与业务逻辑耦合”的问题,通过代理对象封装横切逻辑,实现无侵入式扩展。

源码核心片段(简化版)

// 代理工厂:创建代理对象的核心类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() {                    @Override                    public Object invoke(Object proxy, Method methodObject[] argsthrowsThrowable{                        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 methodObject[] argsMethodProxyproxythrowsThrowable{                    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 ApplicationContextApplicationEventPublisher {    // 存储所有观察者(事件监听器)    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(默认作用域)在整个容器中只有一个实例,避免重复创建浪费资源。

源码核心片段(简化版)

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {    // 存储单例Bean的缓存(核心:确保唯一)    private final Map<StringObject> singletonObjects = new ConcurrentHashMap<>(256);    // 存储正在创建的Bean,解决循环依赖    private final Map<StringObjectFactory<?&gt;&gt; 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织入等。

源码核心片段(简化版)

// 抽象装饰者(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执行、结果处理)。

源码核心片段(简化版)

// 抽象父类(模板类):封装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个核心技巧,帮你快速复用:

  1. 模式组合优于单一使用:Spring很少单独用一种模式,比如IOC容器=工厂模式+单例模式+装饰者模式,AOP=代理模式+模板方法模式。实际项目中,也可根据场景组合多种模式;

  2. 不被模式结构束缚:Spring不会严格遵循模式的“标准结构”,比如BeanFactory既是抽象工厂,又包含工厂方法的逻辑。核心是“解决问题”,而非“符合模式定义”;

  3. 聚焦核心思想而非细节:不管是工厂模式还是代理模式,核心都是“封装变化”。抓住这个核心,就能灵活调整模式的实现方式。

四、结尾:从“看懂”到“会用”的最后一步

今天这篇文章,我们通过Spring核心模块,拆解了6种设计模式的实战用法。其实,设计模式的学习没有捷径——先懂理论,再看源码,最后落地到项目

下一步,建议你按这个流程实践:

  • 打开Spring源码,找到BeanFactory、ProxyFactory等核心类,对照文章再看一遍;

  • 在自己的项目中,尝试用“模板方法模式”简化重复代码,或用“代理模式”实现功能扩展;

  • 收藏本文和配套的拆解图,后续看源码时随时查阅。

下一篇,我们将聚焦面试场景,推出《设计模式面试高频50题(含答案)》,帮你轻松应对设计模式相关面试题!

评论区聊聊:你在看Spring源码时,最疑惑的是哪个设计模式的使用? 👇 点赞+收藏,关注我们,后续干货不错过!

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » Spring源码中的设计模式实战:从IOC到AOP,看懂框架设计的底层逻辑

评论 抢沙发

5 + 7 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮