zoukankan      html  css  js  c++  java
  • 手写web服务器:实现简单filter逻辑

    前言

    今天早上起床的时候,我还在想应该实现哪个组件,想了半天,发现基本上常用的注解组件都被我们給实现了(当然,虽然都实现了,但是基本上都是简易版),最后想来想去觉得filter可以实现下,毕竟没有这个模块,项目中的就没法实现权限控制了。

    在开始的时候,我已经知道filter的难点是地址的匹配,也就是如何把我们配置的地址转换为正则表达式,最后发现这块涉及的知识点有点多,所以今天就只演示通配地址,即/*

    好了,我们一起来看下吧。

    过滤器实现过程

    定义注解

    这里依然很轻车熟路,注解的配置我增加了很多属性,最核心的就是urlPatterns,也就是我们的拦截地址。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface WebFilter {
        String[] value() default {};
    
        String description() default "";
    
        String displayName() default "";
    
        String[] urlPatterns() default {};
    }
    

    定义Filter接口

    这里参考了javaEEfilter接口

    public interface Filter {
        default void init() {}
    
        void doFilter(Request request, Response response, FilterChain filterChain) throws IOException;
    
        default void destrory() {}
    }
    
    public interface FilterChain {
        /**
         * filter调用链
         * @param request
         * @param response
         * @throws IOException
         */
        void doFilter(Request request, Response response) throws IOException;
    }
    

    定义filter

    加上webFilter,并配置拦截地址,实现doFilter方法

    @WebFilter(urlPatterns = {"/*"}, description = "test filter")
    public class TestFilter implements Filter{
        @Override
        public void doFilter(Request request, Response response, FilterChain filterChain) throws IOException {
            System.out.println(String.format("过滤器TestFilter被访问,拦截地址:%s", request.getRequestHear().getRequestMapping()));
            if (Objects.nonNull(filterChain)) {
                filterChain.doFilter(request, response);
            }
        }
    }
    

    过滤器初始化

    这里主要是配合IoC,拿到过滤器的配置信息,并实例化filter

    private static Map<Filter, String[]> filterUrlPatternsMap = Maps.newHashMap();
    
        private static LinkedList<Filter> filterLinkedList = Lists.newLinkedList();
    
        public static Map<Filter, String[]> getFilterUrlPatternsMap() {
            return filterUrlPatternsMap;
        }
    
        public static LinkedList<Filter> getFilterLinkedList() {
            return filterLinkedList;
        }
    
        public static void init(Class zClass) throws IllegalAccessException, InstantiationException {
            Annotation webFilter = zClass.getAnnotation(WebFilter.class);
            if (Objects.nonNull(webFilter)) {
                String[] urlPatterns = ((WebFilter) webFilter).urlPatterns();
                Filter filter = (Filter)zClass.newInstance();
                filterUrlPatternsMap.put(filter, urlPatterns);
                filterLinkedList.add(filter);
            }
        }
    

    修改disPatcher方法

    这里就是对请求地址进行过滤,当匹配到请求时,执行匹配到过滤器的doFilter方法

    Map<Filter, String[]> filterUrlPatternsMap = FilterHandler.getFilterUrlPatternsMap();
                LinkedList<Filter> filterLinkedList = FilterHandler.getFilterLinkedList();
                ListIterator<Filter> filterListIterator = filterLinkedList.listIterator();
                while (filterListIterator.hasNext()) {
                    Filter filter = filterListIterator.next();
                    String[] values = filterUrlPatternsMap.get(filter);
                    for (String value : values) {
                        if(Pattern.matches(value.replace('/', '.'), requestMapping)) {
                            filter.doFilter(request, response, null);
                        }
    
                    }
                }
    

    测试

    我们用浏览器访问任意地址,比如/testAutowire,会看到doFilter方法被执行了,控制台打印如下信息:

    说明,我们的filter已经起作用了,是不是很简单呀。

    总结

    虽然filter的核心功能实现了,但作为一个合格的web服务器,拦截器也得够健壮,够灵活,所以还有很多工作要做:

    比如要实现链式调用,就是实现多个过滤器的顺序调用,层层调用,层层返回,形成调用链,这一块后面要进一步实现;

    另外一个问题就是,我们要实现更灵活的地址匹配,前面我也说了,目前的地址只实现了通配和严格匹配两种,正则表达式支持的也不够完美,这一块也是后面要优化的点。

    好了,核心内容到这里就结束了,但我想说两句闲话,这两天在刷一个制作精良的剧——《觉醒年代》,这应该是这几年,我看过最有价值的电视剧了,让我对很多革命先烈有了更深刻的认识,有兴趣的小伙伴可以去看下,真的很赞。

    下面是项目的开源仓库,有兴趣的小伙伴可以去看看,如果有想法的小伙伴,我真心推荐你自己动个手,自己写一下,真的感觉不错:

    https://github.com/Syske/syske-boot
    

  • 相关阅读:
    [BZOJ 3282] Tree 【LCT】
    [BZOJ 2049] [Sdoi2008] Cave 洞穴勘测 【LCT】
    [BZOJ 1036] [ZJOI2008] 树的统计Count 【Link Cut Tree】
    [HDOJ
    Excel+DDT数据驱动实例
    jenkins+SVN配置
    [转]loadrunner:系统的平均并发用户数和并发数峰值如何估算
    loadrunner:Auto Correlate自动定位瓶颈
    loadrunner:判断是否服务器连接池瓶颈
    利用page_source抓取网页中的URL,进行链接测试
  • 原文地址:https://www.cnblogs.com/caoleiCoding/p/14873617.html
Copyright © 2011-2022 走看看