Servlets 如何在servlet环境中初始化API

Servlets 如何在servlet环境中初始化API,servlets,Servlets,显然,我想编写解耦组件。一部分是表单引擎。我不希望它依赖于ServletAPI,但我必须根据每个请求(或至少每个会话)将其初始化 在应用程序中,我会使用 public static void setLocale(Locale l); 然后我的各个类可以通过静态getter获得它。这在servlet环境中是不可行的(servlet甚至缺少一个静态getServletContext()方法,通过该方法可以模拟静态行为) 我绝对不想使用factory(我将有10多个类,所有这些类都将使用一些配置,至

显然,我想编写解耦组件。一部分是表单引擎。我不希望它依赖于ServletAPI,但我必须根据每个请求(或至少每个会话)将其初始化

在应用程序中,我会使用

public static void setLocale(Locale l);
然后我的各个类可以通过静态getter获得它。这在servlet环境中是不可行的(servlet甚至缺少一个
静态getServletContext()
方法,通过该方法可以模拟静态行为)

我绝对不想使用factory(我将有10多个类,所有这些类都将使用一些配置,至少是区域设置)或更糟糕的:使用参数块构造每个对象(其中包含
Locale
和其他设置)

我想知道在这种情况下最好的做法是什么。静态行为可以用一种可用的方式进行模拟,还是ServletAPI可以解决这个问题

如果其他方法都失败了,我会考虑使用以下方法:

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());
    }    
}
类参数{
私有映射threadParameters=新映射();
公共静态void setParameters(MyParameters){
threadParameters.put(Thread.getCurrentThread(),parameters);
}
公共静态MyParameters getParameters(){
返回threadParameters.get(Thread.getCurrentThread());
}    
}
。。。但这会产生一些安全问题(servlet可能无法初始化它,并且无法使用在同一线程服务的前一个请求期间设置的值)。-尽管使用不同用户的区域设置并不是一种威胁

但我必须根据每个请求(或至少每个会话)将其最小化

使用,或(或)

但这造成了一些安全问题

此外,线程由容器池化。对于不同的后续请求,同一个线程可以重复使用多次。当您在线程中放入某些内容,但在请求结束时没有将其删除时,您将得到线程不安全的代码

最好是创建一个
ThreadLocal
类。假设您希望它基于请求/响应,下面是一个启动示例:

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();
    }

    // ...
}
(请注意,在获取上下文的
try
块的
finally
块中释放上下文非常重要,否则在请求-响应处理引发异常时不会释放上下文)

最后,您可以在代码中的任何地方获得它,如下所示:

Context context = Context.getInstance();
context.setLocale(locale); 
Locale foo = context.getLocale();
// ...
其中,您将方法委托给本地
请求
和/或
响应
变量


注意,类似的构造已经存在于一些MVC框架中,比如JSF及其组件。你可以看看草坪是否比这里更绿,而你也可以考虑使用我在这里讨论的方法:


在我的方法中,请求和响应对象存储在JNI中,而不是存储在ThreadLocal中。除此之外,它们的设置和清理是在一个过滤器中完成的,就像上面的方法一样…

谢谢!当然,我的
MyParameters
示例可以通过单个请求工作,我没有假设线程在整个会话中都是常量。我写的是:“我没有假设线程在整个会话中都是常量”还有一个问题:这是一种普遍使用的做法还是有一种特殊的设计来解决这个问题?在使用threadlocal上下文的MVC框架中,如JSF、Spring MVC、Wicket等,是的,这是实现它的一般方式。您必须非常小心,如代码示例中所示,最终应在
中释放上下文,否则将导致严重的线程安全问题。这里应用的唯一设计模式是facade模式。如果不公开返回“原始”请求/响应的方法,则本例中的
上下文基本上是一个facade。您应该只提供委托给它们的方法。
Context context = Context.getInstance();
context.setLocale(locale); 
Locale foo = context.getLocale();
// ...