ThreadLocalを使いたい場合
コンポーネントから、HttpServletRequestなどにアクセスしたい場合もあるでしょう。そのような場合は、ThreadLocalを使って管理するのが一般的です。
しかし、このような管理クラスを作る場合に、シングルトンやstatic変数を使ってはいけません。グローバル変数はできるだけ避けなければなりません。それではどうすれば良いのでしょうか。
まず、くーすらしくRequestContextというインターフェースを定義します。
次は実装クラスです。
interface RequestContext {
HttpServletRequest getRequest();
void setRequest(HttpServletRequest request);
}
このようにして、HttpServletRequestにアクセスしたいコンポーネントは、RequestContextをDIしてもらえばいいのです。テストのときには、ThreadLocalを使わないRequestContextの実装を使い、ThreadLocalの副作用を避けます。
class RequestContextImpl extends RequestContext {
private ThreadLocal requests_ = new ThreadLocal();HttpServletRequest getRequest() {
return (HttpServletRequest) requests_.get();
}
void setRequest(HttpServletRequest request) {
requests_.set(request);
}
}
staticなThreadLocalやシングルトンが良くないのは、あるテストで行ったことが別のテストに影響(副作用)を与えてしまうことです。
RequestContext、ResponseContextは次のSeasar2のリリースに含まれるかも。コンポーネントのインスタンス管理をrequest,sessionごとに行うことに対する布石。
JSFもこうなってほしかったなぁ。> FacesContext
まさにシングルトンとThreadLocal。そのせいでテストがしにくいんですけど。