初学者自定义过滤器继承抽象流时易忽视可见性权限,因抽象类不强制子类补全public修饰符,导致跨包调用失败;需为重写方法显式添加@override public,新增非私有方法一律声明public,并通过跨包测试提前暴露问题。

初学者在自定义过滤器继承抽象流(如 AbstractFilter 或类似骨架类)时,容易忽视可见性权限红线,核心原因在于:抽象类不强制子类补全访问修饰符,而 Java 默认的包级可见性(default)与接口契约要求的 public 存在隐性冲突——看似能编译、能测试,实则一跨包就失效。
抽象类不传递可见性约束
抽象流基类(如 Spring 的 OncePerRequestFilter、或自定义的 AbstractStreamFilter)通常只声明模板方法(如 doFilterInternal),且多为 protected 或 public。但子类中:
- 新添加的工具方法(如
validateToken())若没写public,默认只能同包调用; - 重写关键方法(如
init(FilterConfig config))若漏掉@Override public,仅写void init(...),就会变成包级方法; - 构造方法未显式声明
public,外部无法实例化,导致 Filter 注册失败或容器初始化报错。
接口契约与实现脱节
Java Servlet 规范中,Filter 接口所有方法(init、doFilter、destroy)都是 public。这意味着:任何实现类必须以 public 提供对应方法,否则违反契约。
但抽象基类不会帮你自动补上 public ——IDE 也不报错,单元测试常在同包下运行,一切正常;直到部署到 Web 容器(如 Tomcat),由容器反射调用时,因方法不可见而抛出 IllegalAccessError 或静默跳过过滤逻辑。
常见疏忽场景
- 在
doFilter重写中漏写public,只写void doFilter(...),导致容器无法调用; - 把自定义的
getAllowedPaths()设为包级,后续被其他模块(如权限中间件)反射调用失败; - 使用 Lombok 的
@RequiredArgsConstructor生成构造器,却忘了加@AllArgsConstructor(access = AccessLevel.PUBLIC),导致 Filter 实例化失败。
规避建议
- 所有重写方法前统一加上
@Override public,养成肌肉记忆; - 新增非私有方法,一律显式声明
public(除非明确设计为包内工具); - 启用 IDE 检查:如 IntelliJ 中开启 “Method may be ‘public’” 警告;
- 在测试中模拟跨包调用(新建测试模块不在同一 package),提前暴露问题。











