设计一个自定义的系统上下文

1,724

这是一个自定义的系统上下文demo,如有不足和遗漏之处,欢迎指出交流~

package com.xxx.lcloud.common.context;

import com.alibaba.ttl.TransmittableThreadLocal;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @ClassName: CustomContext
 * @Desc: 自定义上下文
 * @author: Gift
 * @date: 2020年05月22日
 */

public class CustomContext{

    // 存储当前上下文ID
    private static final TransmittableThreadLocal<String> CURRENT_CTXID_LOCAL = new TransmittableThreadLocal<>();
    // 上下文ID生成器
    private static final AtomicLong CTXID_CREATER = new AtomicLong();
    // 上下文池
    private static final Map<String, CustomContextBean> CONTEXT_BEAN_POOL = new ConcurrentHashMap<>();
    // 自定义Map缓存
    private static Map<String, Map<String, Object>> CONTEXT_CACHE_MAP = new ConcurrentHashMap<>();
    // 线程唯一标识与上下文ID的映射表
    private static final Map<String, String> CTXID_INHERITED_TABLE = new ConcurrentHashMap<>();


    public static CustomContextBean init() {
        String ctxId = CURRENT_CTXID_LOCAL.get();
        if (ctxId != null) {
            return CONTEXT_BEAN_POOL.get(ctxId);
        } else {
            //这个对象作为我们在存储一些常用的值,如上下文中的流水号,或者贯穿整个业务流程的字段
            CustomContextBean customContextBean = new CustomContextBean ();
            ctxId = currentCtxID();
            CURRENT_CTXID_LOCAL.set(ctxId);
            CONTEXT_BEAN_POOL.put(ctxId, customContextBean);
            CONTEXT_CACHE_MAP.put(ctxId, new ConcurrentHashMap<>());
            return customContextBean ;
        }
    }

    /**
     * 获取当前上下文对象
     *
     * @return
     */
    public static ThreadLocal<String> getContext() {
        return CURRENT_CTXID_LOCAL;
    }

    /**
     * 获取当前上下文业务字段Bean
     *
     * @return
     */
    public static CustomContextBean getContextBean() {
        return CONTEXT_BEAN_POOL.get(ctxId());
    }

    /**
     * 获取当前上下文CTXID
     * @return
     */
    public static String currentCtxID() {
        String ctxID = CURRENT_CTXID_LOCAL.get();
        if (ctxID == null) {
            ctxID = CTXID_INHERITED_TABLE.get(assembleSubThreadID());
            if (ctxID == null) { 
                ctxID = String.valueOf(nextCtxID());
                CURRENT_CTXID_LOCAL.set(ctxID);
            }
        }
        return ctxID;
    }

    /**
     * 组装子线程唯一标识
     * @return
     */
    private static String assembleSubThreadID() {
        return String.valueOf(Thread.currentThread().getId());
    }


    /**
     * 生成上下文ID
     * @return
     */
    private static long nextCtxID() {
        long ctxID = CTXID_CREATER.incrementAndGet();
        if (CTXID_CREATER.compareAndSet(Long.MAX_VALUE, 0)) {
            LoggerUtil.info("上下文CTXID 即将超过Long.MAX_VALUE, 下一个上下文CTXID将从[1]开始!" ,ctxID ,Long.MAX_VALUE );
        }
        return ctxID;
    }
        /**
       * 获取上下文缓存的map
       *
       * @return
       */
    public static Map<String, Object> getContextCache() {
        return CONTEXT_CACHE_MAP.get(ctxId());
    }

    /**
     * 释放上下文空间
     */
    public static void release() {
        String cid = ctxId();
        // 移除上下文通用Bean
        CONTEXT_BEAN_POOL.remove(cid);
        // 移除上下临时Map值
        CONTEXT_CACHE_MAP.remove(cid);
        // 移除线程变量
        CURRENT_CTXID_LOCAL.remove();
    }

    /**
     * 获取上下文Id
     *
     * @return
     */
    public static String ctxId() {
        String ctxId = CURRENT_CTXID_LOCAL.get();
        if (ctxId == null) {
            ctxId = CTXID_INHERITED_TABLE.get(Thread.currentThread().getName());
        }
        return ctxId;
    }



    /**
     * 添加自定义缓存值
     *
     * @param key
     * @param object
     */
    public static void setCache(String key, Object object) {
        Map<String, Object> cache = getContextCache();
        if (cache != null) {
            cache.put(key, object);
        }
    }

    /**
     * 获取自定义缓存值
     *
     * @param key
     * @return
     */
    public static Object getCache(String key) {
        Map<String, Object> cache = getContextCache();
        return cache == null ? null : getContextCache().get(key);
    }