您的位置:首页 > 运维架构 > Tomcat

TomCat之Filter小析

2017-05-07 23:46 113 查看
对于做过web开发的人来说,Servlet中的过滤器肯定都不会陌生。这里我尝试着分析一下TomCat服务器中对于Filter是怎么组装的。在这之前,先把主要的几个类列一下:

Filter 过滤器接口

FilterChain 过滤器链

FilterConfig 过滤器的配置

FilterDef 过滤器的配置和描述

ApplicationFilterChain 调用过滤器链

ApplicationFilterConfig 获取过滤器

ApplicationFilterFactory 组装过滤器链

上面的这几个类是组装过滤器中比较核心的一些类。OK下面再说几个比较重要的类:

WebXml 从名字我们可以就看出来这个一个存放web.xml中内容的类

ContextConfig 一个web应用的上下文配置类

StandardContext 一个web应用上下文(Context接口)的标准实现
StandardWrapperValve 一个标准Wrapper的实现。一个上下文一般包括一个或者多个包装器,每一个包装器表示一个servlet。

在ContextConfig中会创建WebXml的实例,解析Web.xml等等一系列的工作。当然也包括实例化过滤器的动作。我们先跳过这一部分,进入到StandardWrapperValve中,因为在这个类中会进行过滤器的组装的操作,Servlet的调用。
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
上面那句话的作用是创建一个应用过滤器链,我们进入到这个方法中看一下(在ApplicationFilterFactory这个类中):
StandardContext context = (StandardContext) wrapper.getParent();//这个Context代表的是一个应用上下文的标准实现
FilterMap filterMaps[] = context.findFilterMaps();//获取FilterMaps 这个是在ContextConfig中组装的。内容是在web.xml中配置的filter

// If there are no filter mappings, we are done
if ((filterMaps == null) || (filterMaps.length == 0)) //如果web.xml中没有配置过滤器,则直接返回
return (filterChain);

// Acquire the information we will need to match filter mappings
String servletName = wrapper.getName();//获取Servlet的名字  一个StandardWrapperValue代表一个具体的Servlet

// Add the relevant path-mapped filters to this filter chain
for (int i = 0; i < filterMaps.length; i++) {  //这里开始循环filterMaps中配置的过滤器(Servlet3.0支持注解的方式添加过滤器,这里也会包含这一部分)
if (!matchDispatcher(filterMaps[i] ,dispatcher)) { //这里是过滤器支持的类型,包括 FORWARD、INCLUDE、REQUEST、ASYNC、ERROR
continue;
}
if (!matchFiltersURL(filterMaps[i], requestPath)) //这里判断是否和请求路径相匹配
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName()); //从应用上下文中查找对应的过滤器
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
boolean isCometFilter = false;
if (comet) {
try {
isCometFilter = filterConfig.getFilter() instanceof CometFilter;
} catch (Exception e) {
// Note: The try catch is there because getFilter has a lot of
// declared exceptions. However, the filter is allocated much
// earlier
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
}
if (isCometFilter) {
filterChain.addFilter(filterConfig); //添加过滤器到过滤器链中
}
} else {
filterChain.addFilter(filterConfig); //添加过滤器到过滤器链中
}
}
在下面还有一段和这一段类似的组装过滤器的内容,我们不再分析。我们看看addFilter这个方法中做了什么:

