Spring 设计模式总结

候选人小唐在面试腾讯 P7 时,面试官问道:

"Spring 源码里用到了哪些设计模式?"

小唐说:"用到了工厂模式、代理模式...还有...单例模式?"

面试官追问:"每种模式在 Spring 中是怎么体现的?"

小唐开始支支吾吾。

【面试官心理】 这道题我用来测试候选人对 Spring 框架的全面理解程度。Spring 是 Java 工程师必须掌握的框架,能说出源码中设计模式的人,说明对 Spring 有深入研究。设计模式是 Java 面试的永恒话题,结合 Spring 源码来回答会更有说服力。


一、核心问题 🔴

1.1 问题拆解

第一层:模式识别

  • "Spring 用到了哪些设计模式?"
  • "每种模式分别在哪里体现?"

第二层:深度分析

  • "Spring 是怎么实现单例模式的?"
  • "Factory 模式在 Spring 中有几种体现?"
  • "模板方法模式是怎么用的?"

第三层:实战价值

  • "这些设计模式对我们写代码有什么指导意义?"
  • "你在项目中用过这些模式吗?"

1.2 标准回答

P5 回答:六大核心模式

Spring 源码中使用了大量设计模式,最核心的有六种:

设计模式在 Spring 中的体现核心类/接口
单例模式Spring Bean 默认单例DefaultSingletonBeanRegistry
工厂模式BeanFactory 系列BeanFactoryFactoryBean
代理模式AOP 事务、AOP 切面JdkDynamicAopProxyCglibAopProxy
模板方法模式JdbcTemplate、HibernateTemplateJdbcTemplateRestTemplate
观察者模式事件监听机制ApplicationEventApplicationListener
策略模式事务传播行为、资源获取策略TransactionManager

1.3 追问升级

追问 1:单例模式

Spring 的单例模式不是传统意义上的单例,而是"容器级单例":

// Spring 的单例注册表
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry {
    // 缓存单例 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) {
        synchronized (this.singletonObjects) {
            singletonObjects.put(beanName, singletonObject);
        }
    }
}

和传统单例的区别:

对比传统单例Spring 单例
数量一个 JVM 一个一个容器一个
线程安全需要自己保证Spring 保证
延迟加载饿汉/懒汉可配置
销毁JVM 退出时容器关闭时
// Spring 单例模式的优势:
// 1. 线程安全由 Spring 容器保证
// 2. 可以懒加载(prototype 单例除外)
// 3. 容易测试
// 4. 可以通过配置切换

// 可以通过 @Scope 切换作用域
@Service
@Scope("prototype") // 每个请求创建新实例
public class MyService { }

追问 2:工厂模式

Spring 的工厂模式有三种形态:

// 形态1:简单工厂 - BeanFactory
// BeanFactory 是 Spring 容器的根接口
// 根据 name 获取 Bean,屏蔽了创建细节

// 形态2:工厂方法 - FactoryBean
// 对于复杂的 Bean 创建逻辑,实现 FactoryBean 接口
public class MyFactoryBean implements FactoryBean<MyObject> {
    @Override
    public MyObject getObject() {
        // 复杂的创建逻辑
        return new MyObject();
    }
}

// 形态3:抽象工厂 - BeanFactory 层次结构
// BeanFactory 有多个子接口和实现类
ConfigurableListableBeanFactory
  └─ DefaultListableBeanFactory
      └─ XmlBeanFactory(已废弃)

追问 3:代理模式

代理模式在 Spring 中无处不在:

// 代理模式在 Spring 中的三大应用场景:

// 1. AOP(面向切面编程)
// 核心类:JdkDynamicAopProxy、CglibAopProxy
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        // 获取方法的拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // 执行拦截器链
        return new CglibMethodInvocation().proceed();
    }
}

// 2. Spring 事务
// TransactionInterceptor 代理了业务方法
// 在方法前后添加事务开启/提交/回滚逻辑

// 3. Spring Data JPA
// JpaRepositoryFactory 创建代理
// 为接口方法提供实现

追问 4:模板方法模式

// JdbcTemplate 是模板方法模式的经典实现
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
    // 模板方法
    public <T> T execute(ConnectionCallback<T> action) {
        Connection con = null;
        try {
            con = getDataSource().getConnection();
            return action.doInConnection(con); // 调用回调
        } catch (SQLException e) {
            throw convertJdbcAccessException(e);
        } finally {
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
    }

    // 具体方法 - 使用模板方法
    public List<Map<String, Object>> queryForList(String sql) {
        return execute(connection -> {
            PreparedStatement ps = connection.prepareStatement(sql);
            return executeQuery(ps);
        });
    }
}
模板方法模式结构:

