Filter与责任链模式

Filter
说起Filter大家应该都不陌生。Filter一般用于Servlet处理之前做一些前置的校验。如果校验通过,那么调用chain.doFilter(request, response)就可以让下一个filter继续执行逻辑。Filter是责任链模式的一种应用。接下来我们将探索、模拟Filter的实现逻辑。

责任链模式
责任链模式是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给连上的下一个处理者。

通过责任链对消息进行处理
对消息进行处理是一个非常简单的责任链模式的应用,直接看代码吧:

public class SimpleFilterChainMain {
    public static void main(String[] args) {
    	//定义一个简单的消息对象
        Msg msg = new Msg();
        //消息内容
        msg.setContent("hello,<script>alert(\"I am an alert box!!\")</script> world! ${jndi:rim:/xxx} ");
        //定义一个过滤器链filterChain1 
        FilterChain filterChain1 = new FilterChain();
        //为filterChain1中添加一个HTML标签的过滤器
        filterChain1.add(new HTMLFilter());
        //定义另一个过滤器链filterChain2
        FilterChain filterChain2 = new FilterChain();
        //为filterChain2添加一个敏感词的过滤器
        filterChain2.add(new SensitiveFilter());
        //将filterChain2本身也作为一个过滤器添加到filterChain1中
        filterChain1.add(filterChain2);
        //使用filterChain1对消息进行过滤
        filterChain1.doFilter(msg);
        //输出一下过滤之后的结果
        System.out.println(msg.getContent());
    }

	/**
	 * 过滤器接口
	 */
    private interface Filter {
        /**
         * 过滤msg
         * @param msg
         */
        void doFilter(Msg msg);
    }

	/**
	 * 消息对象
	 */
    private static class Msg {
        private String content;

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

	/**
	 * HTML标签的过滤器
	 */
    private static class HTMLFilter implements Filter {

        @Override
        public void doFilter(Msg msg) {
            String content = msg.getContent();
            content = content.replace('<', '[');
            content = content.replace('>', ']');
            msg.setContent(content);
        }
    }

	/**
	 * 敏感词的过滤器
	 */
    private static class SensitiveFilter implements Filter {

        @Override
        public void doFilter(Msg msg) {
            String content = msg.getContent();
            content = content.replaceAll("\\$\\{jndi:", "***");
            msg.setContent(content);
        }
    }

	/**
	 * 过滤器链,同时也实现了过滤器接口
	 */
    private static class FilterChain implements Filter {
        List<Filter> filters = new ArrayList<>();

		/**
		 * 向链中添加一个过滤器
		 */
        public void add(Filter filter) {
            filters.add(filter);
        }

        @Override
        public void doFilter(Msg msg) {
            for (Filter filter : filters) {
                filter.doFilter(msg);
            }
        }
    }
}

  

反思与思考
以前我对责任链的理解仅仅只是到了Filter这一层,我认为只要有了一个List<Filter> filters 就算是责任链的体现了。所以所谓的“链”在我这里只是一个list而已。而在上面的例子中,我的责任链已经是一个FilterChain对象了。这个从list到对象的过程就体现了封装,封装是为了更好的变化。封装之后我的FilterChain还实现了Filter接口。这样做的好处是,链中每个过滤器既可以是独立的过滤器,比如HTMLFilter,也可以是另一个过滤器链,比如filterChain2。链与链就这么连上了。

Servlet中的Filter
我们先看看Servlet中的Filter是什么样的效果。
首先,我定义了一个Controller和3个Filter

 

 

在具体的Filter中其实什么也没有做,只是打印了两句话

 

 

接下来我们看下效果

 

 

也就是说先Filter1先处理Request,然后交给Filter2处理,最后交给Filter3处理,当Servlet处理完请求之后,再按照Filter321的顺序处理Response,就像下面的图这样。

 

 


模拟Servlet中Filter的处理模式
Servlet中的Filter之所以能够实现这么神奇的功能,核心原因在于Servlet的Filter有三个参数,Request、Response和FilterChain。

 

demo

接下来我们用demo演示一下:

/**
 * 尝试模拟一下servlet的filter调用过程
 * @author skyline
 */
public class ServletFilterMain {

    public static void main(String[] args) {
        FilterChain filterChain = new MyFilterChain();
        filterChain.addFilter(new Filter1());
        filterChain.addFilter(new Filter2());
        filterChain.addFilter(new Filter3());
        filterChain.doFilter(new Request(), new Response());
    }

    /**
     * 自定义过滤器
     */
    private interface Filter {
        /**
         * 执行过滤的逻辑
         * @param request
         * @param response
         */
        void doFilter(Request request, Response response, FilterChain filterChain);
    }

    /**
     * 过滤器链
     */
    private interface FilterChain {

        void doFilter(Request request, Response response);

        /**
         * 添加过滤器
         * @param filter
         */
        void addFilter(Filter filter);
    }

    private static class Filter1 implements Filter {
        private static final Logger logger = LoggerFactory.getLogger(Filter1.class);

        @Override
        public void doFilter(Request request, Response response, FilterChain filterChain) {
            logger.info("before filterChain.doFilter");
            filterChain.doFilter(request, response);
            logger.info("after filterChain.doFilter");
        }
    }

    private static class Filter2 implements Filter {
        private static final Logger logger = LoggerFactory.getLogger(Filter2.class);

        @Override
        public void doFilter(Request request, Response response, FilterChain filterChain) {
            logger.info("before filterChain.doFilter");
            filterChain.doFilter(request, response);
            logger.info("after filterChain.doFilter");
        }
    }

    private static class Filter3 implements Filter {
        private static final Logger logger = LoggerFactory.getLogger(Filter3.class);

        @Override
        public void doFilter(Request request, Response response, FilterChain filterChain) {
            logger.info("before filterChain.doFilter");
            filterChain.doFilter(request, response);
            logger.info("after filterChain.doFilter");
        }
    }

    /**
     * 模拟请求
     */
    private static class Request {}

    /**
     * 模拟响应
     */
    private static class Response {}

    private static class MyFilterChain implements FilterChain {

        private final List<Filter> filters;
        private int index;

        private MyFilterChain() {
            filters = new ArrayList<>();
            index = -1;
        }

        @Override
        public void doFilter(Request request, Response response) {
            //这里再次体现了封装的必要性,因为如果单纯的遍历filters就无法实现我们想要的效果
            int size = filters.size();
            //每次doFilter时索引+1
            index++;
            if (index < size) {
                //从filters中取出index位置的Filter,调用并调用doFilter
                filters.get(index).doFilter(request, response, this);
            }
        }

        @Override
        public void addFilter(Filter filter) {
            filters.add(filter);
        }
    }
}

效果

先看下效果:

 

 确实实现了123321的效果。

 

posted @ 2022-04-28 11:30  刻思行  阅读(890)  评论(0)    收藏  举报