Websphere采用PARENT_LAST部署时Web应用加载失败,遇Spring初始化异常
问题重现
我在WebSphere部署中采用PARENT_LAST类加载策略,却出现Web应用加载失败的异常:
Failed to load webapp: javax.servlet.ServletContainerInitializer: Provider org.springframework.web.SpringServletContainerInitializer not a subtype。相关异常日志片段如下:
[3/25/18 19:10:50:512 EDT] 00000078 SystemErr R com.ibm.ws.exception.RuntimeWarning: com.ibm.ws.webcontainer.exception.WebAppNotLoadedException: Failed to load webapp: Failed to load webapp: javax.servlet.ServletContainerInitializer: Provider o...
问题根源
这个错误的核心是类加载器隔离导致的类型不匹配:WebSphere本身自带了Servlet API的实现类,当你设置PARENT_LAST时,Web应用会优先加载自己war包中的类。如果你的war里包含了servlet-api或javax.servlet-api依赖,那么应用类加载器会加载这个依赖里的javax.servlet.ServletContainerInitializer接口,而Spring的SpringServletContainerInitializer实现的是这个接口;但WebSphere容器用的是自己类加载器加载的同名接口,这两个接口在JVM里被视为不同的类型,自然会抛出"not a subtype"的异常。
解决步骤
移除war包中的Servlet API依赖
因为WebSphere已经提供了Servlet API的实现,你的应用不需要把它打包进去。如果用Maven管理依赖,把Servlet API的依赖范围改成provided:<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>你的版本</version> <scope>provided</scope> </dependency>Gradle的话则设置
compileOnly:compileOnly 'javax.servlet:javax.servlet-api:你的版本'验证WebSphere类加载配置
登录WebSphere管理控制台,找到你的应用,进入类加载和更新检测页面:- 确认类加载顺序是
PARENT_LAST - 确保没有勾选"使用服务器类加载器加载应用程序"(该选项会让应用共享服务器的类加载器,可能破坏隔离)
- 确认类加载顺序是
清理WebSphere缓存
缓存残留的旧类也可能导致奇怪的冲突,操作步骤:- 停止WebSphere服务器
- 删除服务器profile目录下的
temp和wstemp文件夹(路径一般是profiles/你的Profile名称/temp、profiles/你的Profile名称/wstemp) - 重启服务器后重新部署应用
检查Spring与WebSphere版本兼容性
确保Spring版本和WebSphere支持的Servlet版本匹配:- WebSphere 8.5 支持 Servlet 3.0,对应Spring 3.2+版本
- WebSphere 9.0 支持 Servlet 4.0,对应Spring 5.x版本
版本不匹配也可能导致初始化类的兼容性问题。
内容的提问来源于stack exchange,提问作者iLearn

