面试官最爱刁难:Spring 框架里到底用了多少经典设计模式?

原文来自于:zha-ge.cn/java/117

面试官最爱刁难:Spring 框架里到底用了多少经典设计模式?

每次面试聊到 Spring,几乎必考的一个灵魂拷问就是------

"Spring 框架用了哪些设计模式?举几个例子。"

这题表面看着像背书,其实是面试官在判断:你到底只是"用过 Spring",还是"理解了 Spring 背后的设计哲学"。

我第一次被问的时候,脑子一片空白:"单例?工厂?还有......有吗?" 面试官微微一笑:"还有十多个呢,你才说俩?"

于是我带着不甘和羞耻翻源码、啃文档,才发现:Spring 不仅是一个 IOC 框架,更是设计模式的博物馆。


1. 工厂模式(Factory Pattern):Bean 是"造"出来的

应用场景: BeanFactoryApplicationContext

Spring 的核心容器就是一个大工厂,它接管了 Bean 的创建过程。你写:

java 复制代码
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = context.getBean("userService", UserService.class);

你看不到 new,Bean 却诞生了。这就是典型的工厂模式:把对象创建的细节封装起来,对外只暴露一个统一的获取接口。

  • IOC 容器本质就是工厂
  • 工厂负责 Bean 的创建、依赖注入、生命周期管理
  • 让上层代码"面向接口编程",而不是"new 对象"

📌 面试小技巧:这题别只说"工厂模式",一定要提到 IOC 容器和 BeanFactory


2. 单例模式(Singleton Pattern):Bean 默认是唯一的

应用场景: Spring Bean 的默认作用域

我们都知道 Spring Bean 默认是单例:

java 复制代码
@Component
public class UserService {}

容器里只有一份 UserService 实例,不管注入多少次,拿到的都是同一个。

这就是典型的单例模式,它避免了重复创建对象带来的资源浪费,也保证了全局状态的一致性。

⚠️ 小坑提醒:单例 ≠ 线程安全。Bean 是单例的没错,但如果你在里面写了可变状态变量,线程安全问题还是要自己管。


3. 代理模式(Proxy Pattern):AOP 的灵魂

应用场景: Spring AOP、事务管理、拦截器链

Spring 的 AOP 本质就是一套动态代理:

  • JDK 动态代理:基于接口
  • CGLIB 代理:基于子类

比如你写了:

java 复制代码
@Transactional
public void saveUser() { ... }

Spring 会在运行时为这个 Bean 生成代理对象,方法调用前后织入事务逻辑。你以为你调的是原方法,其实你调的是代理。

这就是典型的代理模式:在不修改原始代码的情况下,增强对象的功能


4. 模板方法模式(Template Method Pattern):JDBC Template / Redis Template

应用场景: JdbcTemplateRestTemplateRedisTemplate

Spring 里一堆 "Template" 结尾的类,背后都是模板方法模式:

  • 父类封装公共流程(比如获取连接、异常处理、关闭资源)
  • 子类或回调实现具体步骤(比如执行 SQL)

例子:

java 复制代码
jdbcTemplate.query("SELECT * FROM user", rs -> {
    while (rs.next()) {
        // 处理结果
    }
});

你不用管资源释放和异常处理,模板方法帮你包好了。这是 Spring 大量"帮你做脏活累活"的根源。


5. 观察者模式(Observer Pattern):事件驱动的秘密

