1、适配器模式的理解
适配器模式可以理解为有两个现成的类Adaptee和Target,它们两个是不能动的,要求必须使用B这个类来实现一个功能,但是A的内容是能复用的,这个时候我们需要编写一个转换器
适配器模式
- Adaptee:被适配者,现有的接口或者类;
- Adapter:适配器类,适配器模式的核心,转换作用
- Target:目标接口或者类
适配器模式的实现步骤
- 定义目标接口,即客户端所期望的接口。
- 定义适配器类,继承目标接口并包含一个适配者对象。
- 在适配器类中实现目标接口的方法,调用适配者对象的相关方法进行适配。
- 在客户端中使用适配器类进行操作。
适用场景
- 继承:需要用到别人的类,但是不能修改
- 多适配者:多个不同的对象,需要让他们具有相同的方法
- 缺省形式
适配器模式有类适配器和对象适配器两种方式,一般采用前者
2、继承场景
来公司第二天,写一个简单的业务,看到同事写的接口中5个方法有3个正好可以用的,但是还需要另外新增一个,于是我便开始了改造(新增一个方法);提交后同事大发雷霆,谁让你新增的,新增了这个方法,这个接口就失去了本来的意思。。。。。。
我去***,那算了,我还是自己写一个吧,想想怎么能在不懂他的接口前提下,复用一下他的代码,那边使用适配器模式
//同事的接口为被适配者
public interface Adaptee{void method1();void method2();void method3();void method4();void method5();
}
public class AdapteeImpl implements Adaptee {@Overridepublic void method1() {System.out.println("method1 execute......");}@Overridepublic void method2() {System.out.println("method2 execute......");}@Overridepublic void method3() {System.out.println("method3 execute......");}@Overridepublic void method4() {System.out.println("method4 execute......");}@Overridepublic void method5() {System.out.println("method5 execute......");}
}//我需要使用的接口为目标接口
public interface Target{void method1();void method2();void method3();void method6();
}
//构建适配器类Adapter
//方式一:类适配器方式
public class Adapter1 extends AdapteeImpl implements Target {@Overridepublic void method6() {System.out.println("method6 execute......");}
}public class Client {public static void main(String[] args) {Target target = new Adapter1();target.method1();target.method2();target.method3();target.method6();}
}//方式二:对象适配器方式
public class Adapter2 implements Target {private Adaptee adaptee;public Adapter2(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void method1() {adaptee.method1();}@Overridepublic void method2() {adaptee.method2();}@Overridepublic void method3() {adaptee.method3();}@Overridepublic void method6() {System.out.println("method6 execute......");}
}public class Client {public static void main(String[] args) {Target target = new Adapter2(new AdapteeImpl());target.method1();target.method2();target.method3();target.method6();}
}
3、多适配者
多个适配者,适配同一个目标接口,为每一个适配者创建一个适配器
这种是最常用的方式,在springMVC和AOP中都有用到,后面会进行解析
例:新能源汽车的发动机有电能发动机(Electric Motor)和光能发动机(Optical Motor)等,各种发动机的驱动方法不同,例如,电能发动机的驱动方法 electricDrive() 是用电能驱动,而光能发动机的驱动方法 opticalDrive() 是用光能驱动,它们是适配器模式中被访问的适配者。
客户端希望用统一的发动机驱动方法 drive() 访问这两种发动机,所以必须定义一个统一的目标接口 Motor,然后再定义电能适配器(Electric Adapter)和光能适配器(Optical Adapter)去适配这两种发动机。
package adapter;//目标:发动机
interface Motor {public void drive();
}//适配者1:电能发动机
class ElectricMotor {public void electricDrive() {System.out.println("电能发动机驱动汽车!");}
}//适配者2:光能发动机
class OpticalMotor {public void opticalDrive() {System.out.println("光能发动机驱动汽车!");}
}//电能适配器
class ElectricAdapter implements Motor {private ElectricMotor emotor;public ElectricAdapter() {emotor=new ElectricMotor();}public void drive() {emotor.electricDrive();}
}//光能适配器
class OpticalAdapter implements Motor {private OpticalMotor omotor;public OpticalAdapter() {omotor=new OpticalMotor();}public void drive() {omotor.opticalDrive();}
}//客户端代码
public class MotorAdapterTest {public static void main(String[] args) {System.out.println("适配器模式测试:");Motor motor=(Motor)ReadXML.getObject();motor.drive();}
}
4、缺省形式
缺省就是对于一个具有很多方法的接口,我没只需要其中几个,不想把所有的方法都实现一遍,可以写一个抽象类作为适配器,再去继承该适配器
public interface Adaptee {void model1();void model2();void model3();void model4();void model5();void model6();void model7();void model8();void model9();void model10();
}public abstract class Adapter implements Adaptee{@Overridepublic void model1() {}@Overridepublic void model2() {}@Overridepublic void model3() {}@Overridepublic void model4() {}@Overridepublic void model5() {}@Overridepublic void model6() {}@Overridepublic void model7() {}@Overridepublic void model8() {}@Overridepublic void model9() {}@Overridepublic void model10() {}
}public class Target extends Adapter{@Overridepublic void model3() {System.out.println("model3......");}@Overridepublic void model7() {System.out.println("model7......");}
}
5、spring中的适配器模式
5.1 SpringMVC
请求处理流程
HandlerAdapter
在 Spring MVC 中使用了适配器模式。HandlerAdapter
主要用于支持不同类型的处理器(如 Controller、HttpRequestHandler 或者 Servlet 等),让它们能够适配统一的请求处理流程。这样,Spring MVC 可以通过一个统一的接口来处理来自各种处理器的请求。在 Spring MVC 的工作流程中,HandlerAdapter
扮演了一个重要角色。以下是其工作原理的简化版:
DispatcherServlet
:前端控制器(Front Controller),负责接收所有请求并将其分发给相应的处理程序HandlerMapping
:处理器映射器,立请求URL与处理程序之间的映射关系,默认为RequestMappingHandlerMapping
(根据@Controller注解和@RequestMapping注解来进行URL与处理程序的映射),可以在Spring配置文件(如XML配置文件或Java配置类)中显式地配置所需的HandlerMapping
HandlerAdapter
:处理器适配器,通过handlerMapping
获取到对应的处理程序handler(controller)
后,通过所有注册的handlerAdapter
的supports()
方法找到对应的适配器来调用,当存在多个合适的HandlerAdapter时,框架会根据一定规则进行判断和选择
- 用户发起一个 HTTP 请求到 Spring MVC 应用。
DispatcherServlet
接收到请求后,首先会调用HandlerMapping
,寻找合适的处理器(Handler)来处理这个请求。- 找到合适的处理器后,
DispatcherServlet
需要找到一个能够处理这个处理器的HandlerAdapter
。为此,它会遍历所有已注册的HandlerAdapter
,调用它们的supports
方法,检查它们是否支持当前处理器。 - 找到支持当前处理器的
HandlerAdapter
后,DispatcherServlet
会调用该HandlerAdapter
的handle
方法,将请求委托给处理器进行处理。 - 处理器处理完请求后,会返回一个
ModelAndView
对象,DispatcherServlet
会将这个对象传递给适当的ViewResolver
,以解析视图并将响应返回给用户。
我们在
Controller
、Service
、Mapper
中写的业务逻辑,在HandlerAdapter
的处理过程中执行
以下是一个简化的 HandlerAdapter
接口示例:
public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
Spring MVC 提供了一些内置的 HandlerAdapter
实现,如RequestMappingHandlerAdapter
、SimpleControllerHandlerAdapter
、HttpRequestHandlerAdapter
是 Spring MVC 中内置的几个 HandlerAdapter
实现,它们分别用于支持不同类型的处理器。
RequestMappingHandlerAdapter
:支持基于注解的处理器,如使用@Controller
和@RequestMapping
注解的处理器方法。这是 Spring MVC 中最常用的处理器类型。SimpleControllerHandlerAdapter
:支持实现org.springframework.web.servlet.mvc.Controller
接口的处理器。这是 Spring MVC 早期版本中的处理器类型,现在已经较少使用。HttpRequestHandlerAdapter
:支持实现org.springframework.web.HttpRequestHandler
接口的处理器。这种类型的处理器主要用于处理静态资源,如图片、样式表等。
举例:
@Controller
@RequestMapping("/user")
public class UserController {@GetMapping("/{id}")public String getUserById(@PathVariable("id") Long id, Model model) {// 执行业务逻辑return "userDetails";}
}
在上述例子中有一个controller
,当spring接收到请求时,处理过程为:
假设我们使用了默认的配置和注解驱动。
1、首先,前端控制器(DispatcherServlet)会根据请求的 URL 路径来选择合适的 HandlerMapping。在 Spring MVC 中,默认使用的是 RequestMappingHandlerMapping,它会根据 @RequestMapping 注解以及其他相关注解来确定处理程序(handler)与请求路径之间的映射关系。
2、 对于 UserController 中的 getUserById() 方法,使用了 @GetMapping 注解,并指定了路径为 “/{id}”。因此,当客户端发送 GET 请求到 “/user/{id}” 路径时,RequestMappingHandlerMapping 就会匹配到这个处理程序(handler)。
3、 接下来,在执行处理程序之前,前端控制器还需要选择合适的 HandlerAdapter,并将请求委托给它来执行处理程序。
4、对于标注有 @GetMapping、@PostMapping 等注解的方法,默认情况下会选择 RequestMappingHandlerAdapter 作为主要的 HandlerAdapter。
5、RequestMappingHandlerAdapter 是一个功能强大且灵活的适配器,能够处理包含模型数据、参数绑定、异常处理等复杂情况。
在上述例子中,当通过 RequestMappingHandlerMapping 匹配到 UserController 的 getUserById() 方法后,前端控制器就会选择 RequestMappingHandlerAdapter 来执行这个处理程序,并传递相应的请求参数和模型数据给该方法。
在 Spring MVC 中,前端控制器(DispatcherServlet)会根据请求路径和方法来选择合适的 HandlerAdapter。
选择后,HandlerAdapter 将接收到的请求参数、模型数据等信息传递给相应的处理程序(业务逻辑),并执行该处理程序。
HandlerAdapter 根据具体的处理程序类型来确定调用哪个方法,以及如何将请求数据传递给该方法。
不同类型的处理程序可能有不同的要求和处理方式。 例如,在使用注解配置的方法作为处理程序时,默认情况下会选择 RequestMappingHandlerAdapter。
RequestMappingHandlerAdapter 会根据注解中定义的规则,将请求参数、路径变量、请求体内容等绑定到方法的入参上,并调用该方法执行业务逻辑。它还能够通过模型对象(Model)来向视图传递数据。
可以说 HandlerAdapter 是负责将请求数据传递给我们自己编写的业务逻辑处理程序,并执行其中定义的方法。它是框架与业务代码之间进行通信和协调的重要环节。
自定义handlerAdapter
通常情况下,Spring MVC 默认提供的 HandlerAdapters 是能够满足大多数应用场景的,并且能够处理各种类型的处理程序(handler)。
在某些特殊情况下,可能需要自定义 HandlerAdapter 来满足特定的需求。以下是一些需要自定义 HandlerAdapter 的情况:
需要支持新的处理程序类型:如果你使用了自定义的处理程序类型,而该类型不属于 Spring MVC 默认支持的类型,那么你可以编写自己的 HandlerAdapter 来支持该类型。
特定的请求/响应方式:如果你想要处理一种不常见或非标准的请求/响应方式,例如 WebSocket、SSE(服务器发送事件)等,你可能需要编写一个适配器来处理这些方式。
定制化业务逻辑:如果你有特殊的业务需求,需要在执行业务逻辑之前或之后添加额外的逻辑操作,例如权限校验、日志记录等,你可以编写一个自定义 HandlerAdapter 来扩展框架提供的功能。
性能优化:如果你对性能有极高要求,并希望通过优化执行过程来提升系统性能,可以根据具体场景编写一个更高效的 HandlerAdapter 来替换默认实现。
总之,在需要与 Spring MVC 框架进行更深度集成、满足特定需求或优化性能时,可以考虑自定义 HandlerAdapter。但在大多数情况下,默认提供的 HandlerAdapters 能够满足开发需求。
handlerAdapter的适配器模式
可以看到处理器的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用 Controller 方法,需要调用的时候就得不断地使用 if else 来进行判断是哪一种子类然后执行。那么如果后面要扩展 Controller, 就得修改原来的代码,这样违背了 OCP 原则
下面手写一下handlerAdapter的选择流程
//controller类,我们自己写的逻辑,即handler
public interface Controller {}public class AnnotationController implements Controller{public void doAnnotationHandler() {System.out.println("annotation...");}
}public class HttpController implements Controller{public void doHttpHandler() {System.out.println("http...");}
}public class SimpleController implements Controller{public void doSimpleHandler() {System.out.println("simple...");}
}
//handlerAdapter类 处理器适配器
//通过handlermapping获取到对应的handler后,再查找对应的处理器适配器调用对应方法
public interface HandlerAdapter {boolean supports(Object handler);void handle(Object handler);
}public class AnnotationHandlerAdapter implements HandlerAdapter{@Overridepublic boolean supports(Object handler) {// TODO Auto-generated method stubreturn (handler instanceof AnnotationController);}@Overridepublic void handle(Object handler) {// TODO Auto-generated method stub((AnnotationController)handler).doAnnotationHandler();}
}public class HttpHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {// TODO Auto-generated method stubreturn (handler instanceof HttpController);}@Overridepublic void handle(Object handler) {// TODO Auto-generated method stub((HttpController)handler).doHttpHandler();}
}public class SimpleHandlerAdapter implements HandlerAdapter{@Overridepublic boolean supports(Object handler) {// TODO Auto-generated method stubreturn (handler instanceof SimpleController);}@Overridepublic void handle(Object handler) {// TODO Auto-generated method stub((SimpleController)handler).doSimpleHandler();}
}
//DispatcherServlet类 执行整体逻辑
public class DispatchServlet {public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();//注内置的处理器适配器,也可以自定义,然后注册到DispatcherServlet类中public DispatchServlet() {handlerAdapters.add(new AnnotationHandlerAdapter());handlerAdapters.add(new HttpHandlerAdapter());handlerAdapters.add(new SimpleHandlerAdapter());}public void doDispatch() {/** 1、这里用来调用handlermapping获取对应的controller(handler)* springmvc中默认使用的是 RequestMappingHandlerMapping*/AnnotationController annotationController = new AnnotationController();//2、通过controller(handler)选择对应的handlerAdapterHandlerAdapter handlerAdapter = getHandler(annotationController);//3、调用对应处理程序(controller的方法),处理请求handlerAdapter.handle(annotationController);}public HandlerAdapter getHandler(Controller controller) {for (HandlerAdapter handlerAdapter : handlerAdapters) {if(handlerAdapter.supports(controller)) {return handlerAdapter;}}return null;}
}
//客户端
public class Client {public static void main(String[] args) {new DispatchServlet().doDispatch();}
}
自定义适配器
要自定义一个 HandlerAdapter
,你需要实现 org.springframework.web.servlet.HandlerAdapter
接口,并提供对你的自定义处理器的支持。下面是一个简单的自定义 HandlerAdapter
示例:
首先,创建一个自定义处理器:
public class CustomHandler {public String handleRequest() {return "Hello, CustomHandler!";}
}
接着,实现一个自定义的 HandlerAdapter
:
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class CustomHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return handler instanceof CustomHandler;}@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {CustomHandler customHandler = (CustomHandler) handler;String result = customHandler.handleRequest();return new ModelAndView("customView", "message", result);}@Overridepublic long getLastModified(HttpServletRequest request, Object handler) {return -1;}
}
要在 Spring MVC 应用中使用这个自定义的 HandlerAdapter
,你需要将其注册到 DispatcherServlet
中。在基于 Java 配置的应用中,你可以这样做:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {@Overrideprotected void addAdapters(List<HandlerAdapter> adapters) {adapters.add(new CustomHandlerAdapter());super.addAdapters(adapters);}
}
这样,你的自定义 HandlerAdapter
就会在 Spring MVC 应用中生效,并能处理 CustomHandler
类型的处理器。
5.2 AOP
在Spring的Aop中,使用Advice(通知)来增强被代理类的功能,Advice的类型有:BeforeAdvice、AfterReturningAdvice、ThreowSadvice。
每种Advice都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。
各种不同类型的Interceptor,通过适配器统一对外提供接口,如下类图所示:client —> target —> adapter —> interceptor —> advice。最终调用不同的advice来实现被代理类的增强
原理springmvc类似