显然我想编写解耦的组件。其中一部分是表单引擎。我不希望它依赖于 servlet API,但我必须按请求(或至少按 session )初始化它。
在应用程序中我会使用类似的东西
public static void setLocale(Locale l);
然后我的各个类可以使用静态 getter 来获取它。这在 servlet 环境中是不可行的(servlet 甚至缺少可以模拟静态行为的static getServletContext()
方法)。
我绝对不想使用工厂(我将有 10 多个类,所有这些类都将使用一些配置,至少是 Locale)或者比这更糟糕:使用参数 block 构造每个对象(其中包含 Locale
和其他设置)。
我想知道在这种情况下最好的做法是什么。能否以可用的方式模拟静态行为,或者 servlet API 是否可以解决此问题?
如果所有其他可能性都失败了,我想到使用类似的东西:
class MyParameters {
private Map<Thread, MyParameters> threadParameters = new Map<Thread, MyParameters>();
public static void setParameters(MyParameters parameters) {
threadParameters.put(Thread.getCurrentThread(), parameters);
}
public static MyParameters getParameters() {
return threadParameters.get(Thread.getCurrentThread());
}
}
...但这会产生一些安全问题(servlet 可能无法初始化它并使用在同一线程处理的先前请求期间设置的值)。 - 尽管使用不同用户的区域设置并不是那么大的威胁。
最佳答案
but I have to inialize it per-request (or at least per-session).
使用 Filter
, HttpServlet
或 ServletRequestListener
(或 HttpSessionListener
)。
but this creates some security concerns
此外,线程由容器池化。对于不同的后续请求,可以多次重用同一个线程。当您在线程中放入某些内容并且在请求结束时未将其删除时,您最终会得到线程不安全的代码。
你最好的选择是创建一个 ThreadLocal<T>
类(class)。假设您希望它基于请求/响应,下面是一个启动示例:
public final class Context {
private static ThreadLocal<Context> instance = new ThreadLocal<Context>();
private HttpServletRequest request;
private HttpServletResponse response;
private Context(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
}
public static Context getInstance() {
return instance.get();
}
public static Context newInstance(HttpServletRequest request, HttpServletResponse response) {
Context context = new Context(request, response);
instance.set(context);
return context;
}
public void release() {
instance.remove();
}
// ...
}
获取并将其设置为 Filter
.
Context context = null;
try {
context = Context.newInstance(request, response);
chain.doFilter(request, response);
} finally {
if (context != null) context.release();
}
(请注意,在您获取的 finally
block 的 try
block 中释放上下文非常非常重要,否则无论何时它都不会被释放请求-响应处理抛出异常)
最后,您可以在代码中的任何位置获取它,如下所示:
Context context = Context.getInstance();
context.setLocale(locale);
Locale foo = context.getLocale();
// ...
其中您将方法委托(delegate)给本地 request
和/或 response
变量。
请注意,类似的构造已经存在于某些 MVC 框架中,例如 JSF 及其 FacesContext
。您不想自己种植,而是想看看那边的草是否更绿。
关于servlets - 如何在servlet环境中初始化API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5753913/