架构探险笔记11-与Servlet API解耦
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解耦相关推荐
- 8.ActionContext类与Servlet API解耦的访问方式
为了避免与Servlet API耦合在一起,方便Action类做单元测试, Struts2对HttpServletRequest.HttpSession和ServletContext进行了封装, ...
- 架构探险笔记10-框架优化之文件上传
确定文件上传使用场景 通常情况下,我们可以通过一个form(表单)来上传文件,就以下面的"创建客户"为例来说明(对应的文件名是customer_create.jsp),需要提供一个 ...
- 架构探险笔记7-事务管理简介
什么是事务 事务(Transaction)通俗的理解为一件事,要么做完,要么不做,不能做一半留一半.也就是说,事务必须是一个不可分割的整体,就像我们在化学课上学到的原子,原子是构成物质的最小单位.于是 ...
- 架构探险笔记5-使框架具备AOP特性(下)
开发AOP框架 借鉴SpringAOP的风格,写一个基于切面注解的AOP框架.在进行下面的步骤之前,确保已经掌了动态代理技术. 定义切面注解 /*** 切面注解*/ @Target(ElementTy ...
- 使用Zookeeper实现服务注册中心-《架构探险-从零开始写分布式服务框架》读书笔记
前言 最近在看<架构探险-从零开始写分布式服务框架>,对于分布式框架的入门级选手还是挺合适的,扫盲.对分布式服务框架中的基本概念:RPC.SOA.序列化.Spring集成RPC.ZooKe ...
- 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 ...
- 阿里巴巴中台战略思想与架构实战笔记
阿里巴巴中台战略思想与架构实战笔记 序言一 序言二 第一部分 引子 第1章 阿⾥巴巴集团中台战略引发的思考 1.1 阿⾥巴巴共享业务事业部的发展史 1.2 企业信息中心发展的症结 "烟囱式& ...
- 架构探险-轻量级微服务架构_第3部分-单活动架构+一些时髦的Dagger
架构探险-轻量级微服务架构 This series takes a basic MVP app using Retrofit and RxJava to display a list of Githu ...
- 优酷 YouTube Twitter及JustinTV视频网站架构设计笔记
本文是整理的关于优酷.YouTube.Twitter及JustinTV几个视频网站的架构或笔记,对于不管是视频网站.门户网站或者其它的网站,在架构上都有一定的参考意义,毕竟成功者的背后总有值得学习的地 ...
最新文章
- 甲骨文推出低成本高速公共与混合云方案,矛头直指AWS
- ABAP COMMIT WORK关键字在CRM content management应用里的使用场景
- HTML 父窗口打开子窗口,并从子窗口返回值
- 用Prime95来做linux下CPU压力测试
- java filterconfig_使用FilterConfig读取配置文件的信息 ---学习笔记
- Atitit.java expression fsm 表达式分词fsm引擎
- java模拟form表单提交图片文件
- 微机原理 寻址方式 及基于EMU8086的用例
- 贴片电阻的功率与封装对照表
- 百面机器学习(5)——非监督学习
- python将一个word文档中内容全部复制,添加到另一个word文档末
- 三星手机开发游戏工具 提升游戏体验
- 【jQuery】jQuery对象与prevObject
- 2021-07-19支付宝扫码点餐推广怎么做(干货来了)
- reporting services报表部署错误:运行配置文件中指定的扩展时出现异常。 ---> 超过了最大请求长度。
- 怎么写竞品分析报告(思路):
- Go 每日一库之 negroni
- linux里添加网卡,Linux添加虚拟网卡的多种方法
- 南邮 OJ 1055 叙拉古猜想
- mt6592android7,MT6592/MT6592M/MT6592T三版本性能对比
热门文章
- kafka分区和es的分区支持对比
- VB 一个API方式存取日志文件的模块
- 视频直接变漫画!GAN又有了新玩法 | Demo+代码+论文
- 史上首次无人车队集体婚礼,直男新郎给新娘の礼物:工业设计书
- 中国成全球第二AI医疗交易国,上半年AI制药融资数等于去年全年 | 报告
- 李开复发布新书《AI未来》,答技术大变革下的生存法则,LeCun纳德拉推荐
- 又是AI+IoT!谷歌试图收购物联网公司Xively
- 在哈佛的一场闭门会上,专家说全球各国都应设置“人工智能部长”
- “每天AI资讯这么多!该看哪些?”推荐一份优质资料清单
- Postgresql的一些命令