2023年Stack Overflow调研显示,78%的Spring开发者每天打交道的注解背后,藏着他们从未意识到的设计模式。这不是框架的阴谋,是文档没告诉你怎么"透视"代码。

一个典型场景:你在Service层加@Autowired,觉得只是"自动注入"。但Spring容器里发生的是工厂模式(Factory Pattern)的完整链路——BeanDefinition解析、依赖图谱构建、代理对象生成。你写的每一行"声明式"代码,都是命令式逻辑的压缩包。

单例模式:Spring的默认人格

单例模式:Spring的默认人格

Spring容器中的Bean默认就是单例。这不是配置项,是架构假设。

但这里有个陷阱:很多人把"单例"和"Spring单例"混为一谈。

GoF的单例模式保证一个类只有一个实例;Spring的单例保证一个Bean定义在一个容器上下文里只有一个实例。后者作用域更小,却更实用——它允许你在不同上下文(比如父子容器)里存在"同名不同命"的Bean。这种设计让模块化部署成为可能,代价是你得理解@Scope的隐性边界。

代理模式:AOP的隐身衣

代理模式:AOP的隐身衣

@Transactional可能是Java世界最被误用的注解。开发者以为它"开启事务",实际上它开启的是动态代理。

Spring用JDK动态代理(接口基于)或CGLIB(类基于)包裹你的Bean。方法调用先经过代理层,事务管理器判断是否需要切入。同一个类内部方法互相调用时事务失效,根源就在这里——this指针绕过了代理层。

这个细节每年在GitHub上产生超过2000个"事务不生效"的issue,解法却简单得离谱:注入自己,或者改用AspectJ编译期织入。

模板方法模式:JdbcTemplate的暴力美学

模板方法模式:JdbcTemplate的暴力美学

写过原生JDBC的人都知道资源关闭的噩梦。JdbcTemplate把这套流程焊死在骨架里:获取连接、执行回调、处理异常、释放资源,一气呵成。

你只需实现RowMapperPreparedStatementSetter,把变化的部分插进固定流程。这种"好莱坞原则"(别调用我们,我们会调用你)在Spring Data里随处可见——JpaRepository的方法命名解析、RedisTemplate的序列化钩子,都是同一套思维的不同皮肤。

观察者模式:事件机制的暗线

观察者模式:事件机制的暗线

Spring 4.2之后,@EventListener让异步解耦变得廉价。但多数人没意识到:这是观察者模式(Observer Pattern)的工程化实现。

应用上下文本身就是事件广播器,ApplicationEventMulticaster负责分发。ContextRefreshedEventContextClosedEvent这些内置事件,构成了Spring生命周期的隐形骨架。自定义事件只需继承ApplicationEvent,但真正的技巧在于设计事件粒度——太细导致广播风暴,太粗失去解耦意义。

Netflix的Spring Cloud套件里,配置刷新事件EnvironmentChangeEvent能触发上百个微服务实例的热更新,靠的就是这套机制的横向扩展。

Spring 6.1引入的AOT(提前编译)正在改写部分模式的实现方式。当原生镜像成为默认选项,动态代理会让位给静态织入,依赖注入的反射操作会被编译期生成代码取代。那些藏在注解里的设计模式,正在以另一种形态重生。

你最近一次调试Spring源码,是在解决什么问题?