Web应用同一线程内不同架构层次的数据共享

在编写java web应用的Service 层代码时,常常需要根据当前会话用户查询相关的数据,而用户信息一般都是放在 HttpSession中,那么问题来了,如何在 Service层获取会话用户?

简单的做法是在 Contrller 层获取会话用户,然后通过参数传递给 Service。那么问题又来了,Service 方法那么多,这种做法太繁琐了,有没有优雅一点的办法?

稍有点经验的大概都知道可以用 ThreadLocal 解决,没错,就是她了,先上代码:

public class ThreadContext {

	private static final ThreadLocal<LoginUser> loginUserThreadLocal = new ThreadLocal<LoginUser>();

	public static void setLoginUser(LoginUser loginUser) {
		loginUserThreadLocal.set(loginUser);
	}

	public static LoginUser getLoginUser() {
		return loginUserThreadLocal.get();
	}

}

这个 ThreadContext 再配合加一个 Servlet Filter,由 Filter 事先把会话用户放到线程变量里,这样在后续的Controller、Service 甚至是自定义的JSP标签与函数库都可以轻松获取到会话用户信息了,会话用户信息共享的问题至此已解决!

会话用户信息共享只是数据共享的一个方面,在实际的应用中,肯定还有其他数据是需要在线程内共享的,那么我们可以对ThreadContext类进行扩展,代码如下:

public class ThreadContext {

	private static final ThreadLocal<Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>>> contextThreadLocal = new ThreadLocal<Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>>>();
	
	public static final void clear() {
		contextThreadLocal.remove();
	}
	
	@SuppressWarnings("unchecked")
	protected static final void set(ObjectWrapper<?> wrapper) {
		Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>> context = contextThreadLocal.get();
		if (context == null) {
			context = new HashMap<Class<ObjectWrapper<?>>, ObjectWrapper<?>>();
			contextThreadLocal.set(context);
		}
		context.put((Class<ObjectWrapper<?>>) wrapper.getClass(), wrapper);
	}

	@SuppressWarnings("unchecked")
	protected static final <T> T get(Class<? extends ObjectWrapper<? extends T>> wrapperClass) {
		Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>> cache = contextThreadLocal.get();
		if (cache == null) {
			return null;
		}
		ObjectWrapper<T> wrapper = (ObjectWrapper<T>) cache.get(wrapperClass);
		return wrapper == null ? null : wrapper.getObj();
	}

}
public abstract class ObjectWrapper<T> {

	private T obj;

	public ObjectWrapper<T> wrap(T obj) {
		this.obj = obj;
		return this;
	}

	T getObj() {
		return obj;
	}

}
public class LoginUserWrapper extends ObjectWrapper<LoginUser> {
}

public class MyObjectWrapper extends ObjectWrapper<MyObject> {
}

以上代码,改进的内容如下:

  1. ThreadLocal的存储类型改为Map,这样就可以储存多个变量了
  2. 增加了clear方法,在过滤器的前后执行,及时释放资源,同时避免线程池的数据污染
  3. 引入ObjectWrapper,利用泛型机制自动转型

设置时,调用:
ThreadContext.set(new LoginUserWrapper().warp(loginUser));
ThreadContext.set(new MyObjectWrapper().warp(MyObject));

读取时,调用:
LoginUser loginUser = ThreadContext.get(LoginUserWrapper.class);
MyObject myObject = ThreadContext.get(MyObjectWrapper.class);

具体实现可以参考项目:http://git.oschina.net/jlin/delonix

ThreadContext 类:
http://git.oschina.net/jlin/delonix/blob/master/delonix-core/src/main/java/net/gazhi/delonix/core/thread/ThreadContext.java

ResetThreadContextFilter 类:
http://git.oschina.net/jlin/delonix/blob/master/delonix-core/src/main/java/net/gazhi/delonix/core/web/ResetThreadContextFilter.java

你可能感兴趣的:(java,多线程,mvc,threadLocal,filter,数据共享,会话用户)