Servlet API解耦

为什么需要与Servlet API解耦

目前在Controller中是无法调用Servlet API的,因为无法获取Request与Response这类对象,我们必须在Dispatcher中将这些对象传递给Controller的Action方法才能拿到这些对象,这显然会增加Controller对Servlet API的耦合。最好能让Controller完全不使用Servlet API就能操作Request与Response对象。

最容易拿到Request与Response对象的地方就是DispatcherServlet的service方法:

@WebServlet(urlPatterns = "/*",loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
}

然而,我们又不想把Request和Response对象传递到Controller的Action方法中,所以我们需要提供一个线程安全的对象,通过它来封装Request和Response对象,并提供一系列常用的Servlet API,这样我们就可以在Controller中随时通过该对象来操作Request与Response对象的方法了。需要强调的是,这个对象一定是线程安全的,也就是说每个请求线程独自拥有一份Request与Response对象,不同请求线程间是隔离的

与Servlet API解耦的实现过程

一个简单的思路是,编写一个ServletHelper类,让它去封装Request与Response对象,提供常用的ServletAPI工具方法,并利用ThreadLocal技术来保证线程安全,代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class ServletHelper {private static final Logger LOGGER = LoggerFactory.getLogger(ServletHelper.class);/*** 使每个线程独自拥有一份ServletHelper实例*/private static final ThreadLocal<ServletHelper> SERVLET_HELPER_HOLDER = new ThreadLocal<ServletHelper>();private HttpServletRequest request;private HttpServletResponse response;public ServletHelper(HttpServletRequest request, HttpServletResponse response) {this.request = request;this.response = response;}/*** 初始化* @param request* @param response*/public static void init(HttpServletRequest request,HttpServletResponse response){SERVLET_HELPER_HOLDER.set(new ServletHelper(request,response));}/*** 销毁*/public static void destroy(){SERVLET_HELPER_HOLDER.remove();}/*** 获取Request对象* @return*/private static HttpServletRequest getRequest(){return SERVLET_HELPER_HOLDER.get().request;}/*** 获取Response对象* @return*/private static HttpServletResponse getResponse(){return SERVLET_HELPER_HOLDER.get().response;}/*** 获取Session对象* @return*/private static HttpSession getSession(){return getRequest().getSession();}/*** 获取ServletContext对象* @return*/private static ServletContext getContext(){return getRequest().getServletContext();}
}

最重要的就是init和destroy方法,我们需要在恰当的地方调用它们,哪里是最恰当的地方呢?当然是上面提到的DispatcherServlet的service方法。此外还提供了一系列私有的getter和setter方法,因为我们需要封装几个常用的Servlet API工具方法:

    /*** 将属性放入Request中* @param key* @param val*/public static void setRequestAttribute(String key,Object val){getRequest().setAttribute(key,val);}/*** 获取Request中的属性* @param key* @param <T>* @return*/public static <T> T getRequestAttribute(String key){return (T) getRequest().getAttribute(key);}/*** 从Request中移除属性* @param key*/public static void removeRequestAttribute(String key){getRequest().removeAttribute(key);}/*** 重定向* @param location*/public static void sendRedirect(String location){try {getResponse().sendRedirect(location);} catch (IOException e) {LOGGER.error("redirect failure",e);}}/*** 将属性放入Session中* @param key* @param val*/public static void setSessionAttribute(String key,Object val){getSession().setAttribute(key,val);}/*** 获取Session中的属性* @param key* @param <T>* @return*/public static <T> T getSessionAttribute(String key){return (T) getSession().getAttribute(key);}/*** 移除Session中的属性* @param key*/public static void removeSessionAttribute(String key){getSession().removeAttribute(key);}/*** 使Session失效*/public static void invalidateSession(){getSession().invalidate();}

以上这些工具方法都是可拓展的,只要是我们认为比较常用的都可以封装起来。

现在ServletHelper已经开发完毕,是时候将其整合到DispatcherServlet中并初始化Request与Response对象了,实际上就是调用init与destroy方法。

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletHelper.init(req,resp);   //使每个线程都有独立的request和responsetry {/****/}finally {ServletHelper.destroy();}}

现在就可以在Controller类中随时调用ServletHelper封装的Servlet API了:而且不仅仅可以在Controller类中调用,实际上在Service类中也是可以调用。因为所有调用都来自同一请求线程。DispatcherServlet是请求线程的入口,随后请求线程会先后来到Controller与Service中,我们只需要使用ThreadLocal来确保ServletHelper对象中的Request与Response对象线程安全即可。

代码

转载于:https://www.cnblogs.com/aeolian/p/10238434.html

