【问题解决】Tomcat启动服务时提示Filter初始化或销毁出现java.lang.AbstractMethodError错误
问题背景
最近在开发项目接口,基于SpringBoot 2.6.8,最终部署到外置Tomcat 8.5.85 下,开发过程中写了一个CookieFilter,实现javax.servlet.Filter接口,代码编译期正常。部署到外置Tomcat 8.5.85 下,在控制台上报错:
16-Jan-2023 16:11:07.756 严重 [localhost-startStop-1] org.apache.catalina.core.StandardContext.filterStart 启动过滤器异常[cookieFilter]
java.lang.AbstractMethodError
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:281)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:109)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4604)
...省略其他输出...
日志截图如下:

除了初始化错误还有销毁错误,异常类型与以下的错误类型一致:
16-Jan-2023 16:11:07.876 严重 [localhost-startStop-1] org.apache.catalina.core.ApplicationFilterConfig.release 失败的销毁过滤器类型为[xx.CookieFilter]名称为[CookieFilter]
java.lang.AbstractMethodError
at org.apache.catalina.core.ApplicationFilterConfig.release(ApplicationFilterConfig.java:312)
at org.apache.catalina.core.StandardContext.filterStop(StandardContext.java:4638)
...省略其他输出...
日志截图如下:

我的代码差不多长这样:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class CookieFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//做一些处理...
filterChain.doFilter(request, response);
}
}
反复分析
- 首先要知道这个异常(java.lang.AbstractMethodError)是什么?

