策略模式在spring哪里用到了?

策略模式是 Spring 框架中应用得最为广泛的设计模式之一,几乎贯穿了整个框架的设计。它的核心思想是定义一系列的算法,将它们一个个封装起来,并且使它们可以相互替换,从而让算法的变化独立于使用算法的客户端。

在 Spring 中,这通常体现为:

  1. 定义一个策略接口
  2. 提供多个不同的接口实现类(即各种策略)。
  3. 在运行时,根据条件(如配置、上下文环境等)由 Spring 容器动态地决定使用哪个具体的实现(通常通过依赖注入实现)。

1. Resource 接口与资源加载

这是最直观的例子之一。

  • 策略接口org.springframework.core.io.Resource
  • 具体策略
    • UrlResource:用于加载网络资源。
    • ClassPathResource:用于加载类路径下的资源。
    • FileSystemResource:用于加载文件系统资源。
    • ServletContextResource:用于加载 Web 应用上下文中的资源。
  • 策略选择者org.springframework.core.io.ResourceLoader(其默认实现是 DefaultResourceLoader

如何使用

你不需要直接 new 一个具体的 Resource 实现,而是通过 ResourceLoader 来获取。ResourceLoader 会根据你传入的资源字符串的前缀(如 classpath:file:http:)自动选择正确的策略。

java 复制代码
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:config.xml");
// 此时 resource 的实际类型是 ClassPathResource

Resource httpResource = resourceLoader.getResource("https://example.com/data.json");
// 此时 httpResource 的实际类型是 UrlResource

2. Bean 实例化策略

Spring 需要根据类定义创建 Bean 的实例,而创建实例的方式有多种。

  • 策略接口org.springframework.beans.factory.support.InstantiationStrategy
  • 具体策略
    • SimpleInstantiationStrategy:使用普通的反射调用构造函数来实例化对象。
    • CglibSubclassingInstantiationStrategy:使用 CGLIB 动态生成子类的方式来进行实例化(例如,需要方法注入或代理没有默认构造函数的类时)。它是 SimpleInstantiationStrategy 的子类。
  • 策略选择者AbstractAutowireCapableBeanFactorycreateBeanInstance() 方法中会根据 Bean 的定义(是否需要方法注入、是否有 lookup-method 等)来决定使用哪种实例化策略。

3. HandlerMapping

在 Spring MVC 中,需要根据 HTTP 请求找到对应的处理控制器(Controller)。

  • 策略接口org.springframework.web.servlet.HandlerMapping
  • 具体策略
    • RequestMappingHandlerMapping:基于 @RequestMapping 注解将请求映射到方法(目前最主流的策略)。
    • BeanNameUrlHandlerMapping:根据 Bean 的名字(以 "/" 开头)来映射 URL。
    • SimpleUrlHandlerMapping:通过配置文件手动配置 URL 和 Controller 的映射关系。
  • 策略选择者DispatcherServlet 会持有多个 HandlerMapping 组件,形成一个责任链。在处理请求时,它会按顺序遍历这些策略,直到某一个策略能返回一个可用的 Handler。

4. HandlerAdapter

同样在 Spring MVC 中,DispatcherServlet 拿到 Handler 之后,需要调用这个 Handler 的真正处理方法。但由于 Handler 的形式多种多样(如普通的 @Controller、传统的 Controller 接口实现、HttpRequestHandler 等),调用方式也不同。

  • 策略接口org.springframework.web.servlet.HandlerAdapter
  • 具体策略
    • RequestMappingHandlerAdapter:用于适配和执行基于 @RequestMapping 注解的方法。
    • SimpleControllerHandlerAdapter:用于适配实现了 Controller 接口的处理器。
    • HttpRequestHandlerAdapter:用于适配实现了 HttpRequestHandler 接口的处理器。
  • 策略选择者DispatcherServlet 会遍历所有 HandlerAdapter,询问其 supports() 方法是否支持当前找到的 Handler。找到第一个支持的 Adapter 后,就使用它来执行目标方法。
java 复制代码
// 在 DispatcherServlet 中的核心逻辑
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    for (HandlerAdapter adapter : this.handlerAdapters) {
        if (adapter.supports(handler)) { // 询问每个策略:你能处理这个Handler吗?
            return adapter; // 找到能处理的策略
        }
    }
    ...
}

5. PlatformTransactionManager(平台事务管理器)

这是一个业务层面非常经典的策略模式应用。

  • 策略接口org.springframework.transaction.PlatformTransactionManager
  • 具体策略
    • DataSourceTransactionManager:用于管理 JDBC 本地事务。
    • JpaTransactionManager:用于管理 JPA 事务。
    • JtaTransactionManager:用于管理分布式 JTA 事务。
    • HibernateTransactionManager:用于管理 Hibernate 事务。
  • 策略选择者 :应用程序开发者。我们通过在 Spring 配置文件中配置具体的实现(策略),然后在代码中通过 @Transactional 注解使用。Spring 会根据配置注入正确的策略来管理事务。
xml 复制代码
<!-- 配置具体策略 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
java 复制代码
// 使用统一接口,无需关心具体策略
@Transactional
public void performBusinessLogic() {
    // ...
}

相关推荐
我命由我123451 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
考虑考虑2 小时前
Sentinel安装
java·后端·微服务
凤凰院凶涛QAQ3 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
掘金_答案4 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
猿与禅5 小时前
CosId 分布式 ID 生成器完全教程:从架构原理到生产落地
java·shardingsphere·雪花算法·分布式id·高性能·cosid·号段模式
MindUp5 小时前
企业网盘权限模型解析:多层级访问控制与审计能力选型指南
java·linux·运维
NG4775 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程
程序员天天困5 小时前
优雅记录操作日志:从注解到 SpEL 的全链路实践与开源方案对比
java·后端
战血石LoveYY6 小时前
Integer类型超限,导致数据异常
java·算法
乐观的Terry7 小时前
1、为什么要自己造发布系统
java·spring boot·后端·spring cloud·架构