void addFilter(ApplicationFilterConfig filterConfig) {

// Prevent the same filter being added multiple times
for(ApplicationFilterConfig filter:filters)
if(filter==filterConfig)//去掉重复的过滤器配置 这里用的是 ==
return;

if (n == filters.length) {//对过滤器配置数组扩容 一次括十个长度
ApplicationFilterConfig[] newFilters =
new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters, 0, newFilters, 0, n);
filters = newFilters;
}
filters[n++] = filterConfig; //加入到数组中

}
下面我们再回到org.apache.catalina.core.StandardWrapperValve这个类的invoke方法中:
// Call the filter chain for this request 注释写的很清楚 调用过滤器链
// NOTE: This also calls the servlet's service() method //同时也会调用servlet的service方法
try {
if ((servlet != null) && (filterChain != null)) { //如果存在过滤器链
// Swallow output if needed
if (context.getSwallowOutput()) { //需要吞咽输出 (不知道是什么东西)
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) { // Servlet3.0的新特性
((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
} else if (comet) { //这里不太清楚
filterChain.doFilterEvent(request.getEvent());
} else { //执行过滤器
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (request.isAsyncDispatching()) {
((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
} else if (comet) {
filterChain.doFilterEvent(request.getEvent());
} else { //执行过滤器
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
下面我们进入到org.apache.catalina.core.ApplicationFilterChain的doFilter方法中这个方法其实是调用的internalDoFilter(request,response);这个方法,我们直接进入到这个方法中:
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {

// Call the next filter if there is one
if (pos < n) { // n代表的是过滤器链中有多少个过滤器 pos代表当前执行到哪个过滤器了
ApplicationFilterConfig filterConfig = filters[pos++]; //获取要执行的过滤器配置
Filter filter = null;
try {
filter = filterConfig.getFilter(); //要执行的过滤器
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
filter, request, response); //过滤器执行前的事件

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);//执行过滤器 这里可以看到最后传的参数是this 以达到循环调用的目的
}

support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response); //过滤器执行后的事件
我们继续往下看
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);
}

support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
servlet, request, response); // Service执行前的事件
if (request.isAsyncSupported()
&& !support.getWrapper().isAsyncSupported()) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse)) {

if( 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); //调用service的方法
}
} else {
servlet.service(request, response); //调用service的方法
}
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response);//service执行后的方法
OK,上面就是大致的一个过滤器链组装和调用的过程。下面我把和Filter相关的一些类抽取了出来,以便能在项目中使用到这种模式-责任链模式。
Filter:过滤器
public interface Filter {
/**
* 要执行过滤器
*
* @param request
* @param response
* @param chain
* @throws IOException
*/
void doFilter(Object request, Object response,
FilterChain chain) throws IOException;

void destory();
}

FilterChain:过滤器链

public interface FilterChain {
/**
* 过滤器链,执行过滤器
* @param request
* @param response
* @throws IOException
*/
void doFilter(Object request, Object response)
throws IOException;
}
ApplicationFilterConfig:过滤器的一些特殊配置

public class ApplicationFilterConfig {

/**
* 设置过滤器
*/
private Filter filter;

public Filter getFilter() {
return filter;
}

public ApplicationFilterConfig(Filter filter) {
this.filter = filter;
}
}
ApplicationFilterChain:组装过滤器链,调用过滤器
public class ApplicationFilterChain implements FilterChain {
/**
* 执行到哪一个过滤器了
*/
private int pos = 0;
/**
* 一共有组装了多少个过滤器
*/
private int n = 0;
/**
* 执行完过滤器之后执行的处理类
*/
private Servlet servlet;
/**
* 过滤器数组
*/
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
/**
* 每次增加的长度
*/
public static final int INCREMENT = 10;

/**
* 过滤器链,执行过滤器
*
* @param request
* @param response
* @throws IOException
*/
@Override
public void doFilter(Object request, Object response) throws IOException {
//@TODO 这里可以写一些逻辑处理
internalDoFilter(request, response);
}

public void internalDoFilter(Object request, Object response) throws IOException {
if (pos < n) {
//过滤器的处理
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = filterConfig.getFilter();
filter.doFilter(request,response,this);
return;
}
servlet.service(request,response);
}
/**
* 添加过滤器
* @param filterConfig
*/
public void addFilter(ApplicationFilterConfig filterConfig){
//过滤掉重复的Filter
for(int i=0;i<filters.length;i++){
if(Objects.equals(filters[i], filterConfig)){
return;
}
}
//数组扩容
if( n == filters.length){
ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters,0,newFilters,0,n);
filters = newFilters;
}
filters[n++] = filterConfig;
}

public void setServlet(Servlet servlet) {
this.servlet = servlet;
}

public void release() {
for (int i = 0; i < n; i++) {
filters[i] = null;
}
n = 0;
pos = 0;
servlet = null;
}
}
ApplicationFilterFactory:创建过滤器链
public final class ApplicationFilterFactory {
/**
* 创建过滤器链,每个请求都会调用
* @param request
* @param wrapper
* @param servlet
*/
public static ApplicationFilterChain createFilterChain(Object request, Object wrapper, Servlet servlet){

ApplicationFilterChain applicationFilterChain = new ApplicationFilterChain();
//设置Filter
ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(new FirProcessFilter());
applicationFilterChain.addFilter(filterConfig);
filterConfig = new ApplicationFilterConfig(new SecProcessFilter());
applicationFilterChain.addFilter(filterConfig);
return applicationFilterChain;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息