责任链模式及其在web容器中的应用
先来看一个问题
一、简单的过滤
假如你想设计一个类对一串字符串实现简单的过滤,你会怎么写这个类?对于刚接触编程的人来说可能会像下面这种写法:
Message过滤类
public class Message {
private String text;
public Message() {
}
public String doFilter(){
//去掉空格
return text.replace(" ", "");
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
FilterTest测试类
public class FilterTest {
public static void main(String[] args) {
String text = "Hello World";
Message message = new Message();
message.setText(text);
text = message.doFilter();//实现过滤
System.out.println(text);
}
}
上面的代码实现了简单的字符串过滤类,很明显这样写的代码扩展性很不好,假如我之后想对字符串大小写进行过滤就要重新修改这个类,一点都不灵活。这个时候我们就想把过滤这个行为抽象出来,让每一个具体过滤方法实现这个抽象接口。
二、将过滤抽象出来
Filter接口
public interface Filter {
public String doFilter(String text);
}
SpaceFilter空格过滤类
public class SpaceFilter implements Filter{
@Override
public String doFilter(String text) {
// TODO Auto-generated method stub
return text.replace(" ", "");
}
}
UpstrFilter大小写过滤类
public class UpstrFilter implements Filter{
@Override
public String doFilter(String text) {
//转换成大写
return text.toUpperCase();
}
}
Message 类
public class Message {
private String text;
public Message() {
}
public String doFilter(){
if(text != null && !"".equals(text)){
//过滤空格
text = new SpaceFilter().doFilter(text);
//过滤大写
text = new UpstrFilter().doFilter(text);
}
//去掉空格
return text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
FilterTest 测试类
public class FilterTest {
public static void main(String[] args) {
String text = "Hello World";
Message message = new Message();
message.setText(text);
text = message.doFilter();//实现过滤
System.out.println(text);
}
}
这样假如还有其他过滤手段时只要实现Filter接口,在Message 的doFilter中增加新的过滤手段即可。但是这样还是不够灵活,需要修改Message 类,所以我们可以设计一个类FilterChain来保存所有的Filter,在Message的doFilter方法中遍历执行FilterChain中所有的Filter
三、FilterChain来保存所有的Filter
FilterChain类
public class FilterChain {
List<Filter> filters = new ArrayList<Filter>();
public FilterChain addFilter(Filter filter){
filters.add(filter);
return this;
}
public String doFilter(String text){
if(null != text && !("").equals(text)){
for(Filter f : filters){
text = f.doFilter(text);
}
}
return text;
}
}
修改后Message 类
public class Message {
private String text;
private FilterChain filterChain;
public Message() {
}
public String doFilter(){
return filterChain.doFilter(text);
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public FilterChain getFilterChain() {
return filterChain;
}
public void setFilterChain(FilterChain filterChain) {
this.filterChain = filterChain;
}
}
FilterTest测试类
public class FilterTest {
public static void main(String[] args) {
String text = "Hello World";
Message message = new Message();
message.setText(text);
FilterChain filterChain = new FilterChain();
filterChain.addFilter(new SpaceFilter())
.addFilter(new UpstrFilter());
message.setFilterChain(filterChain);
text = message.doFilter();
System.out.println(text);
}
}
到这里已经有点责任链的味道了,最后我们将过滤器和过滤链今行合并
四、合并过滤链
FilterChain类
public class FilterChain implements Filter{
List<Filter> filters = new ArrayList<Filter>();
private int index = 0;
public FilterChain addFilter(Filter filter){
filters.add(filter);
return this;
}
@Override
public String doFilter(String text, FilterChain filterChain) {
if(index >= filters.size())
return text;
Filter filter = filters.get(index++);
return filter.doFilter(text, filterChain);
}
}
SpaceFilter
public class SpaceFilter implements Filter{
@Override
public String doFilter(String text, FilterChain filterChain) {
// TODO Auto-generated method stub
text = text.replace(" ", "");
return filterChain.doFilter(text, filterChain);
}
}
UpstrFilter
public class UpstrFilter implements Filter{
@Override
public String doFilter(String text, FilterChain filterChain) {
//转换成大写
text = text.toUpperCase();
return filterChain.doFilter(text, filterChain);
}
}
Message
public class Message {
private String text;
private FilterChain filterChain;
public Message() {
}
public String doFilter(){
return filterChain.doFilter(text, filterChain);
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public FilterChain getFilterChain() {
return filterChain;
}
public void setFilterChain(FilterChain filterChain) {
this.filterChain = filterChain;
}
}
web中的过滤器
在web中的过滤器就是使用了责任链模式来实现。
我们来看一下tomcat中的过滤器链的源码ApplicationFilterChain,以下是ApplicationFilterChain的doFilter方法
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);
}
}
其中internalDoFilter方法就是过滤器链调用过滤器的方法
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);
}
}
}
可以看到,tomcat正是通过filter.doFilter(request, response, this);方法使得每一个过滤器都持有过滤器链,在处理完一个过滤器后,调用下一个过滤器,直到所有过滤器执行完毕。