ThreadLocal(三) 线程上下文实战

 场景: 某个复杂长链路请求, 例如下单, 需要多组件方法参与,但是对于各种参数聚合, 耦合度很高对于二次开发不方便

解决思路: 利用 ThreadLocal 线程变量来完成, 以后每次改造只需要改造,或者向 ThreadLocal 中增加自己的参数即可,

注意:

  1. 禁止参与多线程!!!否则会导致参数丢失!!!!!
  2. 注意每个线程必须执行 destroy 操作!!!
  3. 建议在入口处进行线程变量初始化和销毁

1. 创建业务上下文类

package net.xinhuamm.converge.model.common;

import lombok.Data;
import net.xinhuamm.converge.bean.news.ConvergeNewsInsertRequest;
import net.xinhuamm.converge.bean.news.ConvergeNewsPushRequest;
import net.xinhuamm.gusteau.usercenter.model.response.admin.AdminContextResponse;

/**
 * Description: 业务上下文, 里面有业务配置参数,以及环境变量等
 * User: zhouzhou
 * Date: 2019-04-15
 * Time: 14:53
 */
@Data
public class BizContext {
    /**
     * 当前系统环境
     */
    private String systemEnv;
    /**
     * 当前租户id,可为空看当时场景定
     */
    private Long tenantId;

    /**
     * 当前租户信息
     */
    private AdminContextResponse tenantInfo;

    /**
     * 录入请求
     */
    private ConvergeNewsInsertRequest convergeNewsInsertRequest;



}

2. 创建 ThreadLocal 线程变量类

package net.xinhuamm.converge.model.common;


import net.xinhuamm.converge.util.SpringContextUtil;

/**
 * Description:业务会话
 * User: zhouzhou
 * Date: 2019-01-15
 * Time: 14:54
 */
public class BizSession {

    // 初始化
    private static ThreadLocal<BizContext> INSTANCE = new ThreadLocal<BizContext>(){
        @Override
        protected BizContext initialValue() {
            BizContext context = new BizContext();
            if (SpringContextUtil.isTestEnv()){
                context.setSystemEnv("test");
            }
            return context;
        }
    };

    /**
     * 获取当前对象实例
     * @return
     */
    public static BizContext currentSession(){
        return INSTANCE.get();
    }

    /**
     * 创建会话
     * @param bizContext
     */
    public static void store(BizContext bizContext){
        INSTANCE.set(bizContext);
    }

    public static void destroy(){
        INSTANCE.remove();
    }
}

 3. 线程变量的初始化与销毁, 这边是在拦截器使用的初始化和销毁

package net.xinhuamm.converge.interceptor;

import net.xinhuamm.converge.model.common.BizContext;
import net.xinhuamm.converge.model.common.BizSession;
import net.xinhuamm.converge.util.SpringContextUtil;
import net.xinhuamm.gusteau.usercenter.model.response.admin.AdminContextResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Description:租户切面
 * User: zhouzhou
 * Date: 2020-05-19
 * Time: 2:45 PM
 *
 * @author zhouzhou
 */
@Component
public class TenantInterceptor implements HandlerInterceptor {




    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (response.getStatus() == 404 || response.getStatus() == 500) {
            return true;
        }
        BizContext bizContext = BizSession.currentSession();

        // 获取用户 token
        if (SpringContextUtil.isLocal()){
            AdminContextResponse info = new AdminContextResponse();
            info.setCurrentTenantId(1L);
            info.setRealName("张三");
            bizContext.setTenantInfo(info);
        }else{
            // ResultModel<AdminContextResponse> tokenModel = iUserCenterApiService.getUserByToken();
            // if (tokenModel.getCode() != 0 || tokenModel.getData() == null) {
            //     return false;
            // }
            // bizContext.setTenantInfo(tokenModel.getData());
            // bizContext.setTenantId(tokenModel.getData().getCurrentTenantId());
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // ignore
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        BizSession.destroy();
    }
}

 4. 如何在组件中获取和更新线程变量呢?

       // 统计记录日志
            ConvergeNewsOperateLogDTO logDTO = new ConvergeNewsOperateLogDTO();
            logDTO.setDescription(operateRequest.getDescription());
            logDTO.setNewsId(newsId);
            logDTO.setOperateType(operateType);
            logDTO.setOperator(BizSession.currentSession().getTenantInfo().getRealName());
            logService.insert(logDTO);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值