如何实现Filter的调用链

521 阅读3分钟

在开发过程中经常会见到各种xxxFilter过滤器以及xxxIncepteor拦截器,这些过滤器以及拦截器往往都是以接口的方式暴露给我们,我们只要实现接口重写其中的一些方法,xxxFilter一般是doFilter方法,xxxInteceptor一般是intecept方法,那么为什么只要我们实现接口并重写其中的方法就系统就可以执行我们的逻辑呢?并且我们可以实现xxxFilter接口的多个实现类,甚至可以顺序执行我们的实现类,这又是如何实现的呢?

举一个例子,大家都使用过java.servlet.Filter接口,该接口是servlet容器提供的一个过滤器接口,只要我们实现该接口并重写其中的doFilter,那么我们发起http请求,就可以执行到我们的实现类中。

@Component
@Slf4j
public class TestHttpFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String contentType = request.getContentType();
        int serverPort = request.getServerPort();
        log.info("==========执行到TestHttpFilter实现类,获取请求方式类型:{},获取服务端口:{}============",contentType,serverPort);
        chain.doFilter(request,response);
    }
}

通过debug方式可以看到请求经过了我们的Filter实现类TestHttpFilter。原理如何实现的呢? servleFilter.png

HttpFilter-result.png

Spring方式

可以看到我的实现类TestHttpFilter加了spring中的依赖注入的注解,该注解会将该实现类注入到容器中便于后续可以支持调用,那么整个Filter流程如下:

Filter flow.png

接下来实现通过m代码实现整个流程:

实现过滤器接口

/**
 * 过滤器接口
 * @author chenmo
 */
public interface RpcFilter {
    /**
     * 执行过滤器
     * @param name 参数
     * @param age 参数
     * @param filterChain 调用链
     */
    void doFilter(RpcFilterChain filterChain,String name,String age);
}
​

实现过滤器链

/**
 * @author chenmo
 */
public interface RpcFilterChain {
    /**
     * 执行过滤器
     * @param name
     * @param age
     */
    void doFilter(String name,String age);
}
​

实现过滤器链代理类

/**
 * 调用链实现类,定义调用链的调用过程
 * @author chenmo
 */
@Slf4j
public class FilterChainProxy implements RpcFilterChain{
​
    private int position = 0;
    private int size = 0;
    private List<RpcFilter> filterList = new ArrayList<>();
​
    public void addFilter(RpcFilter filter) {
        filterList.add(filter);
        size++;
    }
​
​
    @Override
    public void doFilter(String name,String age) {
        if (size == position) {
            log.info("==========调用结束========");
        } else {
            RpcFilter filter = filterList.get(position);
            position++;
            filter.doFilter(this,name,age);
        }
    }
}
​

实现工厂类

/**
 * 过滤器配置
 * @author chenmo
 */
@Configuration
public class FilterChainFactory {
​
    @Resource
    private List<RpcFilter> rpcFilterList;
​
    private final FilterChainProxy filterChainProxy = new FilterChainProxy();
​
    /**
     *提前执行init将实现类写入调用链
     */
    @PostConstruct
    public void init() {
        for (RpcFilter rpcFilter : rpcFilterList) {
            filterChainProxy.addFilter(rpcFilter);
        }
    }
​
    public FilterChainProxy getFilterChainProxy() {
        return filterChainProxy;
    }
    
}
​

过滤器实现类

/**
过滤器实现类Age
 * @author chenmo
 */
@Component
@Slf4j
public class AgeRpcFilter implements RpcFilter{
    @Override
    public void doFilter(RpcFilterChain filterChain, String name, String age) {
        age += "TestAgeFilter";
        log.info("======调用AgeRpcFilter--age:{}=======",age);
        filterChain.doFilter(name,age);
    }
}
​
/**
 * 过滤器测试实现类Name
 * @author chenmo
 */
@Component
@Slf4j
public class NameRpcFilter implements RpcFilter{
​
​
    @Override
    public void doFilter(RpcFilterChain filterChain, String name, String age) {
        name += "TestNameFilter";
        log.info("======调用NameRpcFilter--name:{}=======",name);
        filterChain.doFilter(name,age);
    }
}
​

测试

/**
 * @author chenmo
 */
@SpringBootApplication
@Slf4j
public class RocketmqTestApplication {
​
    @Resource
    private FilterChainFactory filterChainFactory;
​
    public static void main(String[] args) {
        SpringApplication.run(RocketmqTestApplication.class, args);
    }
​
​
    @Component
    class TestRun implements ApplicationRunner {
​
        @Override
        public void run(ApplicationArguments args) throws Exception {
            FilterChainProxy filterChainProxy = filterChainFactory.getFilterChainProxy();
            log.info("======调用链开始=========");
            filterChainProxy.doFilter("chenlingl","25");
        }
    }
​
}
​

测试结果:

filter test.png

总结

以上的实现逻辑可以看到整个过程并不复杂,执行doFilter的逻辑就像链子的环一样,一环扣一环,最终走到尽头。整个过程的核心逻辑在FilterChainProxy中,通过对实现类一层一层的调用,将我们自定义的Filter实现类执行重写的doFilter方法。

引用

1.programming.vip/docs/workin…