架构探险笔记11-与Servlet API解耦相关推荐

  1. 8.ActionContext类与Servlet API解耦的访问方式

    为了避免与Servlet API耦合在一起,方便Action类做单元测试,   Struts2对HttpServletRequest.HttpSession和ServletContext进行了封装, ...

  2. 架构探险笔记10-框架优化之文件上传

    确定文件上传使用场景 通常情况下,我们可以通过一个form(表单)来上传文件,就以下面的"创建客户"为例来说明(对应的文件名是customer_create.jsp),需要提供一个 ...

  3. 架构探险笔记7-事务管理简介

    什么是事务 事务(Transaction)通俗的理解为一件事,要么做完,要么不做,不能做一半留一半.也就是说,事务必须是一个不可分割的整体,就像我们在化学课上学到的原子,原子是构成物质的最小单位.于是 ...

  4. 架构探险笔记5-使框架具备AOP特性(下)

    开发AOP框架 借鉴SpringAOP的风格,写一个基于切面注解的AOP框架.在进行下面的步骤之前,确保已经掌了动态代理技术. 定义切面注解 /*** 切面注解*/ @Target(ElementTy ...

  5. 使用Zookeeper实现服务注册中心-《架构探险-从零开始写分布式服务框架》读书笔记

    前言 最近在看<架构探险-从零开始写分布式服务框架>,对于分布式框架的入门级选手还是挺合适的,扫盲.对分布式服务框架中的基本概念:RPC.SOA.序列化.Spring集成RPC.ZooKe ...

  6. U3D笔记11:47 2016/11/30-15:15 2016/12/19

    U3D笔记11:47 2016/11/30-15:15 2016/12/19 技术BLOG:http://www.unity.5helpyou.com/2373.html#comment-43108 ...

  7. 阿里巴巴中台战略思想与架构实战笔记

    阿里巴巴中台战略思想与架构实战笔记 序言一 序言二 第一部分 引子 第1章 阿⾥巴巴集团中台战略引发的思考 1.1 阿⾥巴巴共享业务事业部的发展史 1.2 企业信息中心发展的症结 "烟囱式& ...

  8. 架构探险-轻量级微服务架构_第3部分-单活动架构+一些时髦的Dagger

    架构探险-轻量级微服务架构 This series takes a basic MVP app using Retrofit and RxJava to display a list of Githu ...

  9. 优酷 YouTube Twitter及JustinTV视频网站架构设计笔记

    本文是整理的关于优酷.YouTube.Twitter及JustinTV几个视频网站的架构或笔记,对于不管是视频网站.门户网站或者其它的网站,在架构上都有一定的参考意义,毕竟成功者的背后总有值得学习的地 ...

最新文章

  1. 甲骨文推出低成本高速公共与混合云方案,矛头直指AWS
  2. ABAP COMMIT WORK关键字在CRM content management应用里的使用场景
  3. HTML 父窗口打开子窗口,并从子窗口返回值
  4. 用Prime95来做linux下CPU压力测试
  5. java filterconfig_使用FilterConfig读取配置文件的信息 ---学习笔记
  6. Atitit.java expression fsm 表达式分词fsm引擎
  7. java模拟form表单提交图片文件
  8. 微机原理 寻址方式 及基于EMU8086的用例
  9. 贴片电阻的功率与封装对照表
  10. 百面机器学习(5)——非监督学习
  11. python将一个word文档中内容全部复制,添加到另一个word文档末
  12. 三星手机开发游戏工具 提升游戏体验
  13. 【jQuery】jQuery对象与prevObject
  14. 2021-07-19支付宝扫码点餐推广怎么做(干货来了)
  15. reporting services报表部署错误:运行配置文件中指定的扩展时出现异常。 ---> 超过了最大请求长度。
  16. 怎么写竞品分析报告(思路):
  17. Go 每日一库之 negroni
  18. linux里添加网卡,Linux添加虚拟网卡的多种方法
  19. 南邮 OJ 1055 叙拉古猜想
  20. mt6592android7,MT6592/MT6592M/MT6592T三版本性能对比

热门文章

  1. kafka分区和es的分区支持对比
  2. VB 一个API方式存取日志文件的模块
  3. 视频直接变漫画!GAN又有了新玩法 | Demo+代码+论文
  4. 史上首次无人车队集体婚礼,直男新郎给新娘の礼物:工业设计书
  5. 中国成全球第二AI医疗交易国,上半年AI制药融资数等于去年全年 | 报告
  6. 李开复发布新书《AI未来》,答技术大变革下的生存法则,LeCun纳德拉推荐
  7. 又是AI+IoT!谷歌试图收购物联网公司Xively
  8. 在哈佛的一场闭门会上,专家说全球各国都应设置“人工智能部长”
  9. “每天AI资讯这么多!该看哪些?”推荐一份优质资料清单
  10. Postgresql的一些命令