Spring-webソース解析のFilter-OnecePerRequest Filter:
3353 ワード
4.1.70.RELEASEに基づく
まずfilter-mappingの配置を見ます.
直接dofilterの方法を見ます.
1 has AlreadyFilteredAttributeがありますか?
2 skyipDisplatchかどうか
3フィルタをかけないか
私たちは2と3を直接見て、ステップ3で、ショルドノートファイトによってフィルタリングを行うかどうか判断します.その実現はサブクラスに依存します.
2には判定条件が二つあります.
2はERROR要求であり、ERRORをフィルタするべきではなく、同じくtrueに戻る.
上記の全ての判断条件が完了したら、実行するかどうかを決定することができます.
もう一つ注意しなければならない方法は?
まずfilter-mappingの配置を見ます.
encodingFilter
/*
REQUEST
ASYNC
ここでは、ASYNCの構成を指定して、フィルタリング非同期要求を示しています.このASYNCは、エニュメレーション型DispartTypeの一つの要素であり、Servlet 3.0において、一つの要求がDispactcher Type.ASYNCタイプであれば、一つの要求のプロセスにおいて、filterは複数のスレッドを呼び出すことができます.これは明らかに問題がありますが、springはどうやってこの問題を避けますか?これは今日話したいOcePerRequest Filterです.直接dofilterの方法を見ます.
@Override
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("OncePerRequestFilter just supports HTTP requests");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {
// Proceed without invoking this filter...
filterChain.doFilter(request, response);
}
else {
// Do invoke this filter...
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
try {
doFilterInternal(httpRequest, httpResponse, filterChain);
}
finally {
// Remove the "already filtered" request attribute for this request.
request.removeAttribute(alreadyFilteredAttributeName);
}
}
}
ソースからは、springはフィルタリングされたrequestにatributeをセットします.filterチェーンと目標方法の実行が終わったら、このatributeをリリースします. get AlreadyFilteredAttributeName()メソッドが得られ、デフォルトではfilterの名前にサフィックスが付けられていますが、filterが完全に初期化されていない場合は、クラス名にサフィックスが付けられ、後に「.FILTEED」が付けられます.protected String getAlreadyFilteredAttributeName() {
String name = getFilterName();
if (name == null) {
name = getClass().getName();
}
return name + ALREADY_FILTERED_SUFFIX;
}
名前を取得したら、このfilterを実行したかどうかを判断する必要があります.判定条件は3つあります.1 has AlreadyFilteredAttributeがありますか?
2 skyipDisplatchかどうか
3フィルタをかけないか
私たちは2と3を直接見て、ステップ3で、ショルドノートファイトによってフィルタリングを行うかどうか判断します.その実現はサブクラスに依存します.
2には判定条件が二つあります.
private boolean skipDispatch(HttpServletRequest request) {
if (isAsyncDispatch(request) && shouldNotFilterAsyncDispatch()) {
return true;
}
if (request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE) != null && shouldNotFilterErrorDispatch()) {
return true;
}
return false;
}
1は非同期であり、非同期をフィルタするべきでない場合、skypetchはtrueであり、つまりフィルタリングを行わない.2はERROR要求であり、ERRORをフィルタするべきではなく、同じくtrueに戻る.
上記の全ての判断条件が完了したら、実行するかどうかを決定することができます.
doFilterInternal(httpRequest, httpResponse, filterChain);
この方法はサブクラスの具体的な実現方法です.その一つは前の記事で述べたCharcterEncocdingFilterです.もう一つ注意しなければならない方法は?
protected boolean isAsyncStarted(HttpServletRequest request) {
return WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted();
}
これがtrueに戻ると、現在のスレッドが終了している時はレスポンスは返されません.