面试记录 2026-09-28
题目:Spring中用到了哪些设计模式
难度:difficulty/high
标签:spring/practice, general/knowledge, difficulty/high
评分:⭐⭐⭐☆☆(3/5)
我的回答
Spring 中最常规的首先是代理,它的大部分功能都是基于代理的实现的,AOP。另外就是工厂,工厂方法,它的创建对象都是基于工厂方法去实现的。再之后是单例模式,它的管理 bean 的模式大部分是单例的。还有就是享元模式。再有就是模板模式,它的很多功能是模板化的,比如 Resent Template Latter,JDBC Template Latter 都是模板方法性质的。然后是策略模式,其他的暂时想不起来了。
点评
优点:
- 核心模式答对了:代理(AOP)、工厂(BeanFactory)、模板方法(JdbcTemplate/RestTemplate)、策略(事务管理器多实现)
- 单例模式:Bean 默认作用域确实是 singleton
不足:
- "享元模式"是错误答案 —— 这是本题的失分点。Spring 里没有明显的享元模式实现,可能把"单例"或"对象池"记混了。享元模式是共享细粒度对象(如 Integer.valueOf(127) 的对象缓存、字符串常量池)
- 漏了几个非常经典的设计模式:
- 观察者模式:@EventListener / ApplicationEventPublisher / ApplicationListener
- 适配器模式:AbstractCachingErrorHandler、HandlerMethodReturnValueHandler
- 装饰器模式:JDK/CGLIB 代理某种程度上也是装饰器
- 责任链模式:SpringMVC 的 HandlerInterceptor、Spring Security 的 FilterChain
- 建造者模式:@Bean 方法、JdbcTemplate.builder()
- 中介者模式:ApplicationContext
- 抽象工厂:BeanFactory / FactoryBean
- Spring 的"单例"和 GoF 单例不完全一样,没点出这个区别
- 策略模式的例子不具体
补充(Spring 设计模式分类表):
| 类别 | 模式 | Spring 实现 |
|---|
| 创建型 | 单例模式 | Bean 默认 singleton 作用域 |
| 工厂方法 | BeanFactory.getBean() / FactoryBean.getObject() |
| 抽象工厂 | BeanFactory 本身 |
| 建造者 | @Configuration 类中 @Bean 方法 |
| 结构型 | 代理模式 | AOP、JDK 动态代理、CGLIB 代理 |
| 装饰器 | 代理增强、HttpServletRequestWrapper |
| 适配器 | AbstractCachingErrorHandler、HandlerMethodReturnValueHandler |
| 外观模式 | RestTemplate / JdbcTemplate |
| 行为型 | 模板方法 | JdbcTemplate.execute()、RestTemplate.exchange() |
| 观察者 | ApplicationEvent / @EventListener |
| 策略 | PlatformTransactionManager 多实现、ResourceLoader 多实现 |
| 责任链 | HandlerInterceptor、FilterChain |
| 中介者 | ApplicationContext |
| 状态模式 | TransactionSynchronizationManager |
关键区分点:
- 代理 vs 装饰器:代理是控制访问(AOP),装饰器是动态添加功能
- 工厂 vs 建造者:工厂一次性创建,建造者分步构建复杂对象
- Spring 单例 vs GoF 单例:Spring 是容器级单例(可多容器),GoF 是全局唯一
完整讲解
第一部分:知识重点剖析
核心考点定位:考察对 Spring 源码架构的理解深度,以及能否把设计模式与 Spring 的实际实现一一对应。
知识点拆解:
- 创建型模式:
- 单例模式:Bean 默认作用域是 singleton,容器保证每个 bean 定义只有一个实例。注意区分 Spring 单例 vs GoF 单例:Spring 是容器级单例(可多容器并存),GoF 是全局唯一(静态实例 + 私有构造器)
- 工厂方法:BeanFactory.getBean() 按名称/类型获取 bean,本质是工厂方法模式
- 抽象工厂:FactoryBean 是"生产其他 bean 的工厂",Spring 在容器启动时调用 FactoryBean.getObject() 得到真正的业务 bean
- 建造者:@Configuration 类中的 @Bean 方法内部多行初始化代码,本质是建造者模式构建复杂对象
- 结构型模式:
- 代理模式(Spring 最大特色):AOP 通过 JDK 动态代理(基于接口)或 CGLIB(基于继承)在运行时包装目标对象
- 装饰器模式:代理增强、HttpServletRequestWrapper 等包装类
- 适配器模式:AbstractCachingErrorHandler、HandlerMethodReturnValueHandler 系列把不同格式的返回值适配到统一响应
- 外观模式(Facade):JdbcTemplate、RestTemplate 把 JDBC/HTTP 客户端的复杂操作收敛为几个简单方法
- 行为型模式:
- 模板方法:JdbcTemplate.execute()、RestTemplate.exchange() 定义了"操作-预处理-后置处理"的算法骨架,子类/lambda 实现具体细节
- 观察者模式:ApplicationEvent + ApplicationListener + @EventListener 实现事件驱动,@TransactionalEventListener 更进一步结合事务
- 策略模式:PlatformTransactionManager 有多种实现(DataSourceTransactionManager / JtaTransactionManager),ResourceLoader 有多种实现(ClassLoaderResourceLoader / DefaultResourceLoader),运行时选不同实现
- 责任链模式:SpringMVC 的 HandlerInterceptor 链、Spring Security 的 FilterChain
- 中介者模式:ApplicationContext 协调 Bean 之间的通信
- 状态模式:TransactionSynchronizationManager 管理事务同步状态
- 几个容易搞混的对比:
- 代理 vs 装饰器:代理是控制访问(AOP、远程代理、保护代理),装饰器是动态添加功能(IO 流装饰)
- 工厂 vs 建造者:工厂一次性创建,建造者分步构建复杂对象
- 观察者 vs 发布-订阅:观察者是同步通知,发布-订阅通常引入消息中间件
- 享元模式的常见误用(本题失分点):
- 享元模式是共享细粒度对象以减少内存开销,如 Integer 缓存、字符串常量池、Character 缓存
- Spring 中并没有明显的享元模式实现,容易和"单例"混淆
第二部分:考察方向与延伸递进
考察方向:
- 深度:Spring 源码中对设计模式的具体实现类
- 广度:设计模式之间的对比和适用边界
- 应用:业务开发中如何借鉴 Spring 的设计思路
延伸递进面试题:
- Spring 的三级缓存用了什么设计模式?如果不用工厂模式(ObjectFactory)会怎样?
- 解答要点:三级缓存本质是抽象工厂模式(L3 存的是 ObjectFactory,延迟决定"要不要代理")。如果不用工厂模式,只能用两级缓存,但会导致 AOP 场景下"B 持有 A 原始对象而 A 自身持有代理对象"的引用分裂问题。三级缓存的核心价值是让"是否代理"的决策延迟到运行时按需生成
- Spring 里有哪些地方用到了责任链?如果让你自定义一条拦截链怎么做?
- 解答要点:SpringMVC 的 HandlerInterceptor(preHandle/afterCompletion/postHandle)、Spring Security 的 FilterChain、Tomcat 的 Pipeline、Spring AOP 的 AdviceChain 都用责任链。自定义方式:定义接口 Handler { boolean handle(Request ctx, Handler next); },构造一个 List<Handler>,运行时依次调用 handler.handle(ctx, next),最后一个 handler 处理业务逻辑,异常向上传播
- Spring 的观察者模式如何结合事务使用?@TransactionalEventListener 的 phase 有哪些?
- 解答要点:@TransactionalEventListener 结合事务使用,支持 BEFORE_COMMIT、AFTER_COMMIT、AFTER_ROLLBACK、BEFORE_COMPLETION 四种 phase,默认是 AFTER_COMMIT。适合"事务提交后再发通知/发消息"的场景,避免事务回滚后消息已经发出去的问题
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,Spring 是设计模式的集大成者,我按创建型、结构型、行为型三大类来讲。
创建型模式:
- 单例模式:Bean 默认作用域是 singleton,容器保证每个 bean 定义只有一个实例。这里有个关键点:Spring 的"单例"是容器级单例(可多容器并存),和 GoF 的"全局唯一单例"(静态实例 + 私有构造器)不完全一样
- 工厂方法:BeanFactory.getBean() 按名称/类型获取 bean,本质是工厂方法模式
- 抽象工厂:FactoryBean 是"生产其他 bean 的工厂",Spring 在容器启动时调用 FactoryBean.getObject() 得到真正的业务 bean
- 建造者:@Configuration 类中的 @Bean 方法内部多行初始化代码,本质是建造者模式
结构型模式:
- 代理模式(Spring 最大特色):AOP 通过 JDK 动态代理(基于接口)或 CGLIB(基于继承)在运行时包装目标对象
- 装饰器模式:代理增强、HttpServletRequestWrapper 等包装类
- 适配器模式:AbstractCachingErrorHandler、HandlerMethodReturnValueHandler 系列把不同格式的返回值适配到统一响应
- 外观模式(Facade):JdbcTemplate、RestTemplate 把 JDBC/HTTP 客户端的复杂操作收敛为几个简单方法
行为型模式:
- 模板方法:JdbcTemplate.execute()、RestTemplate.exchange() 定义了"操作-预处理-后置处理"的算法骨架,子类/lambda 实现具体细节
- 观察者模式:ApplicationEvent + ApplicationListener + @EventListener 实现事件驱动,@TransactionalEventListener 更进一步结合事务
- 策略模式:PlatformTransactionManager 有多种实现(DataSourceTransactionManager / JtaTransactionManager),ResourceLoader 有多种实现(ClassLoaderResourceLoader / DefaultResourceLoader),运行时选不同实现
- 责任链模式:SpringMVC 的 HandlerInterceptor 链、Spring Security 的 FilterChain
- 中介者模式:ApplicationContext 协调 Bean 之间的通信
- 状态模式:TransactionSynchronizationManager 管理事务同步状态
几个容易搞混的对比:
- 代理 vs 装饰器:代理是控制访问(AOP、远程代理),装饰器是动态添加功能(IO 流装饰)
- 工厂 vs 建造者:工厂一次性创建,建造者分步构建复杂对象
关于享元模式的一个澄清:享元模式是共享细粒度对象以减少内存开销(如 Integer 缓存、字符串常量池),Spring 中并没有明显的享元模式实现,容易和"单例"混淆。
实际工程借鉴:我在写业务代码时会借鉴 Spring 的设计思路——比如用模板方法把"参数校验-业务执行-后置日志"的重复代码抽象成 Template;用观察者模式通过 Spring 事件解耦业务模块(订单支付完成后触发积分、通知、库存回滚);用工厂模式把复杂的 Bean 构建封装在 @Configuration 类里。
面试记录 2026-10-11
题目:Spring中用到了哪些设计模式
难度:difficulty/high
标签:spring/practice, difficulty/high
评分:⭐⭐⭐☆☆(3/5)
我的回答
Spring 中用到很多设计模式,最核心的首先是代理模式,它的很多依赖的基础都是代理,IOC 都是基于代理模式去实现的。然后是模板方法,比如,Rest Template,JDBC Template,这都是基于模板方法去实现。然后是责任链设计模式,有单例模式、享元模式,策略模式,工厂模式等;
点评
优点:
- 核心模式答对了:代理(AOP)、模板方法(RestTemplate/JdbcTemplate)、责任链、单例、策略、工厂
- 提到了代理是 Spring 的核心基础
不足:
- "IoC 都是基于代理"表述不准确:IoC 核心是控制反转(容器管理对象生命周期),代理主要用于 AOP
- "享元模式"是错误答案(和 2026-09-28 一样):Spring 里没有明显的享元模式实现,享元是共享细粒度对象(如 Integer 缓存、字符串常量池)
- 漏掉了观察者模式(@EventListener)、适配器模式(HandlerMethodReturnValueHandler)、中介者模式(ApplicationContext)等
- 责任链模式没有举例(SpringMVC HandlerInterceptor、Spring Security FilterChain)
补充:
- Spring 设计模式分类(创建型/结构型/行为型)
- 关键区分:代理 vs 装饰器、工厂 vs 建造者、Spring 单例 vs GoF 单例
完整讲解
第一部分:知识重点剖析
核心考点定位:考察对 Spring 源码架构的理解深度,以及能否把设计模式与 Spring 的实际实现一一对应。
知识点拆解:
- 创建型模式:
- 单例模式:Bean 默认作用域是 singleton,容器保证每个 bean 定义只有一个实例。注意区分 Spring 单例 vs GoF 单例:Spring 是容器级单例(可多容器并存),GoF 是全局唯一(静态实例 + 私有构造器)
- 工厂方法:BeanFactory.getBean() 按名称/类型获取 bean,本质是工厂方法模式
- 抽象工厂:FactoryBean 是"生产其他 bean 的工厂",Spring 在容器启动时调用 FactoryBean.getObject() 得到真正的业务 bean
- 建造者:@Configuration 类中的 @Bean 方法内部多行初始化代码,本质是建造者模式构建复杂对象
- 结构型模式:
- 代理模式(Spring 最大特色):AOP 通过 JDK 动态代理(基于接口)或 CGLIB(基于继承)在运行时包装目标对象
- 装饰器模式:代理增强、HttpServletRequestWrapper 等包装类
- 适配器模式:AbstractCachingErrorHandler、HandlerMethodReturnValueHandler 系列把不同格式的返回值适配到统一响应
- 外观模式(Facade):JdbcTemplate、RestTemplate 把 JDBC/HTTP 客户端的复杂操作收敛为几个简单方法
- 行为型模式:
- 模板方法:JdbcTemplate.execute()、RestTemplate.exchange() 定义了"操作 - 预处理 - 后置处理"的算法骨架,子类/lambda 实现具体细节
- 观察者模式:ApplicationEvent + ApplicationListener + @EventListener 实现事件驱动,@TransactionalEventListener 更进一步结合事务
- 策略模式:PlatformTransactionManager 有多种实现(DataSourceTransactionManager / JtaTransactionManager),ResourceLoader 有多种实现(ClassLoaderResourceLoader / DefaultResourceLoader),运行时选不同实现
- 责任链模式:SpringMVC 的 HandlerInterceptor 链、Spring Security 的 FilterChain
- 中介者模式:ApplicationContext 协调 Bean 之间的通信
- 状态模式:TransactionSynchronizationManager 管理事务同步状态
- 几个容易搞混的对比:
- 代理 vs 装饰器:代理是控制访问(AOP、远程代理、保护代理),装饰器是动态添加功能(IO 流装饰)
- 工厂 vs 建造者:工厂一次性创建,建造者分步构建复杂对象
- 观察者 vs 发布 - 订阅:观察者是同步通知,发布 - 订阅通常引入消息中间件
- 享元模式的常见误用(本题失分点):
- 享元模式是共享细粒度对象以减少内存开销,如 Integer 缓存、字符串常量池、Character 缓存
- Spring 中并没有明显的享元模式实现,容易和"单例"混淆
第二部分:考察方向与延伸递进
考察方向:
- 深度:Spring 源码中对设计模式的具体实现类
- 广度:设计模式之间的对比和适用边界
- 应用:业务开发中如何借鉴 Spring 的设计思路
延伸递进面试题:
- Spring 的三级缓存用了什么设计模式?如果不用工厂模式(ObjectFactory)会怎样?
- 解答要点:三级缓存本质是抽象工厂模式(L3 存的是 ObjectFactory,延迟决定"要不要代理")。如果不用工厂模式,只能用两级缓存,但会导致 AOP 场景下"B 持有 A 原始对象而 A 自身持有代理对象"的引用分裂问题。三级缓存的核心价值是让"是否代理"的决策延迟到运行时按需生成
- Spring 里有哪些地方用到了责任链?如果让你自定义一条拦截链怎么做?
- 解答要点:SpringMVC 的 HandlerInterceptor(preHandle/afterCompletion/postHandle)、Spring Security 的 FilterChain、Tomcat 的 Pipeline、Spring AOP 的 AdviceChain 都用责任链。自定义方式:定义接口 Handler { boolean handle(Request ctx, Handler next); },构造一个 List<Handler>,运行时依次调用 handler.handle(ctx, next),最后一个 handler 处理业务逻辑,异常向上传播
- Spring 的观察者模式如何结合事务使用?@TransactionalEventListener 的 phase 有哪些?
- 解答要点:@TransactionalEventListener 结合事务使用,支持 BEFORE_COMMIT、AFTER_COMMIT、AFTER_ROLLBACK、BEFORE_COMPLETION 四种 phase,默认是 AFTER_COMMIT。适合"事务提交后再发通知/发消息"的场景,避免事务回滚后消息已经发出去的问题
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,Spring 是设计模式的集大成者,我按创建型、结构型、行为型三大类来讲。
创建型模式:
- 单例模式:Bean 默认作用域是 singleton,容器保证每个 bean 定义只有一个实例。这里有个关键点:Spring 的"单例"是容器级单例(可多容器并存),和 GoF 的"全局唯一单例"(静态实例 + 私有构造器)不完全一样
- 工厂方法:BeanFactory.getBean() 按名称/类型获取 bean,本质是工厂方法模式
- 抽象工厂:FactoryBean 是"生产其他 bean 的工厂",Spring 在容器启动时调用 FactoryBean.getObject() 得到真正的业务 bean
- 建造者:@Configuration 类中的 @Bean 方法内部多行初始化代码,本质是建造者模式
结构型模式:
- 代理模式(Spring 最大特色):AOP 通过 JDK 动态代理(基于接口)或 CGLIB(基于继承)在运行时包装目标对象
- 装饰器模式:代理增强、HttpServletRequestWrapper 等包装类
- 适配器模式:AbstractCachingErrorHandler、HandlerMethodReturnValueHandler 系列把不同格式的返回值适配到统一响应
- 外观模式(Facade):JdbcTemplate、RestTemplate 把 JDBC/HTTP 客户端的复杂操作收敛为几个简单方法
行为型模式:
- 模板方法:JdbcTemplate.execute()、RestTemplate.exchange() 定义了"操作 - 预处理 - 后置处理"的算法骨架,子类/lambda 实现具体细节
- 观察者模式:ApplicationEvent + ApplicationListener + @EventListener 实现事件驱动,@TransactionalEventListener 更进一步结合事务
- 策略模式:PlatformTransactionManager 有多种实现(DataSourceTransactionManager / JtaTransactionManager),ResourceLoader 有多种实现(ClassLoaderResourceLoader / DefaultResourceLoader),运行时选不同实现
- 责任链模式:SpringMVC 的 HandlerInterceptor 链、Spring Security 的 FilterChain
- 中介者模式:ApplicationContext 协调 Bean 之间的通信
- 状态模式:TransactionSynchronizationManager 管理事务同步状态
几个容易搞混的对比:
- 代理 vs 装饰器:代理是控制访问(AOP、远程代理),装饰器是动态添加功能(IO 流装饰)
- 工厂 vs 建造者:工厂一次性创建,建造者分步构建复杂对象
关于享元模式的一个澄清:享元模式是共享细粒度对象以减少内存开销(如 Integer 缓存、字符串常量池),Spring 中并没有明显的享元模式实现,容易和"单例"混淆。
实际工程借鉴:我在写业务代码时会借鉴 Spring 的设计思路——比如用模板方法把"参数校验 - 业务执行 - 后置日志"的重复代码抽象成 Template;用观察者模式通过 Spring 事件解耦业务模块(订单支付完成后触发积分、通知、库存回滚);用工厂模式把复杂的 Bean 构建封装在 @Configuration 类里。