自用日志中ThreadLocal的使用

title: 自用日志中ThreadLocal的使用 date: 2017.04.15 23:07 categories:

  • 技术博客 tags:
  • 实现方式
  • 日志

接到一个技术类需求,碰到了几个比较有意思的点。

主需求:实现自用的日志记录

基本思路:新增一张systemlog表用于存放数据,利用AOP的思想截获用户的操作行为,增强类中处理具体的操作数据,存入log表,实现分下面两步。

1. 配置增强类AOP

  • bean的配置
  • AOP的配置(切点,增强 | 通知,切面)

2. 增强类实现

  • 该类的作用定位为工具,因此命名为LogUtil,放入util包中(遵循规范)。
  • 业务代码

重点是ThreadLocal相关

这次的需求让我回想到了之前关于session的几个点,原因是思路有些重合,看回这个需求,日志的记录要求用户的每次交互都作为数据存入log表,其中表字段设计时需要存入用户对象信息,一见这样的模式就要想到session,可是session无法直接获取,因而需要一个中间层来处理他,这一次就用到了ThreadLocal。

设想一下:用户进入web,每次操作都通过一个触发点将单次请求存起来,每一次的获取我使用拦截器来实现(以后再聊),而放请求这个动作就需要了解Thread的两个小伙伴。

ThreadLocal是与线程绑定的,可以完成这样的需求(log表中记录登录用户)。 核心类:

  • Thread:表示线程对象
  • ThreadLocal:线程通过该类拷贝进行存值的操作
  • ThreadLocalMap:线程自带的容器类,类似Map但有区别,当下没必要纠结其细节

看看JDK1.8源码:

  • ThreadLocal中的get
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
复制代码

原英文注释写的很清楚了:该方法返回当前线程中local变量的副本。

  • ThreadLocal中的set
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
复制代码

作用:将传入的value放入线程中的map。

  • ThreadLocalMap中的set
 private void set(ThreadLocal<?> key, Object value) {...}
复制代码

作用:将调用该方法的local变量作为key,传入的值作为value放入自定义的map结构中。

关于ThreadLocal的分析网上有很多,今天我不聊过多,说一个思路吧:看源码的时候要学会简化,比如尽可能去抓源码中关键的地方,必要时候配合画类图+脑图的方式,我把类结构简单拿了一下:

因此到这里,我可以试着实现前面的思路,在SharedContext共用类中添加ThreadLocal成员与静态方法,用于完成对request的存取:

public static ThreadLocal<HttpServletRequest> local=new ThreadLocal();//本地线程变量

public static void setReq(HttpServletRequest req){
	local.set(req);//将请求存到那个map中
}
public static HttpServletRequest getReq(){
	return local.get();//拿出来
}
复制代码

到了LogUtil中业务代码(记录日志功能),我们就可以通过SharedContext共用类获取到当前请求对象(本次是获取session然后拿到user数据),而在取之前要根据自家业务需求在对应的地方存入请求,SharedContext是共用静态的,所以伸缩性很强。

到这里,这个需求的重点之一已经完成了。

小结

  • 思路要清晰
  • 设计好了就去尝试
  • 出问题有很多解决方案(前人的经验)
  • 看源码也有技巧(光能读英语还不够)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值