适配器模式

适配器模式

定义

适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。它通过一个中间件(适配器)将一个类的接口转换成客户期望的另一个接口,使原本不能一起工作的类能够协同工作。

简单的demo

假设我们有一个老的接口 OldPayment,但是现在系统统一要求用一个新的接口 NewPayment。
为了兼容老系统,又不改老代码,就用适配器来搞定!

1. 定义老接口 OldPayment

public interface OldPayment {
    void oldPay(double amount);
}

2. 老接口的实现(模拟老系统)

public class OldPaymentImpl implements OldPayment {
    @Override
    public void oldPay(double amount) {
        System.out.println("老支付系统,支付金额:" + amount + " 元");
    }
}

3. 定义新接口 NewPayment

public interface NewPayment {
    void pay(double amount);
}

4. 适配器 PaymentAdapter

public class PaymentAdapter implements NewPayment {

    private final OldPayment oldPayment;

    public PaymentAdapter(OldPayment oldPayment) {
        this.oldPayment = oldPayment;
    }

    @Override
    public void pay(double amount) {
        // 适配:新接口调用老接口
        oldPayment.oldPay(amount);
    }
}

5. 测试

import org.example.design_pattern.Adapter.NewPayment;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class DesignPatternApplicationTests {


    @Autowired
    private NewPayment newPayment;


    @Test
    public void testAdapter() {
        newPayment.pay(100);
    }


}

6. 输出结果

【适配器】开始调用老支付系统...
老支付系统,支付金额:100.0 元

Spring中的示例

Spring MVC 的 HandlerAdapter 体系

1. 先来理解一下场景

在 Spring MVC 中,一个请求进来,Controller 方法可能有各种不同写法,比如:

  • 普通的 @Controller + 方法

  • HttpRequestHandler 接口实现类

  • SimpleControllerHandlerAdapter 支持的简单控制器

每种类型处理请求的方法不一样!

问题来了:DispatcherServlet 怎么统一调用这些不同风格的 Controller?
答案就是:用适配器模式!

核心逻辑:

  • 有很多种 Controller(对象不同、方法不同)

  • DispatcherServlet 只管调用 统一的 HandlerAdapter

  • 每个 HandlerAdapter 负责适配一种 Controller

2. Spring MVC 中的结构图

DispatcherServlet
    ↓(根据 handler 找到合适的 handlerAdapter)
HandlerAdapter(接口)
    ↓(不同适配器实现)
RequestMappingHandlerAdapter  (适配 @RequestMapping 的 Controller)
HttpRequestHandlerAdapter     (适配实现 HttpRequestHandler 接口的 Controller)
SimpleControllerHandlerAdapter(适配实现 Controller 接口的 Controller)

3. 源码

HandlerAdapter 接口定义:

public interface HandlerAdapter {

    boolean supports(Object handler);

    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);
}

supports(handler) 判断是否支持当前的 Controller;

handle(request, response, handler) 真正去调用 Controller。

4. DispatcherServlet 的执行流程(适配器用法核心)

DispatcherServlet 处理请求大致流程:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerExecutionChain handler = getHandler(request); // 找到处理器
    HandlerAdapter ha = getHandlerAdapter(handler.getHandler()); // 找适配器

    ModelAndView mv = ha.handle(request, response, handler.getHandler()); // 用适配器处理
}

注意:

  • getHandlerAdapter() 会遍历容器里所有 HandlerAdapter;

  • 调用 supports(handler),找到能处理当前 handler 的适配器;

  • 最终调用 handle() 执行 Controller。

也就是说:

DispatcherServlet 不关心你的 Controller 是什么鬼,只要有 HandlerAdapter 能处理就行。

AOP(面向切面编程)

1. 背景:Spring AOP 通知(Advice)有很多种

在 Spring AOP 中,一个切面(Aspect)可以定义很多种通知(Advice):

  • 前置通知(BeforeAdvice)

  • 后置通知(AfterReturningAdvice)

  • 异常通知(ThrowsAdvice)

  • 环绕通知(MethodInterceptor)

每种通知,接口和执行逻辑都不一样!

2. 问题

