Mybatis-plus 可以实现字段自动填充功能,我通常会把多个表中共同字段抽离到了一个公共实体类中,如创建时间,创建人员,更新时间,更新人员等等,但是如何获取当前用户信息填入创建人员,更新人员字段?
ThreadLocal可以帮助我解决这个问题,我使用的的是JWT token 验证登陆状态,在每次Http请求时Header都会附带token,token中就会附带用户信息,当我们验证完后把用户信息set进Threadlocal,就可以在同一个线程中通过ThreadLocal获取用户信息。
ThreadLocal理解
ThreadLocal是线程安全的,它可以确保多线程访问时每个线程只能访问到自己的线程私有变量。它的线程隔离机制是通过把共享变量的副本存储到Thread.threadLocals实现,每个线程只能访问自己的副本,就能避免线程安全问题。
ThreadLocal实际上就是一个操作Thread.threadLocals的外壳。Thread.threadLocals变量是一个keyvalueMap,Thread创建的时候默认初始化threadLocals为null,在ThreadLocal首次读或写的时候初始化threadLocals。ThreadLocalMap是ThreadLocal中的静态内部类,ThreadLocalMap通过Entry键值对的方式存储数据,是一个定制化的Map。
ThreadLocal源码分析
set()
1 2 3 4 5 6 7 8 9 10 11 12
| public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
|
我们可以发现ThreadLocal set的方法是对Thread.threadLocals这个定制化的Map进行操作
getMap()
1 2 3 4
| ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
|
createMap()
1 2 3 4
| void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
|
get()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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(); }
|
setInitialValue()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
protected T initialValue() { return null; }
|
remove()
1 2 3 4 5 6 7
| public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
|