前言
Servlet中的Filter使用到了責任鏈模式,F(xiàn)ilter是提供給用戶對請求做處理的,不同的組件可能有不同的處理,所以他們的處理邏輯不會耦合在一起,這樣就需要一個方案將這些不同組件產(chǎn)生的分散且不確定的處理邏輯聚集起來,讓他們得到執(zhí)行,責任鏈模式就是一個優(yōu)雅的解決方案,我們直接以Servlet中Filter的處理來做講解,實戰(zhàn)才是最好的講解。
個人整理了一些資料,有需要的朋友可以直接點擊領取。
Filter
我們先來看看頂級接口設計
javax.servlet.Filter 直接暴露給用戶實現(xiàn)的,需要處理的用戶只要實現(xiàn)Filter,并將Filter添加到Servet容器中,就能夠得到執(zhí)行,F(xiàn)ilter聚合了FilterConfig
javax.servlet.FilterConfig 過濾器配置,包含對應一個真實的Filter
javax.servlet.FilterChain 過濾器鏈,有一個FilterConfig列表,用來驅動執(zhí)行下一個Filter邏輯,以及添加Filter到鏈上,這個類是主要邏輯所在地方,如果是你設計,你會把主要邏輯放在哪里?
這里可以看到Filter和FilterConfig互為聚合對象,有點循環(huán)引用的意思。
public interface Filter {
public default void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
public default void destroy() {}
}
public abstract class GenericFilter implements Filter, FilterConfig, Serializable {
private static final long serialVersionUID = 1L;
private volatile FilterConfig filterConfig;
@Override
public String getInitParameter(String name) {
return getFilterConfig().getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return getFilterConfig().getInitParameterNames();
}
public FilterConfig getFilterConfig() {
return filterConfig;
}
@Override
public ServletContext getServletContext() {
return getFilterConfig().getServletContext();
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
init();
}
public void init() throws ServletException {
// NO-OP
}
@Override
public String getFilterName() {
return getFilterConfig().getFilterName();
}
}
public interface FilterConfig {
public String getFilterName();
public ServletContext getServletContext();
public String getInitParameter(String name);
public Enumeration<String> getInitParameterNames();
}
public final class ApplicationFilterConfig implements FilterConfig, Serializable {
...
private transient Filter filter = null;
Filter getFilter() throws ClassCastException, ReflectiveOperationException, ServletException,
NamingException, IllegalArgumentException, SecurityException {
// Return the existing filter instance, if any
if (this.filter != null)
return this.filter;
// Identify the class loader we will be using
String filterClass = filterDef.getFilterClass();
this.filter = (Filter) context.getInstanceManager().newInstance(filterClass);
initFilter();
return this.filter;
}
}
這里看到包含的是一個FilterConfig數(shù)組,從FilterConfig中能夠拿到Filter,說明FilterConfig是更加高層的對象, 高層對象聚合底層對象,高層對象被使用,在做設計時應該注意到。
public interface FilterChain {
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
public final class ApplicationFilterChain implements FilterChain {
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
} else {
internalDoFilter(request,response);
}
}
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
// We fell off the end of the chain -- call the servlet instance
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}
if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
servlet.service(request, response);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}
}
Interceptor
Filter是個很簡單的模式,Spring MVC中的Interceptor和Filter有所不同,因為Filter只能在請求前處理,不能在請求后處理,所以功能上有一些局限,所以Spring提供了Interceptor,所以有了Interceptor之后,如非特殊情況,我們一般使用Interceptor來滿足需求。先來看看頂級接口:
org.springframework.web.servlet.HandlerInterceptor
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
org.springframework.web.servlet.HandlerExecutionChain
這里可以看到是直接遍歷把所有前置,后置方法輪流調完。不是動態(tài)代理完成的。
public class HandlerExecutionChain {
...
@Nullable
private HandlerInterceptor[] interceptors;
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
}
最后
就先總結到這里了,覺得有幫助的可以幫忙點個贊,感謝支持!