统一管理这些五花八门的 Advice,怎么做到?

  • 各种 Advice 接口不同、方法不同;

  • 但是 AOP 框架希望 统一拦截器链执行。

答案就是:适配器模式!

用适配器把各种不同的 Advice,统一适配成 MethodInterceptor(方法拦截器),然后 Spring AOP 内部就可以只认一种类型执行!

3. 具体结构

角色 类名 说明
Target 目标接口 MethodInterceptor 统一的执行接口(拦截方法调用)
Adaptee 被适配对象 BeforeAdvice、AfterReturningAdvice、ThrowsAdvice 等 不同种类的通知接口
Adapter 适配器 AdvisorAdapter 把各种 Advice 适配成 MethodInterceptor

4. 源码

AdvisorAdapter(适配器接口)

public interface AdvisorAdapter {

    boolean supportsAdvice(Advice advice);

    MethodInterceptor getInterceptor(Advisor advisor);
}
  • supportsAdvice(Advice advice):判断是否能适配这种通知类型;
  • getInterceptor(Advisor advisor):把通知适配成 MethodInterceptor。

5. Spring AOP 内置的适配器实现

Spring 自带了几个常用的 AdvisorAdapter:

适配器 支持的通知类型
BeforeAdviceAdapter 支持 BeforeAdvice
AfterReturningAdviceAdapter 支持 AfterReturningAdvice
ThrowsAdviceAdapter 支持 ThrowsAdvice

它们都实现了 AdvisorAdapter 接口。

6. 运行时流程

  1. AOP 解析配置(比如 @Aspect注解);

  2. 拿到各种通知(Advice),比如 BeforeAdvice;

  3. 遍历系统里的所有 AdvisorAdapter;

  4. 用 supportsAdvice() 判断,找到能支持的适配器;

  5. 调用 getInterceptor() 把 Advice 转成 MethodInterceptor;

  6. 把所有 MethodInterceptor 按顺序组成 拦截器链;

  7. 执行链路逻辑。

个人思考

适配器模式(Adapter)和策略模式(Strategy)的区别

核心区别

模式 核心目的
适配器模式(Adapter) 解决接口不兼容的问题,让原本不能直接用的东西可以用。
策略模式(Strategy) 解决算法或行为的切换问题,根据不同情况选择不同的实现。

Spring AOP 中,适配器模式 和 责任链模式

项目 适配器模式(Adapter) 责任链模式(Chain of Responsibility)
主要解决什么问题? 接口不兼容,统一适配成统一标准 处理请求链式传递,谁能处理谁处理
作用时间 静态建链阶段(适配成统一拦截器) 运行时执行阶段(链式调用拦截器)
关键词 适配、转换 链式处理、传递责任
Spring AOP 中体现 AdvisorAdapter 适配各种 Advice 成 MethodInterceptor 一堆 MethodInterceptor 组成责任链,逐个调用

1. AOP里的适配器模式:统一接口(MethodInterceptor)

在建拦截器链之前,把各种各样的通知(Advice)适配成 MethodInterceptor。

比如:

  • BeforeAdvice → BeforeAdviceInterceptor(MethodInterceptor)

  • AfterReturningAdvice → AfterReturningAdviceInterceptor(MethodInterceptor)

  • ThrowsAdvice → ThrowsAdviceInterceptor(MethodInterceptor)

目的是统一接口格式,让后续执行链可以统一处理

2. AOP里的责任链模式:执行拦截链

在执行环节,MethodInterceptor链式调用,逐个处理方法调用。

比如:

  • 第一个拦截器执行 invoke,决定是自己处理,还是继续 invocation.proceed()

  • 第二个拦截器执行 invoke

  • 第三个拦截器执行 invoke

  • 最后真正调用目标方法

目的是链式传递控制权,每个拦截器可以控制是否继续传递。

这就是典型的责任链模式!

3. 总结

AOP中,适配器模式解决的是 “接口统一” 问题,责任链模式解决的是 “执行流程链式传递” 问题。

扩展

为什么SpringAOP中只有内置 3个 AdvisorAdapter

