适配器模式----------设计模式
最近在看SpringMVC源码,从中看到了比较优秀的设计模式所以来分享下。

1.适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作
具体的详细知识可以参考这篇文章

http://haolloyin.blog.51cto.com/1177454/346128

http://blog.csdn.net/xtu_xiaoxin/article/details/8796499

适用场景:

1、已经存在的类的接口不符合我们的需求;

2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;

3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。

2.SpringMvc中的适配器(HandlerAdapter)
SpringMVC中的适配器到底是解决以上哪个问题的呢?我们来一步一步看看源码,看看Spring是怎么做的

首先我们找到前端控制器DispatcherServlet可以把它理解为适配器模式中的Client,它的主要作用在于通过处理映射器(HandlerMapper)来找到相应的Handler(即Controlle(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)r),并执行Controller中相应的方法并返回ModelAndView,

mappedHandler.getHandler()其实就是通过Spring容器中获取到的(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)Controller

先短暂回顾下流程

1.DispatcherServlet中的doDispatch

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
ModelAndView mv = null;
Exception dispatchException = null; try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request); // 此处通过HandlerMapping来映射Controller
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // 获取适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
} if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // 通过适配器调用controller的方法并返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) {
return;
} applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

2.为什么要使用适配器模式呢?
Controller可以理解为Adaptee(被适配者)其中之一

