您的位置:首页 > 运维架构 > 网站架构

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

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

在编写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> {
}

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

ThreadLocal的存储类型改为Map,这样就可以储存多个变量了

增加了clear方法,在过滤器的前后执行,及时释放资源,同时避免线程池的数据污染

引入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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息