• Web开发小妙招:巧用ThreadLocal规避层层传值


    摘要:我们可以在处理每次请求的过程中,无需从Controller以及Service中的方法层层传值,只需要直接通过该局部变量取值即可。

    本文分享自华为云社区《拦截器中巧用ThreadLocal规避层层传值》,作者:KevinQ。

    Web开发中的一点麻烦事

    最近,准确地说,是一直都有的一点麻烦事:函数层层传递。什么意思呢?比如说有个很常见的需求描述是:记录用户的某次操作明细。

    以在Java的开源框架jfinal中,操作添加一个用户的接口为例,有:

    1. public class XXController() {
    2. public void addUser() {
    3. // 获取操作人
    4. Integer opUserId = Integer.parseInt(getHeader("opUserId"));
    5. // 获取其他参数...
    6. service.addUser(...., opUserId);
    7. renderAppMsg("添加用户成功");
    8. }
    9. }

    为了记录用户添加的具体操作内容以及信息错误,这个记录用户操作的记录可能需要穿透好层方法。

    1. public class XXService() {
    2. public void addUser(String tel, String name, String password, Integer opUserId) {
    3. checkTel(tel, opUserId);
    4. checkName(name, opUserId);
    5. checkPassword(password, opUserId);
    6. }
    7. public void checkTel(String tel, Integer opUserId) {
    8. check(tel, opUserId);
    9. }
    10. publc void check(..., Integer opUserId) {
    11. // ...
    12. }
    13. }

    举得这个例子或许不是很恰当,但是相信大家可以理解这个麻烦点在哪里。

    函数调用链中的每个方法并不是需要这个参数,而可能仅仅是为了向下个被调用的函数传递这个参数。

    那么是否有方法帮助我们来不需要这样逐层传递,从而获取接口请求参数的方法呢。

    思考

    这有点类似与一个全局变量,但是这个变量对每次请求来说是变化的,那么是否有一种方式能够让我们来保存这样一种:针对每次请求的全局变量呢?

    在最近学习Shiro的过程中,以及学习若依开源框架的过程中,我们发现其均使用到了一个强大的Java类:ThreadLocal。

    shiro使用ThreadLocal是用来保存当前登录对象,若依框架中,其中所使用的分页插件PageUtil使用ThreadLocal保存请求参数中的pageNum与pageSize等分页参数。因此我们是不是也可以使用ThreadLocal来达到同样的目的。

    在拦截器中使用ThreadLocal暂存请求参数

    为此,我们来尝试一下,通过ThreadLocal保存请求参数,通过拦截器我们可以拦截每次请求,如下是实现方式:

    1. package com.holdoa.core.interceptor;
    2. import com.jfinal.aop.Interceptor;
    3. import com.jfinal.aop.Invocation;
    4. import javax.servlet.http.HttpServletRequest;
    5. public class RequestPool implements Interceptor {
    6. public static ThreadLocal<HttpServletRequest> localRequest= new ThreadLocal<>();
    7. @Override
    8. public void intercept(Invocation inv) {
    9. localRequest.set(inv.getController().getRequest());
    10. inv.invoke();
    11. localRequest.remove();
    12. }
    13. public static HttpServletRequest getRequest() {
    14. return localRequest.get();
    15. }
    16. }

    我们通过ThreadLocal将整个请求暂存起来,当然,为了节约内存,也可以只保存使用频次高的通用参数,比如当前登录人的信息等等。

    使用参数

    使用时,只需要我们通过这个线程局部变量取值即可:

    String para = RequestPool.localRequest.get().getParameter("username");

    如此,我们便可以在处理每次请求的过程中,无需从Controller以及Service中的方法层层传值,只需要直接通过该局部变量取值即可。

    点击关注,第一时间了解华为云新鲜技术~

  • 相关阅读:
    Java Cannot deserialize instance of `xxx` out of START_ARRAY token错误分析及解决
    【数据结构与算法】<==>栈和队列的OJ题
    蓝牙耳机学生党推荐,性价比高的学生党蓝牙耳机推荐
    hal开发之hidl/aidl支持的绑定式直通式详细讲解
    PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本
    强化学习-task2
    22 年最全面试java八股文合集
    IC刷卡数据如何获取?5个渠道的IC刷卡数据免费下载~
    iptables使用详解(centos7)
    spring-boot-starter-security的简单使用
  • 原文地址:https://blog.csdn.net/devcloud/article/details/125634840