2011-04-22 60 views
2

显然我想编写解耦组件。一部分是表单引擎。我不希望它依赖于servlet API,但我必须按请求(或至少每个会话)初始化它。如何在Servlet环境中初始化一个API

在一个应用程序,我会使用类似

public static void setLocale(Locale l); 

那么我个人类可以用静态的getter得到它。这在servlet环境中是不可行的(servlet甚至缺乏可模拟静态行为的方法)。

我绝对不想使用工厂(我将有10多个类,所有这些类都将使用一些配置,至少是Locale)或者比这更糟糕:使用参数块构建每个对象(其中包含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可能无法初始化和前一个请求期间使用设置的值由同一个线程服务)。 - 虽然使用不同的用户的区域设置并不是太大的威胁。

回答

3

但我必须按每次请求(或至少每个会话)初始化它。

使用FilterHttpServletServletRequestListener(或HttpSessionListener)。

但会带来一些安全问题事关

此外,线程由容器合并。对于不同的后续请求,同一个线程可以重复使用多次。当你在线程中放置某些东西时,不要在请求结束时将其移除,最终会得到线程安全代码。

最好的办法是创建一个ThreadLocal<T>类。假设你希望它是请求/响应基础,这里有一个开球例如:

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

(注意,这是非常重要释放在try块的finally块的背景下,你要收购它,否则它不会被释放每当请求 - 响应处理抛出除外)

最后,你可以在你的代码到处让它如下:

Context context = Context.getInstance(); 
context.setLocale(locale); 
Locale foo = context.getLocale(); 
// ... 

其中您将方法委托给当地的request和/或response变量。

请注意,类似的构造已经存在于一些MVC框架中,如JSF及其FacesContext。如果你不想在那里生长,那么你想看看草地是不是更环保。

+0

谢谢!当然,我的'MyParameters'示例可以通过一个请求来工作,我并没有假设一个线程会通过一个会话保持不变。 – vbence 2011-04-22 13:41:10

+0

不,线程是基于请求的,而不是基于会话的。 – BalusC 2011-04-22 13:42:05

+0

我写的是:“我没有假设一个线程会通过一个会话持续不断” – vbence 2011-04-22 14:43:51