JdbcTemplate.execute()  // 模板方法,定义骨架
  ├─ 获取连接
  ├─ try {
  │     doInConnection()  // 抽象步骤,由子类实现
  │   } finally {
  │     释放连接
  │   }

子类实现:
  └─ query()、update() 等 // 具体实现

追问 5:观察者模式

// Spring 事件机制是观察者模式的实现

// 1. 事件(Subject)
public abstract class ApplicationEvent extends EventObject {
    private final long timestamp;
    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }
}

// 2. 监听器(Observer)
public interface ApplicationListener<E extends ApplicationEvent> {
    void onApplicationEvent(E event);
}

// 3. 事件广播器(管理 Observer)
public interface ApplicationEventMulticaster {
    void addApplicationListener(ApplicationListener<?> listener);
    void removeApplicationListener(ApplicationListener<?> listener);
    void multicastEvent(ApplicationEvent event);
}

追问 6:策略模式

// 策略模式在 Spring 事务中的应用

// 定义策略接口
public interface TransactionManager {
    TransactionStatus getTransaction(TransactionDefinition definition);
    void commit(TransactionStatus status);
    void rollback(TransactionStatus status);
}

// 具体策略实现
public class DataSourceTransactionManager implements TransactionManager {
    @Override
    public TransactionStatus getTransaction(TransactionDefinition definition) {
        // 数据源事务策略
    }
}

public class JpaTransactionManager implements TransactionManager {
    @Override
    public TransactionStatus getTransaction(TransactionDefinition definition) {
        // JPA 事务策略
    }
}

// 使用
@Bean
public TransactionManager transactionManager() {
    return new DataSourceTransactionManager(dataSource);
}

二、延伸问题 🟡

2.1 其他设计模式

适配器模式

// Spring MVC 中的 HandlerAdapter
public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler);
}

// Spring 根据不同的 Controller 类型选择不同的 Adapter
// RequestMappingHandlerAdapter、SimpleControllerHandlerAdapter 等

装饰器模式

// HttpServletRequestWrapper 装饰了 HttpServletRequest
public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
    private byte[] content;
    // 可以在读取 body 之前/之后做一些处理
}

// BufferedReader 装饰了 Reader
// BeanWrapper 装饰了 Bean

责任链模式

// FilterChain 是责任链模式
public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response);
}

// AOP 拦截器链
public class ReflectiveMethodInvocation implements MethodInvocation {
    List<Object> interceptorsAndDynamicMethodMatchers;

    public Object proceed() {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinPoint();
        }
        // 依次调用下一个拦截器
        return this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)
            .invoke(this);
    }
}

建造者模式

// MockMvc 的构建
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context)
    .apply(springSecurity())
    .build();

// UriComponentsBuilder
UriComponents uri = UriComponentsBuilder.fromUriString("http://example.com")
    .path("/api")
    .queryParam("id", 1)
    .build()
    .expand("name")
    .encode();

三、设计模式的启示

3.1 从 Spring 学到的设计原则

原则Spring 体现
开闭原则扩展通过 FactoryBean、BeanPostProcessor
依赖倒置面向接口编程,BeanFactory 接口定义
里氏替换所有 TransactionManager 实现可互换
接口隔离分离不同功能的接口
单一职责每个类职责明确
迪米特法则BeanFactory 隐藏创建细节

3.2 在项目中的应用

// 1. 使用模板方法模式封装重复逻辑
public abstract class BaseService<T> {
    @Autowired
    protected BaseRepository<T> repository;

    public void save(T entity) {
        beforeSave(entity);
        repository.save(entity);
        afterSave(entity);
    }

    protected void beforeSave(T entity) { } // 钩子方法
    protected void afterSave(T entity) { }
}

// 2. 使用策略模式处理多种支付方式
@Service
public class PaymentStrategyFactory {
    @Autowired
    private Map<String, PaymentStrategy> strategies;

    public PaymentStrategy getStrategy(String type) {
        PaymentStrategy strategy = strategies.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的支付方式: " + type);
        }
        return strategy;
    }
}

public interface PaymentStrategy {
    void pay(Order order);
    void refund(Order order);
}

// 3. 使用观察者模式解耦业务逻辑
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void createOrder() {
        orderRepository.save(order);
        publisher.publishEvent(new OrderCreatedEvent(order));
    }
}

四、面试总结

Spring 设计模式是展示你对 Spring 理解深度的好机会。

P5 候选人能说出 2-3 种设计模式。 P6 候选人能说出 5-6 种,并能给出 Spring 中的具体体现。 P7 候选人能结合源码分析每种模式的实现,并能在项目中应用这些模式。

记住,面试中不是背设计模式的名字,而是展示你对 Spring 框架设计思想的理解。