public abstract class ThreadContext { /** * Private internal log instance. */ private static final Logger log = LoggerFactory.getLogger(ThreadContext.class); public static final String SECURITY_MANAGER_KEY = ThreadContext.class.getName() + "_SECURITY_MANAGER_KEY"; public static final String SUBJECT_KEY = ThreadContext.class.getName() + "_SUBJECT_KEY"; private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>(); protected ThreadContext() { } public static Map<Object, Object> getResources() { return resources != null ? new HashMap<Object, Object>(resources.get()) : null; } public static void setResources(Map<Object, Object> newResources) { if (CollectionUtils.isEmpty(newResources)) { return; } resources.get().clear(); resources.get().putAll(newResources); } private static Object getValue(Object key) { return resources.get().get(key); } public static Object get(Object key) { if (log.isTraceEnabled()) { String msg = "get() - in thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } Object value = getValue(key); if ((value != null) && log.isTraceEnabled()) { String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } return value; } public static void put(Object key, Object value) { if (key == null) { throw new IllegalArgumentException("key cannot be null"); } if (value == null) { remove(key); return; } resources.get().put(key, value); if (log.isTraceEnabled()) { String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + key + "] to thread " + "[" + Thread.currentThread().getName() + "]"; log.trace(msg); } } public static Object remove(Object key) { Object value = resources.get().remove(key); if ((value != null) && log.isTraceEnabled()) { String msg = "Removed value of type [" + value.getClass().getName() + "] for key [" + key + "]" + "from thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } return value; } public static void remove() { resources.remove(); } public static SecurityManager getSecurityManager() { return (SecurityManager) get(SECURITY_MANAGER_KEY); } public static void bind(SecurityManager securityManager) { if (securityManager != null) { put(SECURITY_MANAGER_KEY, securityManager); } } public static SecurityManager unbindSecurityManager() { return (SecurityManager) remove(SECURITY_MANAGER_KEY); } public static Subject getSubject() { return (Subject) get(SUBJECT_KEY); } public static void bind(Subject subject) { if (subject != null) { put(SUBJECT_KEY, subject); } } public static Subject unbindSubject() { return (Subject) remove(SUBJECT_KEY); } private static final class InheritableThreadLocalMap<T extends Map<Object, Object>> extends InheritableThreadLocal<Map<Object, Object>> { protected Map<Object, Object> initialValue() { return new HashMap<Object, Object>(); } @SuppressWarnings({"unchecked"}) protected Map<Object, Object> childValue(Map<Object, Object> parentValue) { if (parentValue != null) { return (Map<Object, Object>) ((HashMap<Object, Object>) parentValue).clone(); } else { return null; } } } }
公司现有的项目中要求具有登录校验工作,很多人提起shiro以及spring security等众多框架,不是说框架不好,只是个人感觉很多内容并不是很需要框架去依赖,反倒失去独立思考的能力,就比如说很多人总是说dubbo,其实看了dubbo的实现,并没有让我很惊艳的地方,完全可以使用netty的方式写一个。
今天我就把shiro中的ThreadContext的改造下,其实equest过来后,我们只需解决通过filter拦截请求是否有验证过就足矣,那要尽可能多接受请求,通过这些出发点后,最原始的肯定是能够接受最方便的。
ThreadLocal作为线程副本很好的解决线程之间的独立性,通过TL能够保证存储线程的变量,虽然可能是使用不到造成memory leadking,实际上因为线程副本的变量存储空间跟线程本身并不是同个生命周期,那就要小心在线程销毁的时候,记得ThreadLocal的remove掉。
结论:
其实很多开源框架并不一定全部适合所有场景,而且很多开源框架本身存在诸多问题,在并不能完全控制住的情况下,很容易产生杂七杂八的难以解决的问题。