- 也就是说父子两个类编译时机不同,先编译父类,在编译子类前对父子类方法定义做了不兼容的修改,编译子类通过后,让子类与先编译的父类一起运行,导致运行期实例化子类时找不到父类定义抽象方法的实现,从而抛出AbstractMethodError错误。
- 根据Filter的生命周期,初始化init,运行期doFilter,销毁destroy,我们可以推测出是CookieFilter没有实现init方法与destroy方法
- 这里问题就来了:这里的父(接口)是javax.servlet.Filter,实现的CookieFilter只是一个Filter实现类,我们并没有办法修改Filter接口,按理说编译期就应该报错才对嘛,为啥能编译成功呢?
- 原因就在于在SpringBoot上使用Filter接口需要引用
javax.servlet:javax.servlet-api依赖包,这个包里定义的Filter接口的init()与destroy()是有默认实现的,代码如图: 
- 也就是说,我们编译期不重写init()与destroy()其实是可以的;
- 原因就在于在SpringBoot上使用Filter接口需要引用
- 但是运行在外置Tomcat8.5.x上的时候,这两个方法却要求必须实现了么?
- 有两种可能,一是Tomcat 8.5.x的共享库中有Filter定义,与我们需要的Filter不同,没有默认实现init与destroy方法;另一个可能是我们打的包中有两个包包含javax.servlet.Filter,运行期JVM加载顺序不一致就会引出不同的问题!
- 根据上边的猜测一,我找到了Tomcat 8.5.85的Filter源码https://github.com/apache/tomcat/blob/8.5.85/java/javax/servlet/Filter.java,我们发现在第67行init方法的确没有default关键字修饰,destroy方法也是这样的,第一个猜测是成立的
- 根据猜测二,我在程序War包中找到了两个servlet-api包:javax.servlet-api与servlet-api,前者版本较后者新。问题分析到这里就可以做解决方案了。
解决方案
- 方案一:不管新旧servlet-api包,所有Filter都添加默认init与destroy方法
- 方案二:升级外置Tomcat版本到9.x,原因是9.x的Tomcat的共享库Filter有默认实现init与destroy方法
- 方案三:构建排除较新的javax.servlet-api包,继续使用Tomcat 8.5.x,同样地所有Filter都要添加init与destroy方法,空的方法也可以。
- 方案四:使用内嵌Tomcat9.x部署,构建排除旧版servlet-api包
- 方案五:构建排除javax.servlet-api包与旧版servlet-api包,代码改造添加init与destroy方法,以共享库定义Filter为主
- 方案六:不大推荐。构建排除旧版servlet-api包,仍部署在Tomcat 8.5.x,有可能会加载到共享库里的Filter
这几种方案中对于研发层面最简单避免这个问题的就是方案一,这里的解决方案是抛砖引玉,欢迎大家评论给出更优解。我是Hellxz,下次博客见。
【问题解决】Tomcat启动服务时提示Filter初始化或销毁出现java.lang.AbstractMethodError错误的更多相关文章
- Struts2环境下Tomcat启动异常:Exception starting filter struts2,报了一个java.lang.ClassNotFoundException
在写一个struts2+hibernate整合的小例子时,启动Tomcat服务器,报了一个: 严重: Exception starting filter struts2java.lang.ClassN ...
- mysql启动服务时提示"服务名无效"
1,首先说明一下我的环境,我刚开始是用的XAMPP这个集成的软件,里面安装了apache, mysql,tomcat这些软件,然后通过控制面板对其进行启动关闭的操作,这些操作很方便,但是我就用net ...
- Mysql----mysql启动服务时提示"服务名无效"
1,首先说明一下我的环境,我刚开始是用的XAMPP这个集成的软件,里面安装了apache, mysql,tomcat这些软件,然后通过控制面板对其进行启动关闭的操作,这些操作很方便,但是我就用net ...
- eclipse中启动服务时提示端口被占的2种解决方案
出现类似这样的:port '19001' at localhost are already in use 第一种:在任务管理器中关闭相关eclipse进程,然后重启eclipse.这种方法可能有时候会 ...
- Tomcat连HBase报错: HTTP Status 500 - java.lang.AbstractMethodError: javax.servlet.jsp.JspFactory.getJspApplicationContext
Tomcat中连接HBase数据库,启动的时候报错: HTTP Status 500 - java.lang.AbstractMethodError: javax.servlet.jsp.JspFac ...
- 使用 ServerSocket 进行文件上传,以及用Tomcat启动ServerSocket时,会卡死解决
服务器端代码 import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOExcept ...
- PLSQL往Oracle数据库插入中文后变为问号 和 启动PLSQL时提示NLS_LANG在客户端不能确定的解决办法
PLSQL往Oracle数据库插入中文后变为问号 和 启动PLSQL时提示NLS_LANG在客户端不能确定的解决办法 1.检查服务器的字符编码 Select * from V$NLS_PARAMETE ...
- 启动Oracle时提示:ORA-01078:failure in processing system parameters
一.使用环境操作系统:CentOS release 6.2 (Final) 数据库:Oracle 12g数据库主目录:/ora12/product/product/12.1.0/db_1 二.问题描述 ...
- SpringBoot启动项目时提示:Error:java: 读取***.jar时出错;
场景 在IDEA中新建SpringBoot项目后,修改了默认的Maven仓库和配置文件,然后在启动项目时提示: Error:java: 读取\org\assertj\assertj-core\3.11 ...
- SpringBoot启动项目时提示:Error:(3, 32) java: 程序包org.springframework.boot不存在
场景 在IDEA中新建SpringBoot项目,后启动项目时提示: Error:(3, 32) java: 程序包org.springframework.boot不存在 实现 将pom.xml中par ...
随机推荐
- SpringBoot内置工具类,告别瞎写工具类了
不知大家有没有注意到,接手的项目中存在多个重复的工具类,发现其中很多功能,Spring 自带的都有.于是整理了本文,希望能够帮助到大家! 一.断言 断言是一个逻辑判断,用于检查不应该发生的情况 Ass ...
- 基于mnist的P-R曲线(准确率,召回率)
一.准确率,召回率 TP(True Positive):正确的正例,一个实例是正类并且也被判定成正类 FN(False Negative):错误的反例,漏报,本为正类但判定为假类 FP(False P ...
- 本人常用的sed命令用法
如果使用sed命令修改文件,需要为sed命令指定[-i]选项(i,insert表示插入指令),下面是本人常用到的几种场景: 1. 在文件最后一行的下一行添加配置 如:在配置文件/etc/profile ...
- 网页嵌入zabbix页面(不同域名)
先来结论: 方案一:绕过身份验证:https://www.cnblogs.com/JaSonS-toy/p/4939805.html(我不是这样实现,可以自行尝试) 方案二: 1.保证请求的ip与请求 ...
- 阿里云 ACK 接入观测云
简介 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理.2021 年成为国内唯一连续三年入选 Gartner 公共云容器报告的 ...
- 这么简单,还不会使用java8 stream流的map()方法吗?
一.前言 在日常的开发工作中经常碰到要处理list中数据的问题,比如从数据库中查出了很多学生,由于一些原因需要在内存中找出这些学生中的所有姓名,或者把名为"王五"的语文成绩暂时修改 ...
- C++编程笔记(GPU并行编程-2)
C++与CUDA 内存管理 封装 利用标准库容器实现对GPU的内存管理 #include <iostream> #include <cuda_runtime.h> #inclu ...
- 工程坐标转换方法C#代码实现
目录 1. 前言 2. 计算总体框架 3. C#代码实现 3.1 整体类的构建 3.2 椭球参数赋值 3.3 转换1.3(大地经纬度坐标与地心地固坐标的转换) 3.4 投影转换 3.5 转换2的实现( ...
- .net core 中 WebApiClientCore的使用
WebApiClient 接口注册与选项 1 配置文件中配置HttpApiOptions选项 配置示例 "IUserApi": { "HttpHost": &q ...
- 【ASP.NET Core】MVC控制器的各种自定义:IActionHttpMethodProvider 接口
IActionHttpMethodProvider 接口的结构很简单,实现该接口只要实现一个属性即可--HttpMethods.该属性是一个字符串序列. 这啥意思呢?这个字符串序列代表的就是受支持的 ...