パターンに出くわしたらServletRequest
、応答オブジェクトがサーブレットのローカルThreadLocal
変数に配置されます。サーブレット クラスには、現在の要求および応答オブジェクトを取得するメソッドもあります。したがって、これらのオブジェクトを取得するには、サーブレット オブジェクトを操作する必要があります。
ThrealLocal
これらのローカル変数を持つことのポイントは何ですか?
パターンに出くわしたらServletRequest
、応答オブジェクトがサーブレットのローカルThreadLocal
変数に配置されます。サーブレット クラスには、現在の要求および応答オブジェクトを取得するメソッドもあります。したがって、これらのオブジェクトを取得するには、サーブレット オブジェクトを操作する必要があります。
ThrealLocal
これらのローカル変数を持つことのポイントは何ですか?
ポイントは、要求オブジェクトと応答オブジェクトを、他の方法では持たないクラス (たとえば、サーブレットではない) に持つことです。1 つの例は JSF マネージド Bean です。これらのメソッドはパラメーターをとらないため、変数に含まれるHttpServletRequest
を介してリクエストを取得できます。FacesContext
ThreadLocal
これが機能する理由は、各リクエストが個別のスレッド (サーブレット コンテナー) によって処理されるためです。つまり、スレッド = リクエストです。ただし、注意点があります。コンテナはスレッド プールを使用する傾向があります。そのため、スレッドローカルで常に新しいリクエストを設定し、できれば後でクリーンアップする必要があります(たとえば、 a でFilter
)。そうしないと、予期しない動作が発生する可能性があります。
ただし、コードではこれを避ける必要があります。リクエストまたはレスポンスから何かが必要な場合は、それをメソッド引数として渡します。そうしないと、レイヤーの境界に違反するリスクがあります (たとえば、サービス レイヤーでリクエストを使用したい場合)。
これらを使用すると、これらのオブジェクトへの参照を他のクラスに渡すことなく、プロジェクト内の他のクラスから HttpServletRequest および HttpServletResponse にアクセスできます。これは、Web 層のコードとビジネス ロジックを混同する傾向があり、単体テストがより困難になる傾向があるため、私が特に好きなパターンではありません。
リクエスト オブジェクトとレスポンス オブジェクトはスレッド ローカル変数に格納されるため、これらのオブジェクトをメソッド パラメータとして渡す必要なく、スレッド セーフにアクセスできます。
例 1: スレッド ローカルなし
public class MyServlet extends Servlet {
private MyObject myObject = new MyObject();
public void service(ServletRequest request, ServletResponse response) {
myObject.doSomething(request, response);
}
}
public class MyObject {
private MyOtherObject myOtherObject = new MyOtherObject();
public void doSomething(ServletRequest request, ServletResponse response) {
// I do nothing with request/response, but need to accept them in order
// to pass them to myOtherObject
myOtherObject.doSomethingElse(request, response);
}
}
public class MyOtherObject {
public void doSomethingElse(ServletRequest request, ServletResponse response) {
// Do something else with request / response
}
}
例 2: スレッド ローカルを使用
public class MyServlet extends Servlet {
private MyObject myObject = new MyObject();
private static ThreadLocal<ServletRequest> currentRequest = new ThreadLocal<ServletRequest>();
public static ServletRequest getCurrentRequest() {
return currentRequest.get();
}
private static ThreadLocal<ServletResponse> currentResponse = new ThreadLocal<ServletResponse>();
public static ServletResponse getCurrentResponse() {
return currentResponse.get();
}
public void service(ServletRequest request, ServletResponse response) {
...
currentRequest.set(request);
currentResponse.set(response);
...
myObject.doSomething();
}
}
public class MyObject {
private MyOtherObject myOtherObject = new MyOtherObject();
public void doSomething() {
// I do not need to know about request / response as I do nothing with them
myOtherObject.doSomethingElse();
}
}
public class MyOtherObject {
public void doSomethingElse() {
// Now I can get the current request / response in a thread safe
// manner and without having to accept them as parameters
ServletRequest request = MyServlet.getCurrentRequest();
ServletResponse response = MyServlet.getCurrentResponse();
// Do something with request / response
}
}
明らかに、単純なサーブレットの場合、オブジェクトを渡すだけが最も簡単ですが、複雑なシナリオでは、1 つの静的でスレッドセーフな getter を使用すると便利な場合があります。
他の人は、あなたが提示したシナリオで Thread Locals をどのように使用するかをほとんど述べています。ただし、Thread Local 依存実装は「スレッド」固有であり、要求モデルごとに単一のスレッドから離れると中断することに注意してください。例として、少数のスレッドが多数のユーザー要求に同時に使用されるイベントベースのサーバーがあります。
スレッドセーフではないオブジェクトがあるが、そのオブジェクトへのアクセスの同期を避けたい場合 (SimpleDateFormat)。代わりに、各スレッドにオブジェクトの独自のインスタンスを与えます。
get()
ThreadLocal のクリーンアップ、またはset()
ThreadLocal のremove()
メソッドを使用したクリーンアップについては、細心の注意を払う必要があります。
あなたがかつて遭遇したコードの作成者の意図が何であったかは 100% わかりませんが、ServletRequest
インスタンスをパラメーターとして渡したり、インスタンスとして設定したりすることなく、コード内の任意のメソッドからインスタンスを利用できるという考えがあると思います。変数。通常、ThreadLocal
変数は静的であり、in のインスタンスをServletRequest
静的に取得できるメソッドが公開されています。たとえば、ServletRequest
この手法を使用して Struts FromBeans に簡単にアクセスできます。