
「一切皆插件」不是口号:手写一个敢上生产的治理管道过滤器
上一篇把接口治理做成了「一个切面 + 两条过滤器链」,开头立了个 flag:一切皆插件。实现一个 PreFilter / PostFilter 注册成 Bean 就自动入链。 先交代一个背景:这个 Starter 已经接进我自己维护的一个真实项目里跑了,下面这些"关"不是理论推演,是照着它踩出来的。 但「能写出一个能跑的过滤器」和「敢上生产的过滤器」之间差着好几道关。这篇把我自己踩过的地方整理成一份实战记录:先五分钟入门,再讲 FilterContext 到底给了你什么,最后写一个两个过滤器配合的生产级例子。 需求:所有接口的参数不能为 null(真实需求比这复杂,先简化): return false 就是短路:后续前置过滤器不跑,业务方法不执行,调用方收到 400。就这么简单——但简单也意味着,契约全靠自觉。下面把它变生产级。 二、FilterContext 能力清单:管道里流通的唯一数据载体 自定义过滤器能做什么、不能做什么,全看 FilterContext 给了什么。它按功能分成六组: 这张表背后有个设计决策值得注意:上下文不区分读写角色。前置过滤器能读 args,后置过滤器也能读;没有「前置只写、后置只读」的类型约束,靠的是 order 区间约定。这是取舍——类型安全换来的是简单,我选简单,因为管道总共就两条链。 Filter 接口继承了 Spring 的 Ordered,内置过滤器占了这些号段,自定义过滤器要对号入座: 选错号段是真实的 bug 来源:我见过把参数校验写在 @Order(50) 的——它跑在流量统计之前,被它拒绝的请求永远进不了统计,监控上的 QPS 看起来比实际低。校验类放 300~399,别越界。 另外两个 Filter 接口自带的方法,写生产级插件时都用得上: getName():默认返回类名,会出现在过滤器链调试日志和管理接口的 /filters 端点里,给它一个人类可读的名字; isEnabled():运行时开关,默认 true。需要灰度/秒级熔断自定义过滤器时,从配置中心读一个开关返回即可,不用改代码发版。

