如果你要访问的资源是静态资源,比如图片、CSS样式表,DNS解析给出的IP地址便是CDN做事器的地址,你拿到的就会是CDN做事器而不是目标网站的实际地址。由于CDN会缓存网站的大部分资源。
由PHP、Java等后台做事动态天生的页面属于“动态资源”,CDN无法缓存,只能从目标网站获取。此时HTTP要求终极会访问到网站IP。
目标网站的做事器对外表现的是一个IP地址,但为了能够扛住高并发,在内部也是一套繁芜的架构。常日在入口是负载均衡设备,例如四层的LVS或者七层的Nginx,在后面是许多的做事器,构成一个更强更稳定的集群。
Nginx反向代理和负载均衡提到反向代理,就要先说正向代理。正向代理一样平常叫代理。便是要求发起人找一个代理做一件事情,真正干工作的人只认识代理不认识要求发起人。常用的翻墙,便是HTTP中介的一种代理。以是我们利用翻墙代理做事器连接上了国外的网站,但那个网站并不知道我们在利用。
反向代理是做事供应方出一个代理,要求人只跟代理打交道。比如这里要求只发给了Nginx这个代理,后面的便是Nginx自己进行处理,找到真正的业务处理做事器。如果是静态要求,如CSS啥的,就直接转向静态做事器。如果是动态要求就转向Web运用做事器。然而不管是静态做事器还是Web运用做事器都是有好几台做事器。Nginx按照一定的策略对要求向业务做事器进行分配,让压力不集中在1台做事器,这便是负载均衡了。
Nginx除了配置实际处理业务的做事器,还可以配置一些安全策略,比如如果一个IP在1秒内要求了100次,那么将视为攻击,直接返回缺点码,不向后通报要求。还可以配置超时等待韶光,多媒体文件的许可大小等。
Web运用做事要求根据Nginx供应的IP和端口找到做事器上对应的Web前端做事。我们做事器上支配的是Tomcat。我们的Web做事采取的是Spring MVC框架,终于说到正题上了。
建立连接
HTTP协议是运行在TCP/IP 根本上的,依赖TCP/IP协议来实现数据的可靠传输。以是浏览器要用HTTP协议收发数据,首先要做的便是建立TCP连接。
Web做事器的默认端口是80,以是浏览器依照TCP协议的规范,利用“三次握手”建立与Web做事器的连接。有了可靠的TCP连接通道后,浏览器按照HTTP协议规定的格式,通过TCP 发送了一个要求报文。Web做事器收到报文后在内部就要处理这个要求。同样也是依据 HTTP协议的规定,解析报文。
HTTP报文的构造HTTP协议的要求报文和相应报文的构造基本相同,由三大部分组成:
起始行(start line): 描述要求或相应的基本信息;头部字段凑集(header):利用 key-value 形式更详细地解释报文;正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。这个中前两部分起始行和头部字段常常又合称为“要求头”或“相应头”,正文又称为“实体”,与header对应,很多时候就直接称为body。
HTTP协议规定报文必须有header,但可以没有body,而且在header之后必须要有一个“空行”,也便是“CRLF”,十六进制的“0D0A”。以是,一个完全的HTTP报文就像是下图的这个样子,把稳在header和body之间有一个“空行”。
在这个浏览器发出的要求报文里,第一行“GET / HTTP/1.1”便是要求行,而后面的“Host”、“Connection”等等都属于header,报文的末了是一个空缺行结束,没有body。在很多时候,特殊是浏览器发送GET要求的时候都是这样,HTTP报文常常是只有header而没body,相称于只发了一个超级“大头”过来,每时每刻网络上都会有数不清的“大头”在跑来跑去。
进入Web做事器后的处理必知背景:Servlet规范为什么要先容Servlet呢?缘故原由不难明得,Spring的Web框架——Spring MVC便是基于Servlet规范实现的。以是要剖析Spring MVC,首先应追根溯源,弄懂Servlet,因此这里须要讲一下Servlet规范。
Servlet是J2EE标准的一部分,是一种运行在Web做事器真个小型Java程序,更详细地说,Servlet是按照Servlet规范编写的一个Java类,用于交互式地浏览和修正数据,天生动态Web内容。在遵守Servlet规范的条件下,我们可将Web运用支配在Servlet容器下。这样做的好处是什么呢?
我以为可以使开拓者聚焦业务逻辑,而不用去关心HTTP协议方面的事情。试想如果我们为了写一个Web运用,还要去解析HTTP协议干系的内容,那会增加很多事情量。如果我们写的Web运用不大,不夸年夜地说,项目中对HTTP报文解析供应支持的代码会比业务代码还要多,这岂不是得不偿失落。
当然,在现实中,有现成的框架可用,并不须要自己造轮子。如果我们基于Servlet规范实现Web运用的话,HTTP协议的处理过程就不须要我们参与了。这些事情交给Servlet容器(例如Tomcat和Jetty)去做就行了,我们只须要关心业务逻辑怎么实现即可。
在Servlet完成初始化后,针对外部对Servlet的每次要求,Servlet容器就可以利用它处理客户端要求了。客户端要求由ServletRequest类型的要求工具表示。Servlet封装相应并返回给要求的客户端,该相应由ServletResponse类型的相应工具表示,这两个工具是由容器通过参数通报到Servlet接口的service()方法。在HTTP要求的场景下,容器供应的要乞降相应工具详细类型分别是HttpServletRequest和HttpServletResponse。
浏览器通过HTTP要求访问Servlet的交互过程如下图所示:
不同的Servlet容器都会实现对Servlet规范的实现,个中标准的Servlet规范的实现在javax.servlet-api这个jar包里,在Tomcat里面能找到,我们就从这个jar包中HttpServlet类开始剖析,其service()方法源码如下:
//javax.servlet.http.HttpServlet.java@Overridepublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{ HttpServletRequest request; HttpServletResponse response; //验证要求跟返复书息封装工具的类型是不是servlet规范中定义的类型的 //否则抛非常 if (!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)) { throw new ServletException("non-HTTP request or response"); } //转为HttpServletRequest跟HttpServletResponse类型 request = (HttpServletRequest) req; response = (HttpServletResponse) res; service(request, response);}
可以看到其紧张的逻辑便是对要求跟返回工具的验证,确保是按照Servlet规范来的。后面自己定义了一个service()方法来完成后面的要求区分逻辑。
//javax.servlet.http.HttpServlet.javaprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取要求的方法值 String method = req.getMethod(); //判断是不是get要求 if (method.equals(METHOD_GET)) { //判断之前这个要求工具的末了修正韶光是否修正过 long lastModified = getLastModified(req); //如果值为-1,表示当前的servlet工具不支持要求头中的if-modified-since,这时候就须要调用后面的代码逻辑,代价高 if (lastModified == -1) { doGet(req, resp); } else { //如果不是-1,表示支持,然后获取要求头中的if-modified-since参数 long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); //如果要求头中的韶光小于上次的要求韶光,则表示页面须要进行刷新 if (ifModifiedSince < lastModified) { //设置返回体中的Last-Modified参数 maybeSetLastModified(resp, lastModified); //进行后面的逻辑 doGet(req, resp); } else { //如果两个韶光相等则设置返回体的要求状态为304 resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { //获取上次的修正韶光 long lastModified = getLastModified(req); //设置修正韶光 maybeSetLastModified(resp, lastModified); //进行后面逻辑 doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); }}
可以看到这里的浸染实在便是对要求中的要求类型进行判断,来选择后面的逻辑。个中对get要求的剖析后面多了一些处理,这些处理是为了避免做事器对不必要逻辑的处理。
Spring对Servlet规范的实现有了以上Servlet规范的根本知识,我们来看Spring是如何实现规范的。Spring中对Servlet规范的实现类是FrameworkServlet类。个中FrameworkServlet继续了HttpServletBean,因此这个类对doPost()、doDelete()等方法都有实现,但是实现都是差不多的,这里就剖析常用的post和get要求的处理逻辑。
//HttpServletBean继续了HttpServlet类public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { //省略... @Override protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //进行要求的处理 processRequest(request, response); } @Override protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //进行要求的处理 processRequest(request, response); } //省略...}
实际的处理逻辑都在processRequest()这个方法,它是一个protected方法,源码如下:
//FrameworkServlet.javaprotected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取当前系统韶光,用来打算这个步骤的处理耗时 long startTime = System.currentTimeMillis(); Throwable failureCause = null; //获取当前做事运行所在地区,在RequestContextFilter中进行处理设值 LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); //创建干系地区的工具的LocalContext, LocaleContext localeContext = buildLocaleContext(request); //获取要求的属性,要求干系属性会在RequestContextHolder中,它是用ThreadLocal实现的 RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); //创建requestAttributes,ServletRequestAttributes是RequestAttributes子类 ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); //从request获取WebAsyncManager,在filter阶段会创建WebAsyncManager,表示是不是异步相应的要求 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); //将FrameworkServlet的内部类RequestBindingInterceptor设置到asyncManager中,用于在异步中初始化扈从新设置FrameworkServlet asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); //将localeContext跟requestAttributes设置到LocaleContextHolder跟RequestContextHolder中 initContextHolders(request, localeContext, requestAttributes); try { //进行业务处理 doService(request, response); } catch (ServletException | IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { //移除ThreadLocal中的要求干系信息,attribute跟context信息 resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } //打印结果 logResult(request, response, failureCause, asyncManager); //发布要求处理完成事宜 publishRequestHandledEvent(request, response, startTime, failureCause); }}
在这个方法中紧张的逻辑还是准备处理要求须要的高下文和参数等。个中,最主要的便是卖力业务处理的doService()方法,它是一个抽象方法,必须由子类来实现。而FrameworkServlet类只有一个子类,那便是大名鼎鼎的DispatchServlet类,来看DispatchServlet类中对doService()方法的实现。
//DispatchServlet.javaprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); //如果是一个include要求,<jsp:incluede page="xxx.jsp"/> 这种 //可能在一个要求中嵌套了其余的一个要求,因此须要备份当前要求 Map<String, Object> attributesSnapshot = null; //是否是一个include要求,通过request中的javax.servlet.include.request_uri属性判断 //JSP在运行期间是会被编译成相应的Servlet类来运行的, if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); //获取包含的要求中的获取A要求的内部B要求设定的spring的策略 if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } //设置web运用高下文到要求中, request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); //设置本地解析器 request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); //设置主题解析器 request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); //设置主题,如果没有设置则为null,默认的为WebApplicationContext request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); //将request跟response保存到一个FlashMap中,FlashMap用来将一个要求跟 //其余一个要求关联起来,常日在redirect的时候有用 if (this.flashMapManager != null) { //如果当前要求的FlashMap在之前的要求中保存过了,则取出来,并去除对应的缓存 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); //保存FlashMap到属性中 if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); }//DispatchServlet.javaprotected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; //从request中获取WebAsyncManager WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { //检讨是不是multipart要求并将要求转化为MultipartHttpServletRequest类型的 processedRequest = checkMultipart(request); //如果要求不是原来的request要求,则表示是multipart要求并且解析过的 multipartRequestParsed = (processedRequest != request); //根据request中的url从hanlderMapping中获取 //封装了HandlerInterceptor的HandlerExecutionChain mappedHandler = getHandler(processedRequest); //如果不存在对应的处理链则返回 if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } //从HandlerExecutionChain中获取Handler然后探求得当的HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //获取要求办法 String method = request.getMethod(); boolean isGet = "GET".equals(method); //检讨是不是GET要求 if (isGet || "HEAD".equals(method)) { //检讨当前的get类型的要求的末了修正韶光是不是存在的 //这个参数用来减少数据传输用 long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); //如果浏览器要求中的末了要求韶光跟做事器的末了修正韶光同等 //并且是get类型要求则直接返回。 if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //调用applyPreHandle方法,实行全部的前置拦截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //实行对应的HandlerAdapter的Handler方法,拿到对应的视图 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //检讨当前的要求是否正在异步处理,如果是的则直接放弃并返回 if (asyncManager.isConcurrentHandlingStarted()) { return; } //如果处理的结果返回的视图是空的则利用默认的视图,不为空则用途理的结果 applyDefaultViewName(processedRequest, mv); //调用applyPostHandle方法实行后置拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { //进行缺点视图的处理 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()) { //如果mappedHandler不是null,则调用对应的mappedHandler中的AsyncHandlerInterceptor if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { //对流类型的要求,做后置的处理 if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }} try { //要求分发处理 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } }}
以上最主要的便是卖力要求分发的doDispatch()方法,看懂doDispatch()方法,就能彻底理解一次HTTP要求进入到Spring之后,要做哪些处理。
//DispatchServlet.javaprotected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; //从request中获取WebAsyncManager WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { //检讨是不是multipart要求并将要求转化为MultipartHttpServletRequest类型的 processedRequest = checkMultipart(request); //如果要求不是原来的request要求,则表示是multipart要求并且解析过的 multipartRequestParsed = (processedRequest != request); //根据request中的url从hanlderMapping中获取 //封装了HandlerInterceptor的HandlerExecutionChain mappedHandler = getHandler(processedRequest); //如果不存在对应的处理链则返回 if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } //从HandlerExecutionChain中获取Handler然后探求得当的HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //获取要求办法 String method = request.getMethod(); boolean isGet = "GET".equals(method); //检讨是不是GET要求 if (isGet || "HEAD".equals(method)) { //检讨当前的get类型的要求的末了修正韶光是不是存在的 //这个参数用来减少数据传输用 long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); //如果浏览器要求中的末了要求韶光跟做事器的末了修正韶光同等 //并且是get类型要求则直接返回。 if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //调用applyPreHandle方法,实行全部的前置拦截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //实行对应的HandlerAdapter的Handler方法,拿到对应的视图 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //检讨当前的要求是否正在异步处理,如果是的则直接放弃并返回 if (asyncManager.isConcurrentHandlingStarted()) { return; } //如果处理的结果返回的视图是空的则利用默认的视图,不为空则用途理的结果 applyDefaultViewName(processedRequest, mv); //调用applyPostHandle方法实行后置拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { //进行缺点视图的处理 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()) { //如果mappedHandler不是null,则调用对应的mappedHandler中的AsyncHandlerInterceptor if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { //对流类型的要求,做后置的处理 if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }}
在网上有很多环绕DispatcherServlet的doDispatch()方法解释Spring如何处理要求的图。借用网上一张图描述了DispatchServlet对要求的处理过程。
全体流程梳理如下:
首先会检讨当前的要求是不是multipart/form-data类型的要求,是则将要求转换为MultipartHttpServletRequest类型的request解析出URL从HandlerMapping工具中找到对应的封装了HandlerInterceptor凑集的HandlerExecutionChain工具,没有找到就直接返回404缺点页面从HandlerExecutionChain中获取Handler然后探求得当的HandlerAdapter检讨是不是get要求,如果是,然后在检讨lastModified这个属性选择是直接返回还是进行后续的要求处理。调用前面选择的HandlerAdapter的applyPreHandle方法,取到所有拦截器后,for循环调用每个拦截器HandlerInterceptor的preHandle()方法调用前面选择的HandlerAdapter的handle方法,进行逻辑的处理,返回ModelAndView工具检讨当前的要求是否正在异步处理,如果是则直接放弃并返回检讨返回的ModelAndView的视图是不是null,是则返回默认的,不是则不处理调用前面选择的HandlerAdapter的applyPostHandle方法,取到所有拦截器后,for循环调用每个拦截器HandlerInterceptor的postHandle()方法对正常返回的或者发生非常时天生的视图进行处理,对异步要求或multipart/form-data类型要求进行后续的处理虽然全体的request要求的逻辑只有这么多,但是里面的每个步骤都是比较繁芜的。
我们在业务代码中常常写的相应前端要求的Controller在哪儿呢,上图中并没有画出。实际上,在运用启动的时候,Spring容器会加载这些Controller类,并且解析出URL对应的处理函数,封装成Handler工具,存储到HandlerMapping工具中。当有要求到来的时候,DispatcherServlet从HanderMapping中,查找要求URL对应的Handler,然后调用实行Handler对应的函数代码,末了将实行结果返回给客户端。
为什么要把Controller封装成Handler工具呢,由于定义Controller的办法非常多,是分歧一的。以下就展示了三种办法的Controller定义,当然我们用得最多的还是办法一。
//办法一:通过@Controller、@RequestMapping来定义@Controllerpublic class DemoController { @RequestMapping("/getUserName") public ModelAndView getUserName() { ModelAndView model = new ModelAndView("Greeting"); model.addObject("message", "TOM"); return model; }}//办法二:实现Controller接口 + xml配置文件:配置DemoController与URL的对应关系public class DemoControllerImpl implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView model = new ModelAndView("HelloWorld"); model.addObject("message", "HelloWorld"); return model; }}//办法三:继续HttpServlet抽象类 + xml配置文件:配置DemoExtendServletController类与URL的对应关系public class DemoExtendServletController extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello World!"); }
办法一中的函数的定义很随意、不固定,办法二中的函数定义是 handleRequest()、办法三中的函数定义是HttpServlet的service()方法。如果不作适配,DispatcherServlet须要根据不同类型的Controller,调用不同的函数,会有很多if-else分支判断,而且,如果要增加一个新的Controller的定义方法,我们就要在DispatcherServlet类代码中,对应地增加一段if逻辑,这显然不符合开闭原则。Spring利用适配器模式对代码进行改造,定义了统一的接口HandlerAdapter,并且对每种Controller定义了对应的适配器类。在DispatcherServlet类中,就不须要区分对待不同的Controller工具了,统一调用HandlerAdapter的handle()函数就可以了。详情可参考博文Spring中用到的几种范例的设计模式的适配器模式部分。