做JavaEE开发几年了,只是知道Filter、Servlet的执行流程,但是一直对Filter是如何实现的并不了解。
Filter的处理中的FilterChain是J2ee的接口,并没有提供实现,具体的实现有各个Servlet容器来实现的。今天就找了个时间,简单的看了一下Tomcat的FilterChain的内部实现,做了一个大致的了解,下面就来模拟了一下。
以我对Tomcat中Filter简单实现,设计了下面的类图:
Filter接口、FilterChain,是完全按照J2EE中的Filter接口、FilterChain来设计的。
FilterContext是Filter的执行上下文。
DefaultFilterChain用于调配各个过滤器的执行。
Request是封装的简易请求。
FirstFilter、SecondFilter用于模拟我们开发时自定义的Filter。
Client用于测试。
下面附上代码:
// J2EE的Filter /** * Created with IntelliJ IDEA. * User: Administrator * Date: 14-7-28 * To change this template use File | Settings | File Templates. */ public interface Filter { public void init(FilterConfig cfg); public void doFilter(Request request, Object response, FilterChain chain); public void destroy(); } // J2EE的FilterChian public interface FilterChain { void doFilter(Request request, Object response); } // Filter配置信息,用于Filter初始化 public class FilterConfig { private String name; public FilterConfig(){} public FilterConfig(String name){ this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } // 模拟Filter执行的上下文 public class FilterContext { List<Filter> filters=new ArrayList<Filter>(); public FilterContext(){ } public void addFilter(Filter filter, FilterConfig cfg){ this.filters.add(filter); filter.init(cfg); } public void remvoeFilter(Filter filter){ this.filters.remove(filter); filter.destroy(); } public Filter getFilter(int index){ return filters.get(index); } } // 自定义请求 public class Request { private String url; private String param; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getParam() { return param; } public void setParam(String param) { this.param = param; } @Override public String toString() { return this.url+"?"+this.getParam(); } } // 模拟FilterChain的内部实现 public class DefaultFilterChain implements FilterChain { private FilterContext context; private int i=0; public void doFilter(Request request, Object response) { if(i<context.filters.size()){ context.getFilter(i++).doFilter(request, response, this); } else { System.out.println("过滤器已处理完毕,现在由Servlet来处理请求。。。"); } } public void setContext(FilterContext context) { this.context = context; } }
上面的几个类模拟了J2EE对于FIlter的设计。
接下来,自定义两个Filter:
public class FirstFilter implements Filter { private String name; public void init(FilterConfig cfg) { this.name=cfg.getName(); System.out.println("初始化 "+cfg.getName()); } public void doFilter(Request request, Object response, FilterChain chain) { System.out.println(this.name+": "+request); if (request.getUrl()!=null){ chain.doFilter(request,response); } } public void destroy() { //To change body of implemented methods use File | Settings | File Templates. } } public class SecondFilter implements Filter { private String name; public void init(FilterConfig cfg) { this.name=cfg.getName(); System.out.println("初始化 "+cfg.getName()); } public void doFilter(Request request, Object response, FilterChain chain) { System.out.println(this.name+": "+request); if (request.getUrl()!=null){ chain.doFilter(request,response); } } public void destroy() { //To change body of implemented methods use File | Settings | File Templates. } }
模拟客户端发送请求:
public class Client { public static void main(String[] args) throws InterruptedException { final FilterContext context=init(); final int poolsize=10; // 模拟多个请求 ExecutorService pool=Executors.newFixedThreadPool(poolsize); List<Callable<Object>> tasks=new ArrayList<Callable<Object>>(poolsize); for (int i=0; i<poolsize;i++){ tasks.add(new Callable<Object>() { public Object call() throws Exception { //客户端请求 Request request=new Request(); request.setUrl("http://localhost:8080/filter/hello..."); request.setParam("name=zhangsan&age=23&address=xxxxx"); Object response=new Object(); // 这里是模拟过滤器对请求过滤 DefaultFilterChain chain=new DefaultFilterChain(); chain.setContext(context); chain.doFilter(request,response); return response; } }); } pool.invokeAll(tasks); } // 初始化FilterContext static FilterContext init(){ // 初始化FilterContext并添加自定义Filter ,这个过程是模拟Web Server启动 FilterContext context=new FilterContext(); Filter filter=new FirstFilter(); context.addFilter(filter, new FilterConfig("firstFilter")); filter=new SecondFilter(); context.addFilter(filter, new FilterConfig("secondFilter")); return context; } }
这个模拟过程,只是模拟了发送请求,过滤器对请求过滤的过程。并没有对响应信息处理。
上面的模拟的执行结果:
初始化 firstFilter 初始化 secondFilter firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx 过滤器已处理完毕,现在由Servlet来处理请求。。。 firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx 过滤器已处理完毕,现在由Servlet来处理请求。。。 firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx 过滤器已处理完毕,现在由Servlet来处理请求。。。 firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx 过滤器已处理完毕,现在由Servlet来处理请求。。。 过滤器已处理完毕,现在由Servlet来处理请求。。。 firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx 过滤器已处理完毕,现在由Servlet来处理请求。。。 firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx 过滤器已处理完毕,现在由Servlet来处理请求。。。 firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx firstFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx secondFilter: http://localhost:8080/filter/hello...?name=zhangsan&age=23&address=xxxxx 过滤器已处理完毕,现在由Servlet来处理请求。。。 过滤器已处理完毕,现在由Servlet来处理请求。。。 过滤器已处理完毕,现在由Servlet来处理请求。。。
上面的是对Filter的模拟,具体是怎样一个过程,还需要认真的研究源码才可知晓。尽管如此,通过这个模拟至少对Filter的处理有一个简单的了解。
Filter的设计其实是按照AOP的思想设计的。为什么这么说,下一篇博客将揭晓。