从loC 到AOP,从源码角度逐一拆解 Spring中10+个经典设计模式的实现思路与应用场景。

全景速览// 先看全局

Spring 框架大概是 Java 生态里把设计模式用得最彻底的一个框架。与其说"Spring 用了哪些设计模式",不如说它的每一个核心功能背后都有一两个模式在撑着。

先给一张全景图,后文逐一展开:

1.工厂模式(BeanFactory & FactoryBean)

这是 Spring IoC 的基石。工厂模式的核心思想是:把对象的创建过程封装起来,调用方只管"要",不管"怎么造"。

Spring 里的工厂模式分两层来理解:

① BeanFactory — 工厂的工厂

BeanFactory 是最顶层的接口,ApplicationContext 继承并扩展了它。你每次写 applicationContext.getBean("userService"),背后就是工厂在工作。

② FactoryBean — 一个特殊的工厂Bean

很多人傻傻分不清 BeanFactory 和 FactoryBean。一句话说清楚:

BeanFactory 是 Spring 容器本身(大工厂);FactoryBean 是一个特殊的 Bean,它自身可以生产另一个 Bean(小工厂)。
MyBatis 的 SqlSessionFactoryBeanFeign Client 背后就是用 FactoryBean 来创建代理对象的。

// FactoryBean 示例:自定义一个数据库连接工厂
@Component
public class MyConnectionFactoryBean implements FactoryBean<Connection> {

    @Override
    public Connection getObject() throws Exception {
        // 这里可以有复杂的创建逻辑
        return DriverManager.getConnection("jdbc:mysql://localhost/db", ...);
    }

    @Override
    public Class<?> getObjectType() { return Connection.class; }

    @Override
    public boolean isSingleton() { return false; } // 每次都创建新连接
}

// 获取时:getBean("myConnectionFactoryBean") 返回的是 Connection,不是工厂本身
// 如果你想要工厂本身,要加 & 前缀:getBean("&myConnectionFactoryBean")

2.单例模式(Spring 的注册式单例)

一提单例,大家第一反应是"加 synchronized"或者"双重检查锁"。但 Spring 的单例实现和这些都不一样,它用的是注册式单例——就是一个大 Map。

public class DefaultSingletonBeanRegistry {

    // 就是这一个 Map,存所有单例 Bean
    private final Map<String, Object> singletonObjects
        = new ConcurrentHashMap<>(256);

    public Object getSingleton(String beanName) {
        return singletonObjects.get(beanName); // 直接拿缓存
    }

    protected void addSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject); // 创建后存入
    }
}

这种方式的好处是:不像双重检查锁那样每次访问都要判断,也不受类加载顺序的约束。每个 Bean 只在第一次请求时创建,之后从 Map 里直接取。

Spring 单例 ≠ 线程安全!
Spring 保证的是"整个容器只有一个实例",但如果你的 Bean 里有成员变量且在多线程下被修改,依然会有线程安全问题。Controller / Service 里尽量不要定义有状态的成员变量


3.代理模式(AOP 的核心)

这是 Spring 里最重要、也最精彩的一个模式。Spring AOP 的@Transactional@Cacheable@Async,底层全都是代理。

Spring 根据情况选择两种代理方式:

Spring Boot 2.x 之后,默认使用 CGLIB(即使有接口也用 CGLIB),除非你用 @EnableAspectJAutoProxy(proxyTargetClass=false) 明确指定 JDK 代理。Spring Boot 3.x 同样默认 CGLIB。

AOP 代理的完整调用链

// Spring AOP 代理逻辑的简化示意
public class TransactionProxy implements InvocationHandler {

    private final Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // before: 开启事务
        transactionManager.begin();
        try {
            Object result = method.invoke(target, args); // 调用真实方法
            transactionManager.commit();
            return result;
        } catch (Exception e) {
            transactionManager.rollback(); // 异常时回滚
            throw e;
        }
    }
}


4.模板方法模式(xxxTemplate)

