Spring 中用到了哪些设计模式?

#Java#面试八股

Spring 中用到了哪些设计模式?

结论先行:Spring 几乎是一本"设计模式活教材",但面试要挑有代表性的讲:工厂(BeanFactory、FactoryBean)、单例(Bean 默认作用域)、模板方法(JdbcTemplate、refresh)、策略(Resource、HandlerMapping、InstantiationStrategy)、观察者(ApplicationEvent)、代理(AOP)、适配器(HandlerAdapter)、责任链(拦截器链)、装饰器(BeanWrapper、缓存装饰)、委派(BeanDefinitionParserDelegate)。

一、模式与落点对照

模式Spring 中的体现解决的问题
工厂方法BeanFactory#getBean、FactoryBean#getObject把对象创建细节封装起来
单例默认 singleton 作用域、singletonObjects 缓存控制实例数量、复用对象
模板方法JdbcTemplate、RestTemplate、AbstractApplicationContext#refresh固定流程骨架,子类填步骤
策略Resource 实现族、HandlerMapping、PlatformTransactionManager同一接口多种算法可替换
观察者ApplicationEventPublisher + @EventListener解耦事件发布与处理
代理AOP、@Transactional、@Async无侵入增强方法
适配器HandlerAdapter、AdvisorAdapter、MessageConverter统一不同实现到同一调用方式
责任链HandlerExecutionChain、FilterChain、ClientHttpRequestInterceptor请求逐层处理
装饰器BeanWrapper、TransactionAwareCacheDecorator动态叠加职责
委派BeanDefinitionParserDelegate、DispatcherServlet 委派各组件分离解析与调度

二、模板方法:refresh 就是骨架

// 伪代码,展示 refresh 的模板结构:父类定流程,子类实现可变步骤
public abstract class AbstractApplicationContext {
    public void refresh() {
        prepareRefresh();                 // 可覆写
        ConfigurableListableBeanFactory bf = obtainFreshBeanFactory();
        prepareBeanFactory(bf);
        postProcessBeanFactory(bf);       // 钩子:子类扩展
        invokeBeanFactoryPostProcessors(bf);
        registerBeanPostProcessors(bf);
        initMessageSource();
        initApplicationEventMulticaster();
        onRefresh();                      // 钩子:Web 容器在此启动
        registerListeners();
        finishBeanFactoryInitialization(bf);
        finishRefresh();
    }
    protected void onRefresh() { }        // 空实现,留给子类
}

JdbcTemplate 也是同一套路:execute 里管连接的获取、异常转换、释放,把"设参数、取结果"留给 PreparedStatementSetter、RowMapper 回调。

三、观察者:事件解耦

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

// 2. 发布事件(事务内发布,可用 @TransactionalEventListener 控制时机)
@Service
public class OrderService {
    private final ApplicationEventPublisher publisher;
    public OrderService(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }
    public void pay(long orderId) {
        // ... 更新订单状态
        publisher.publishEvent(new OrderPaidEvent(this, orderId));
    }
}

// 3. 监听(默认同步执行,@Async 可异步)
@Component
public class CouponListener {
    @EventListener
    public void onPaid(OrderPaidEvent e) {
        // 发券、加积分,与主流程解耦
    }
}

四、策略 + 工厂:按类型取实现

public interface PayStrategy {
    String type();
    void pay(BigDecimal amount);
}

@Component
public class PayStrategyFactory {
    private final Map<String, PayStrategy> strategies = new HashMap<>();

    // 构造器注入 List,Spring 会把所有实现塞进来
    public PayStrategyFactory(List<PayStrategy> list) {
        for (PayStrategy s : list) {
            strategies.put(s.type(), s);
        }
    }

    public PayStrategy get(String type) {
        return strategies.get(type);
    }
}

五、常见追问

  • 问:Spring 的单例是严格单例模式吗? 不是。它保证"每容器每 Bean 名一个实例",不同容器、不同 id 可有多个实例,且可被反射或 @Scope("prototype") 打破。
  • 问:ApplicationEvent 和 MQ 的区别? 前者是进程内同步/异步事件,无持久化、无跨服务能力;后者跨进程、可持久化、有投递语义。
  • 问:为什么 HandlerAdapter 算适配器? 因为 Controller 有 @RequestMapping、HttpRequestHandler、Controller 接口等多种形态,适配器把它们统一成 handle 调用。
  • 问:能举一个反例吗? DispatcherServlet 本身更像"前端控制器 + 委派",不必强行套某个 GoF 模式,答清楚职责即可。

小结

答题结构:先给"工厂/单例/模板/策略/观察者/代理"六个必答,再各配一个 Spring 里的具体类名。能说出"模板方法体现在 refresh 的钩子"和"事件机制是观察者",说明真读过源码而不是背清单。

笔记加载中…