Spring 中只有内置了 3个 AdvisorAdapter:

  • BeforeAdviceAdapter

  • AfterReturningAdviceAdapter

  • ThrowsAdviceAdapter

而没有 @After、@Around 对应的 AdvisorAdapter,原因是:

因为 @After 和 @Around 对应的 Advice 类型,本身就已经是 MethodInterceptor 类型了,不需要再适配了!

注解 底层生成的 Advice 类型 是否需要适配器
@Before MethodBeforeAdvice 需要 BeforeAdviceAdapter
@AfterReturning AfterReturningAdvice 需要 AfterReturningAdviceAdapter
@AfterThrowing ThrowsAdvice 需要 ThrowsAdviceAdapter
@After MethodInterceptor(直接就是) 不需要适配器
@Around MethodInterceptor(直接就是) 不需要适配器

适配器链默认注册在 DefaultAdvisorAdapterRegistry 里,且只注册了3个适配器。

public DefaultAdvisorAdapterRegistry() {
    registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
    registerAdvisorAdapter(new AfterReturningAdviceAdapter());
    registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

所以,即使你自己扩展 Advice,想搞一个自定义通知,也是可以自己注册新的 AdvisorAdapter 的,Spring 是支持的!

自定义AdvisorAdapter

  1. 自己写一个自定义的 AdvisorAdapter

  2. 把这个 AdvisorAdapter 注册到 Spring 的 AdvisorAdapterRegistry 里面

  3. Spring AOP 建链的时候会自动调用你注册的适配器进行适配

第一步:自己实现一个 AdvisorAdapter

Spring内置的适配器就是这么写的,比如 BeforeAdviceAdapter,
你可以自己仿照写一个,比如:

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.adapter.AdvisorAdapter;
import org.springframework.aop.framework.adapter.UnknownAdviceTypeException;
import org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor;

public class MyCustomAdviceAdapter implements AdvisorAdapter {

    @Override
    public boolean supportsAdvice(org.aopalliance.aop.Advice advice) {
        // 判断是否是你自己定义的Advice类型
        return (advice instanceof MyCustomAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        // 将你的Advice适配成MethodInterceptor
        return new MyCustomAdviceInterceptor((MyCustomAdvice) advisor.getAdvice());
    }
}

比如你的 MyCustomAdvice 是你自定义的通知类型。

第二步:注册到 DefaultAdvisorAdapterRegistry

注册到 Spring 的 AdvisorAdapterRegistry 里。

Spring默认用的是 DefaultAdvisorAdapterRegistry,它维护了一个 List:

this.adapters.add(new MethodBeforeAdviceAdapter());
this.adapters.add(new AfterReturningAdviceAdapter());
this.adapters.add(new ThrowsAdviceAdapter());

你可以手动注册,比如在配置类里这么干:

import org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class AopAdapterConfig {

    @PostConstruct
    public void registerCustomAdapter() {
        DefaultAdvisorAdapterRegistry registry = (DefaultAdvisorAdapterRegistry) DefaultAdvisorAdapterRegistry.getInstance();
        registry.registerAdvisorAdapter(new MyCustomAdviceAdapter());
    }
}

(注意:DefaultAdvisorAdapterRegistry本身是个单例,Spring里默认就是用的它。)

第三步:Spring在建链时自动调用你的适配器

然后你什么都不用管了!

当 Spring AOP 遇到你的 MyCustomAdvice 的时候,就会依次用注册的 AdvisorAdapter 去 supportsAdvice()判断,

  • 如果支持,就 getInterceptor()把你的Advice适配成一个 MethodInterceptor,

  • 然后就放到 MethodInterceptor链条里一起执行了!

一切都是自动的!

  • Spring建链时,真正负责适配的是:DefaultAdvisorAdapterRegistry#getInterceptors(Advisor advisor)

  • 它内部就是遍历所有注册的 AdvisorAdapter,找到能 supportsAdvice() 的,然后调用 getInterceptor()。

  • 如果没有任何适配器能处理,会抛 UnknownAdviceTypeException。

posted @ 2025-04-26 17:35  Eiffelzero  阅读(47)  评论(0)    收藏  举报