模板方法的核心是:父类定义算法骨架(固定流程),子类实现可变的细节步骤。Spring 里用得最普遍的就是各种 XxxTemplate 类。

// 你只需要提供 SQL 和如何处理结果,其他流程 JdbcTemplate 都帮你搞定
List<User> users = jdbcTemplate.query(
    "SELECT * FROM user WHERE age > ?",
    new Object[]{18},
    // ↓ 这是"可变部分",你告诉它怎么把 ResultSet 变成 User 对象
    (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name"))
);
// 获取连接、创建PreparedStatement、关闭资源……都不用你管

同样的模式在 Spring 里还有:RestTemplate(HTTP请求模板)、RedisTemplate(Redis操作模板)、TransactionTemplate(编程式事务模板)。套路都一样。


5.观察者模式(Spring 事件机制)

Spring 的事件发布/订阅机制是观察者模式的标准实现,在框架内部大量使用,同时也开放给开发者用于业务解耦。

// 1. 定义事件(继承 ApplicationEvent)
public class OrderPaidEvent extends ApplicationEvent {
    private final Long orderId;
    public OrderPaidEvent(Object source, Long orderId) {
        super(source);
        this.orderId = orderId;
    }
}

// 2. 发布事件(在支付成功后)
@Service
public class PayService {
    @Autowired private ApplicationEventPublisher publisher;

    public void pay(Long orderId) {
        // ... 支付逻辑 ...
        publisher.publishEvent(new OrderPaidEvent(this, orderId));
        // 发完就走,不关心谁来处理
    }
}

// 3. 监听事件(可以有多个监听器)
@Component
public class LogisticsListener {
    @EventListener
    public void onOrderPaid(OrderPaidEvent event) {
        // 自动触发:创建物流单
        logistics.createShipment(event.getOrderId());
    }
}

@Component
public class NotificationListener {
    @EventListener
    public void onOrderPaid(OrderPaidEvent event) {
        // 自动触发:发送短信通知
        sms.send("您的订单已支付成功");
    }
}

Spring 内部自己也大量使用事件,比如容器启动完成时发布 ContextRefreshedEvent,Bean 被销毁时发布 ContextClosedEvent。如果你想在项目启动后做一些初始化工作,监听 ApplicationReadyEvent 是个很优雅的方式。


6.适配器模式(HandlerAdapter  -- 处理程序适配器)

适配器的经典类比:手机充电器插头不配套,加个转换头就行了。Spring MVC 里的 HandlerAdapter 就是干这个的。

DispatcherServlet 要调用 Handler(处理请求的对象),但 Handler 的类型有很多种:

DispatcherServlet 只需要调 handlerAdapter.handle(...),不需要关心当前 Handler 是 @Controller、函数式路由、还是老式的 Controller 接口——适配器来搞定。

Spring 里同样使用适配器模式的还有:AdvisorAdapter(把各种 Advice 转成 MethodInterceptor)、MessageConverter(把不同格式的数据转换)。


7.装饰器 (包装器模式 动态增强)

装饰器和代理的区别容易混淆,简单说:代理侧重控制访问,装饰器侧重扩展功能。但在 Spring 里两者界限有点模糊。

① BeanWrapper

Spring 在操作 Bean 属性时,不是直接反射,而是把 Bean 包一层 BeanWrapper,通过它来读写属性。BeanWrapper 提供了类型转换、属性编辑等额外能力。

② HttpServletRequestWrapper

这是 Servlet 规范里的装饰器,Spring 里经常用到:

// 默认 HttpServletRequest 的 body 只能读一次(流读完了就没了)
// 用装饰器包一层,把 body 缓存起来,支持多次读
public class CachedBodyHttpServletRequest
        extends HttpServletRequestWrapper {

    private final byte[] cachedBody;

    public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        // 构造时把 body 读出来存好
        this.cachedBody = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() {
        // 每次都从缓存里重新生成流,可以读无数次
        return new CachedBodyServletInputStream(this.cachedBody);
    }
}


8.责任链模式(Filter 链 & Interceptor 链)

前一篇文章里详细讲过 Filter 和 Interceptor 的执行顺序,这两者都是责任链模式的体现。请求像穿糖葫芦一样,依次经过每个节点的处理。

Spring Security 里的 SecurityFilterChain 是责任链模式最复杂的实现,整个安全框架就是一条由十几个 Filter 组成的链:

9.策略模式及其他

策略模式 — Resource 接口

Spring 用 Resource 接口统一抽象所有资源访问,根据路径前缀自动选择策略:

// 同一个接口,不同策略实现
Resource r1 = new ClassPathResource("config.xml");     // classpath:
Resource r2 = new FileSystemResource("/etc/app.yml");  // file:
Resource r3 = new UrlResource("https://example.com/api");// http:

// ResourceLoader 根据前缀自动选择策略,调用方无需关心
Resource res = resourceLoader.getResource("classpath:config.xml");

建造者模式 — BeanDefinitionBuilder

手动向容器注册 Bean 时,用 BeanDefinitionBuilder 链式构建 BeanDefinition,是标准的 Builder 模式。

BeanDefinitionBuilder builder = BeanDefinitionBuilder
    .genericBeanDefinition(UserService.class)
    .setScope("singleton")
    .addPropertyValue("maxRetry", 3)
    .setLazyInit(true);

registry.registerBeanDefinition("userService", builder.getBeanDefinition());

前端控制器模式 — DispatcherServlet

这不是 GoF 23 种之一,但 Spring MVC 的 DispatcherServlet 是前端控制器(Front Controller)模式的教科书实现:所有请求统一入口,再分发给不同 Handler。

总结对照表// 快速查阅

设计模式 类型 Spring 中的体现 核心价值
工厂模式 创建型 BeanFactoryFactoryBeanApplicationContext
BeanFactory 、 FactoryBean 、 ApplicationContext
解耦对象的创建与使用
单例模式 创建型 Bean 默认 singleton 作用域,ConcurrentHashMap 注册式实现 节约资源,全局唯一状态
代理模式 结构型 AOP、@Transactional@Cacheable,JDK动态代理 + CGLIB 透明增强,不改原始代码
模板方法 行为型 JdbcTemplateRestTemplateRedisTemplate
JdbcTemplate 、 RestTemplate 、 RedisTemplate
固定流程 + 可变细节,消除重复代码
观察者模式 行为型 ApplicationEvent@EventListener
ApplicationEvent 、 @EventListener
模块解耦,事件驱动
适配器模式 结构型 HandlerAdapterAdvisorAdapterMessageConverter
HandlerAdapter 、 AdvisorAdapter 、 MessageConverter
接口不兼容时的桥接
装饰器模式 结构型 BeanWrapperHttpServletRequestWrapper
BeanWrapper 、 HttpServletRequestWrapper
不改原类动态扩展功能
责任链模式 行为型 FilterChainInterceptorChainSecurityFilterChain
FilterChain 、 InterceptorChain 、 SecurityFilterChain
请求依次经过多个处理节点
策略模式 行为型 Resource 接口族、InstantiationStrategyTransactionManager 运行时动态切换算法
建造者模式 创建型 BeanDefinitionBuilderUriComponentsBuilder
BeanDefinitionBuilder 、 UriComponentsBuilder
链式构建复杂对象

📌 面试答题思路

被问到"Spring 用了哪些设计模式",不要只列个清单,最好按这个思路组织:

IoC 容器:工厂模式(BeanFactory)+ 单例模式(注册式单例)

AOP:代理模式(JDK动态代理 + CGLIB)

各种 Template:模板方法模式

事件机制:观察者模式

Spring MVC:适配器模式(HandlerAdapter)+ 前端控制器模式(DispatcherServlet)

其他:装饰器(RequestWrapper)、责任链(FilterChain)、策略(Resource)、建造者(BeanDefinitionBuilder)
其他 :装饰器(RequestWrapper)、责任链(FilterChain)、策略(Resource)、建造者(BeanDefinitionBuilder)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