可以看到处理器(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用Controller方法,需要调用的时候就得不断是使用if else来进行判断是哪一种子类然后执行。那么如果后面要扩展(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)Controller,就得修改原来的代码,这样违背了开闭原则(对修改关闭,对扩展开放)。

3.SpringMvc 是如何使用适配器模式来解决以上问题的呢?
Spring创建了一个适配器接口(HandlerAdapter)使得每一种处理器(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)有一种对应的适配器实现类,让适配器代替(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)执行相应的方法。这样在扩展Controller 时,只需要增加一个适配器类就完成了SpringMVC的扩展了

 public interface HandlerAdapter {

 boolean supports(Object handler);

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

 }

supports()方法传入处理器(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)判断是否与当前适配器支持如果支持则从DispatcherServlet中的HandlerAdapter实现类中返回支持的适配器实现类。handler方法就是代理Controller来执行请求的方法并返回结果。
在DispatchServlert中的doDispatch方法中

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

此代码通过调用DispatchServlert 中getHandlerAdapter传入Controller(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等),来获取对应的HandlerAdapter 的实现子类,从而做到使得每一种Controller有一种对应的适配器实现类

返回后就能通过对应的适配实现类代理Controller(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)来执行请求的方法

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

其中一个处理器适配器就是我们常说的最熟悉的Controller类适配器

---------------------
作者:_PPB
来源:CSDN
原文:https://blog.csdn.net/u010288264/article/details/53835185
版权声明:本文为博主原创文章,转载请附上博文链接!

Sping 里面的适配器模式的实现的更多相关文章

  1. PHP设计模式(七)适配器模式(Adapter For PHP)

    适配器模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作. 如下图(借图): // 设置书的接口 // 书接口 interface BookI ...

  2. 《JS设计模式笔记》 5,适配器模式

    //适配器模式的作用就像一个转接口. jQuery("#"+id); $id=function (id) { return jQuery("#"+id)[0]; ...

  3. 设计模式(七): 通过转接头来观察"适配器模式"(Adapter Pattern)

    在前面一篇博客中介绍了“命令模式”(Command Pattern),今天博客的主题是“适配器模式”(Adapter Pattern).适配器模式用处还是比较多的,如果你对“适配器模式”理解呢,那么自 ...

  4. 设计模式(七)适配器模式(Adapter Pattern)

    一.引言 在实际的开发过程中,由于应用环境的变化(例如使用语言的变化),我们需要的实现在新的环境中没有现存对象可以满足,但是其他环境却存在这样现存的对象.那么如果将“将现存的对象”在新的环境中进行调用 ...

  5. PHP 适配器模式

    适配器模式(Adapter)模式:将一个类的接口,转换成客户期望的另一个类的接口.适配器让原本接口不兼容的类可以合作无间.     [适配器模式中主要角色]目标(Target)角色:定义客户端使用的与 ...

  6. 每天一个设计模式-3 适配器模式(Adapteer)

    每天一个设计模式-3 适配器模式(Adapteer) 1.现实中的情况 旧式电脑的硬盘是串口的,直接与硬盘连接,新硬盘是并口的,显然新硬盘不能直接连在电脑上,于是就有了转接线.好了,今天的学习主题出来 ...

  7. 设计模式--适配器模式Adapter(结构型)

    一.适配器模式 适配器模式的主要作用是在新接口和老接口之间进行适配.将一个类的接口转换成客户端期望的另外一个接口.其实适配器模式有点无赖之举,在前期设计的时候,我们就不应该考虑适配器模式,而应该通过重 ...

  8. c#设计模式-适配器模式

    一. 适配器(Adapter)模式 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作. 名称由来 这很像变压器(Adapter),变压 ...

  9. C#设计模式系列:适配器模式(Adapter)

    在实际的软件系统设计和开发中,为了完成某项工作需要购买一个第三方的库来加快开发.这带来一个问题,在应用程序中已经设计好的功能接口,与这个第三方提供的接口不一致.为了使得这些接口不兼容的类可以在一起工作 ...

随机推荐

  1. SQL操作符、通配符等

    一.通配符 常用模糊查询:% SELECT * FROM TB_Name WHERE FIELD LIKE pattern   SELECT * FROM Persons WHERE name LIK ...

  2. MediaManager安装后配置

    端口要改成81 修改Chainmail名称:

  3. Tomcat7 JDK8 Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000540000000, 5368709120, 0) failed; error='Cannot allocate memory' (errno=12)

    [root@crm-web- bin]# shutdown.sh bash: shutdown.sh: command not found [root@crm-web- bin]# sh shutdo ...

  4. java程序高CPU,如何直接定位(linux系统下命令行操作)

    1.top命令找出 2.也可以使用 (1)ps -ef|grep java|grep -v grep (2)jps -l|grep  公司名 然后,记住PID是9529. 3.定位具体的线程或者代码: ...

  5. loj121-动态图连通性

    Solution 线段树分治, 然后直接在线段树上dfs, 在进入/回溯的过程中维护并查集的merge/split. 对于split操作, 可以在merge时按秩合并, 然后利用栈记录, split时 ...

  6. 消息队列与Kafka

    2019-04-09 关键词: 消息队列.为什么使用消息队列.消息队列的好处.消息队列的意义.Kafka是什么 本篇文章系本人就当前所掌握的知识关于 消息队列 与 kafka 知识点的一些简要介绍,不 ...

  7. pjb fabu

    #!/bin/bash PyPath=/opt/shell/mysql LocaName=`pwd` bagname=`basename $LocaName` sleep 1s ConfList=`p ...

  8. Keras 获取中间某一层输出

    1.使用函数模型API,新建一个model,将输入和输出定义为原来的model的输入和想要的那一层的输出,然后重新进行predict. #coding=utf-8 import seaborn as ...

  9. WD与地图 解题报告

    WD与地图 哎,我好傻啊,看了题解还弄错了一遍,靠着lbw指点才董 题意:给一个带点权有向图,要求支持删边,查询一个scc前\(k\)大权值,修改点权,不强制在线. 显然倒序处理变成加边 考虑求出每条 ...

  10. P1996 约瑟夫问题-题解(队列??明明是单循环链好吗)

    一如既往的题目传送:     https://www.luogu.org/problemnew/show/P1996 这里不讲数组模拟的方法(毕竟多做点题的模拟功力足以暴力出这道题),而是讲一种单循环 ...