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,用于创建复杂对象:
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: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
);
类似的还有 RestTemplate、RedisTemplate、TransactionTemplate。
6. 观察者模式 — 事件机制
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 代理。
相关链接
- IoC 容器与依赖注入 - BeanFactory 详解
- AOP 面向切面编程 - 代理模式的具体应用
- 循环依赖 - 三级缓存如何解决循环依赖
- Spring MVC - 适配器模式、责任链模式