应用场景: Spring 事件机制(ApplicationEventPublisher

Spring 的事件机制是标准的观察者模式:

  • 事件源:ApplicationEventPublisher
  • 事件:继承 ApplicationEvent
  • 监听器:实现 ApplicationListener
java 复制代码
@Component
public class MyListener implements ApplicationListener<MyEvent> {
    public void onApplicationEvent(MyEvent event) {
        System.out.println("收到事件:" + event.getMsg());
    }
}

这种松耦合的事件驱动思想广泛用于系统解耦、领域事件发布、状态监听等场景。


6. 适配器模式(Adapter Pattern):统一接口的"翻译官"

应用场景: HandlerAdapterWebMvcConfigurer

Spring MVC 中的 HandlerAdapter 就是一个适配器:

  • 不同的 Controller(方法签名、返回类型都可能不同)
  • DispatcherServlet 无需关心具体实现
  • HandlerAdapter 把它们"翻译"为统一的处理接口

这样,框架的上层调用逻辑不变,底层的控制器实现却可以千变万化。


7. 装饰器模式(Decorator Pattern):BeanPostProcessor、BeanWrapper

应用场景: Bean 初始化前后的增强

BeanPostProcessor 是 Spring 中经典的装饰器使用场景。它允许你在 Bean 创建完成前后,动态增强 Bean 的行为

java 复制代码
public Object postProcessBeforeInitialization(Object bean, String beanName) {
    // 包装或增强 bean
    return bean;
}

AOP 其实也有装饰器的影子:你在原有 Bean 外面套了一层"外衣",增加了功能但不改原本的逻辑。


8. 策略模式(Strategy Pattern):注入不同实现类

应用场景: ApplicationContext.getBean()ConverterValidator

Spring 容器天生支持策略模式:接口多实现的时候,你可以按名字、按条件注入不同策略。

java 复制代码
@Autowired
private PaymentStrategy paymentStrategy;

只要定义多个实现类,Spring 会根据上下文或 @Qualifier 决定用哪个。

这也是为什么 Spring 项目里"扩展性"这么强的根本原因:接口 + 多策略实现。


9. 构建者模式(Builder Pattern):BeanDefinitionBuilder

应用场景: BeanDefinition 的定义与注册

Spring 的底层在创建 BeanDefinition 时就用到了构建者模式:

java 复制代码
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(UserService.class);
builder.addPropertyValue("name", "Deck");

你一步步设置属性,最后由容器统一构建出完整 Bean 定义对象。


10. 职责链模式(Chain of Responsibility):拦截器链 / BeanFactoryPostProcessor

应用场景: Spring MVC 的拦截器链、Filter 链

Spring MVC 的 HandlerInterceptor 就是责任链模式的标准实现: 每个拦截器负责自己的一段逻辑,处理完再交给下一个。

同理,Bean 的初始化过程也会被一连串 BeanPostProcessor"处理链"加工。


面试官杀手锏回答

面试被问到这题时,别傻傻只说"两三个"。推荐答法是这样的:

Spring 框架大量使用了经典设计模式,比如:

  • 工厂模式 :IOC 容器管理 Bean 创建(BeanFactoryApplicationContext
  • 单例模式:Bean 默认作用域是单例
  • 代理模式:AOP、事务增强基于动态代理
  • 模板方法模式JdbcTemplate 等封装固定流程
  • 观察者模式:事件发布与监听
  • 适配器模式HandlerAdapter 解耦 Controller 调用
  • 装饰器模式BeanPostProcessor 动态增强 Bean
  • 策略模式:多实现注入按需切换
  • 职责链模式:拦截器链、Bean 后置处理链

然后加一句收尾:"Spring 就是设计模式的实战手册,学懂这些模式能让我们更好地理解它的源码和扩展点。"


写在最后

当年我以为"设计模式"只是面试背的八股文,Spring 用起来也不需要懂这些。 现在回头看,Spring 就像是一本活着的《设计模式 GOF》:每一种模式都不是纸上谈兵,而是有血有肉地活在框架里。

所以,下次再有人问你"Spring 用了哪些设计模式",别只说"单例和工厂"了。 真正的高手,早已把设计模式变成了写代码的肌肉记忆。

相关推荐
代码充电宝2 小时前
LeetCode 算法题【简单】20. 有效的括号
java·算法·leetcode·面试·职场和发展
疯狂的程序猴2 小时前
iOS混淆实战全解析,从源码混淆到IPA文件加密,打造苹果应用反编译防护体系
后端
朱昆鹏3 小时前
如何通过sessionKey 登录 Claude
前端·javascript·人工智能
wdfk_prog3 小时前
klist 迭代器初始化:klist_iter_init_node 与 klist_iter_init
java·前端·javascript
南北是北北3 小时前
RecyclerView:RecycledViewPool(回收池)
面试
开心就好20253 小时前
iOS 26 文件管理实战,多工具组合下的 App 数据访问与系统日志调试方案
后端
乘风破浪酱524363 小时前
PO、DTO、VO的区别与应用场景详解
后端
code_Bo3 小时前
基于vxe-table进行二次封装
前端·javascript·vue.js
小时前端3 小时前
现代Web认证体系深度解析:从JWT原理到SSO架构设计
前端·面试