JBoss EAP 7.4自动重部署war失败 Keycloak重定向报500错误
问题现象
现有JBoss EAP 7.4.0环境,全量停服替换WAR包再重启的部署流程可正常运行;但使用部署目录热部署、jboss-cli执行undeploy/deploy命令部署时,日志显示应用部署成功,访问应用触发Keycloak SAML登录跳转时直接返回500错误,必须全量重启JBoss服务才能恢复正常。
原有可正常运行的手动部署流程:
- 完全关闭JBoss服务
- 将新的
.war文件复制到/jboss-eap-7.4.0/standalone/deployments目录 - 执行
standalone.sh脚本重启服务器
核心错误日志
2022-06-14 17:22:25,850 WARN [org.apache.jcp.xml.dsig.internal.dom.DOMReference] (default task-1) The input bytes to the digest operation are null. This may be due to a problem with the Reference URI or its Transforms.
2022-06-14 17:22:25,879 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /myapplication: java.lang.RuntimeException: Could not create authentication request.
(中间调用堆栈省略)
Caused by: org.apache.xml.serializer.utils.WrappedRuntimeException: class org.apache.xml.serializer.ToXMLSAXHandler cannot be cast to class org.apache.xml.serializer.SerializationHandler (org.apache.xml.serializer.ToXMLSAXHandler is in unnamed module of loader 'deployment.myapplication.war' @15a25903; org.apache.xml.serializer.SerializationHandler is in unnamed module of loader 'deployment.myapplication.war' @68ae4310)
(底层调用堆栈省略)
根因定位
该问题属于应用侧类加载配置错误,并非JBoss服务器故障:
- 报错核心原因是类加载器隔离失效:两个同名的
org.apache.xml.serializer相关类分别被两个不同的WAR类加载器实例加载,JVM中不同类加载器加载的同名类会被判定为完全不同的类型,直接触发类型转换异常。 - 热部署/CLI部署时,旧版本应用的类加载器没有被完全回收(类加载器泄漏),作为JBoss全局模块存在的Keycloak SAML适配器在生成SAML认证请求、调用XML序列化逻辑时,交叉引用了新旧两个类加载器内的XML处理类,触发报错。
- 全量重启JBoss时,所有类加载器会被完全销毁重建,不存在旧版本类残留,因此不会触发该问题。
- 触发类冲突的直接诱因是应用WAR包自带了
xalan、xml-serializer、xercesImpl等XML处理依赖,和JBoss自身提供的XML模块、Keycloak模块依赖的XML处理逻辑产生了类加载优先级冲突。
修复步骤
- 第一步:清理应用冗余依赖
解压WAR包检查WEB-INF/lib目录,找到xalan、xml-apis、xml-serializer、xercesImpl这类XML处理依赖,在构建配置(Maven/Gradle)中将这些依赖的作用域修改为provided,不打包进WAR包,直接复用JBoss服务器内置的兼容XML实现。 - 第二步:配置JBoss部署类加载规则(若应用必须自带指定版本XML依赖)
在应用的WEB-INF目录下新增jboss-deployment-structure.xml配置文件,排除服务器自带的对应XML模块,强制类加载隔离,避免全局模块跨上下文加载WAR包内的类,配置示例如下:<jboss-deployment-structure> <deployment> <exclusions> <module name="org.apache.xalan" /> <module name="org.apache.xml.serializer" /> <module name="org.apache.xerces" /> </exclusions> </deployment> </jboss-deployment-structure> - 第三步:验证修复效果
启动JBoss服务后,通过热部署/CLI命令部署新版本WAR包,访问应用触发SAML登录流程,若能正常跳转到Keycloak登录页、不再抛出类转换异常即为修复成功。
补充排查点
如果完成上述配置后仍偶发热部署报错,需要检查应用代码中是否存在静态集合、单例对象、线程池任务持有类/类加载器引用的逻辑,这类逻辑会导致热部署时旧类加载器无法被GC回收,持续引发类冲突。
内容的提问来源于stack exchange,提问作者pats

