对于我的应用程序,我必须将某些信息携带到应用程序的每一层(一个示例可能是为传入请求生成的唯一事务ID)。
所以,我打算创建一个引用ThreadLocal<ConcurrentMap<String, Object>>
的类。
感谢有人可以提供帮助;我有一个混乱,出于以下方法,哪个更好:
1。具有静态方法的AppContext.java
public final class AppContext {
private static final ThreadLocal<ConcurrentMap<String, Object>> context = new ThreadLocal<>();
public static void set(final String key, final Object value) {
// set key value in thread local
}
public static Object get(final String key) {
// get value from thread local
}
}
2。具有非静态方法的AppContext.java
public final class AppContext {
private static final ThreadLocal<ConcurrentMap<String, Object>> context = new ThreadLocal<>();
public void set(final String key, final Object value) {
// set key value in thread local
}
public Object get(final String key) {
// get value from thread local
}
}
答案 0 :(得分:7)
尽管其他人可能会说,ThreadLocal变量本身并不是邪恶的,它们在使用时只需要一点额外的关心和理解。线程安全并不真正相关,因为它们固有地绑定到一个线程。当这些线程可能被应用程序的其他不同用户重用时,就会引起关注。在基于Java的Web应用程序中,情况就是如此;但是,您一次只能依靠该线程上的一个用户/请求。非常重要的一步是确保在每个请求结束时清理ThreadLocal对象。
因此,为了避免不必要地为每个请求实例化新的上下文,我建议创建多个静态类型安全的ThreadLocal对象,所有这些对象都存在于“上下文”类中,其中这些对象以某种方式相关。您可以使用多个上下文类来组织这些上下文项的各种组。
然而,根据ThreadLocal评论家的精神,我同意ThreadLocals应该稍微谨慎使用,过度使用可能会产生代码味道。
以下是上述方法的一个例子。
“上下文”类。
public class LogContext {
private static ThreadLocal<String> localCorrelationId = new ThreadLocal<String>();
private static ThreadLocal<String> localUserId = new ThreadLocal<String>();
public static String getCorrelationId() {
return localCorrelationId.get();
}
public static void setCorrelationId(String correlationId) {
localCorrelationId.set(correlationId);
}
public static String getUserId() {
return localUserId.get();
}
public static void setUserId(String userId) {
localUserId.set(userId);
}
public static void cleanup() {
localCorrelationId.remove();
localUserId.remove();
}
}
通过Servlet过滤器管理上下文
@WebFilter(filterName = "LogContextFilter", urlPatterns = {"/*"})
public class LogContextFilter implements Filter {
public void init(FilterConfig filterConfig) {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
try {
LogContext.setCorrelationId(UUID.randomUUID().toString());
chain.doFilter(request, response);
} catch (Throwable t) {
t.printStackTrace();
} finally {
//This is critical!
LogContext.cleanup();
}
}
public void destroy() {
}
}
访问上下文(例如,来自Servlet)
@WebServlet(name = "SimpleServlet", urlPatterns = {"/SimpleServlet"})
public class SimpleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String correlationId = LogContext.getCorrelationId();
}
}
答案 1 :(得分:1)
如果AppContext
是单身,那么静态方法是最好的方法。如果有多个AppContext
,那么您应该使这些方法是非静态的。
答案 2 :(得分:-1)
没有最好的方法来使用ThreadLocal。把它想象成“全局变量”,一切都是消极的。 ThreadLocal是地球上的一个痘。你的应用程序中的癌症,总有一天会消耗你。不惜一切代价避免它。学习如何传递适当的不可变状态,让你的线程难题消失。