跳到主要内容

Spring 中的设计模式

问题

Spring 框架中用到了哪些设计模式?请结合具体场景说明。

答案

Spring 框架大量运用设计模式,是设计模式在 Java 生态中的经典实践。

1. 工厂模式 — BeanFactory / FactoryBean

BeanFactory 是 Spring IoC 容器的核心接口,本质就是一个工厂:

工厂模式
// BeanFactory:根据名称或类型获取 Bean 实例
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = ctx.getBean(UserService.class);

FactoryBean 是一种特殊的 Bean,用于创建复杂对象:

FactoryBean.java
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory> {

@Override
public SqlSessionFactory getObject() throws Exception {
// 复杂的创建逻辑
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
return builder.build(configuration);
}

@Override
public Class<?> getObjectType() {
return SqlSessionFactory.class;
}
}
BeanFactory vs FactoryBean
  • BeanFactory:IoC 容器接口,管理所有 Bean
  • FactoryBean:一种特殊的 Bean,用于封装复杂对象的创建逻辑(MyBatis、Dubbo 都大量使用)

2. 单例模式 — DefaultSingletonBeanRegistry

Spring Bean 默认是单例作用域。DefaultSingletonBeanRegistry 维护了三级缓存来管理单例 Bean:

单例注册表(简化)
public class DefaultSingletonBeanRegistry {
// 一级缓存:完整的单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
// 二级缓存:提前曝光的半成品(解决循环依赖)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
// 三级缓存:对象工厂(生成代理对象)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

public Object getSingleton(String beanName) {
// 先查一级 → 再查二级 → 最后查三级
Object bean = singletonObjects.get(beanName);
if (bean == null) {
bean = earlySingletonObjects.get(beanName);
if (bean == null) {
ObjectFactory<?> factory = singletonFactories.get(beanName);
if (factory != null) {
bean = factory.getObject();
earlySingletonObjects.put(beanName, bean);
singletonFactories.remove(beanName);
}
}
}
return bean;
}
}
提示

注意这里不是 GoF 的经典单例模式(私有构造函数 + 静态方法),而是通过注册表方式实现的容器级别单例。

3. 代理模式 — AOP

Spring AOP 是代理模式的典型应用,在运行时为目标对象创建代理:

代理模式
// JDK 动态代理(目标实现了接口)
public class JdkDynamicAopProxy implements InvocationHandler {
private final Object target;

@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// 前置通知
Object result = method.invoke(target, args);
// 后置通知
return result;
}
}

// CGLIB 代理(目标没有实现接口)
// 通过生成目标类的子类来实现代理
代理方式条件原理
JDK 动态代理目标实现了接口实现相同接口
CGLIB 代理目标未实现接口生成子类(不能代理 final 类/方法)

4. 适配器模式 — HandlerAdapter

Spring MVC 中不同类型的 Handler(Controller)需要不同的调用方式,HandlerAdapter 统一了调用接口:

适配器模式
public interface HandlerAdapter {
// 判断是否支持该 Handler
boolean supports(Object handler);
// 统一的调用接口
ModelAndView handle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception;
}

// 适配 @RequestMapping 注解的 Controller
public class RequestMappingHandlerAdapter implements HandlerAdapter { /* ... */ }
// 适配实现 Controller 接口的 Handler
public class SimpleControllerHandlerAdapter implements HandlerAdapter { /* ... */ }

5. 模板方法模式 — JdbcTemplate

定义算法骨架,将具体步骤延迟到子类或回调:

模板方法模式
// JdbcTemplate 封装了获取连接、执行 SQL、处理异常、释放资源的流程
// 用户只需关注 SQL 和结果映射
jdbcTemplate.query("SELECT * FROM user WHERE id = ?",
(rs, rowNum) -> {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
return user;
},
userId
);

类似的还有 RestTemplateRedisTemplateTransactionTemplate

6. 观察者模式 — 事件机制

Spring 的事件驱动模型基于观察者模式:

Spring 事件
// 1. 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}
}

// 2. 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;

public void createOrder(Order order) {
// 业务逻辑...
publisher.publishEvent(new OrderCreatedEvent(this, order));
}
}

// 3. 监听事件
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 发送通知、更新库存...
}
}

7. 策略模式 — Resource / InstantiationStrategy

策略模式
// Resource 接口的不同实现策略
Resource resource1 = new ClassPathResource("config.xml"); // 类路径
Resource resource2 = new FileSystemResource("/opt/config"); // 文件系统
Resource resource3 = new UrlResource("https://example.com");// URL

// InstantiationStrategy:Bean 实例化策略
// - SimpleInstantiationStrategy:反射
// - CglibSubclassingInstantiationStrategy:CGLIB(方法注入时使用)

设计模式汇总

设计模式Spring 中的应用
工厂模式BeanFactory、FactoryBean
单例模式DefaultSingletonBeanRegistry(三级缓存)
代理模式AOP(JDK 动态代理 / CGLIB)
适配器模式HandlerAdapter、AdvisorAdapter
模板方法JdbcTemplate、RestTemplate、RedisTemplate
观察者模式ApplicationEvent、@EventListener
策略模式Resource、InstantiationStrategy
建造者模式BeanDefinitionBuilder、UriComponentsBuilder
装饰器模式BeanWrapper、HttpServletRequestWrapper
责任链模式Filter 链、Interceptor 链
组合模式CompositeCacheManager

常见面试问题

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

答案

至少包括:工厂模式(BeanFactory)、单例模式(Bean 默认作用域)、代理模式(AOP)、模板方法(JdbcTemplate)、观察者模式(事件机制)、适配器模式(HandlerAdapter)、策略模式(Resource)、责任链模式(Filter/Interceptor 链)。

Q2: BeanFactory 和 FactoryBean 的区别?

答案

  • BeanFactory:Spring IoC 容器的顶层接口,定义了 getBean() 等方法
  • FactoryBean:一种特殊的 Bean(接口),实现它的类会由 Spring 自动调用 getObject() 来创建真正的 Bean。通过 &beanName 可获取 FactoryBean 本身

Q3: 为什么 Spring 选择三级缓存实现单例,而不是经典的双重检查锁?

答案

因为 Spring Bean 的创建不是简单的 new 操作,涉及属性注入、代理增强等复杂步骤。三级缓存(一级存完整对象、二级存半成品、三级存 ObjectFactory)可以解决循环依赖问题——在 Bean 还未完全创建时就能提前暴露引用。经典双重检查锁只能保证线程安全,无法解决循环依赖。

Q4: Spring AOP 默认用 JDK 代理还是 CGLIB?

答案

  • Spring Framework:目标实现了接口用 JDK 代理,否则用 CGLIB
  • Spring Boot 2.x+:默认统一使用 CGLIB(spring.aop.proxy-target-class=true

可通过 @EnableAspectJAutoProxy(proxyTargetClass = false) 改为优先使用 JDK 代理。

相关链接