Spring Boot+Wildfly21通过JNDI连接MongoDB类型转换异常排查
Spring Boot WAR部署Wildfly 21时JNDI连接MongoDB的类型转换异常排查
问题现象
部署Spring Boot WAR到Wildfly 21后,通过JNDI获取MongoClient时出现类型转换异常:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'java:global/MyMongoClient' is expected to be of type 'com.mongodb.client.MongoClient' but was actually of type 'com.mongodb.client.internal.MongoClientImpl'
即使直接注入实现类MongoClientImpl,异常信息显示预期与实际类型完全一致,但仍报错:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'java:global/MyMongoClient' is expected to be of type 'com.mongodb.client.internal.MongoClientImpl' but was actually of type 'com.mongodb.client.internal.MongoClientImpl'
当前配置
Wildfly 21 Standalone.xml 配置
<subsystem xmlns="urn:jboss:domain:naming:2.0"> <bindings> <object-factory name="java:global/MyMongoClient" module="org.mongodb" class="com.mongodb.client.MongoClientFactory"> <environment> <property name="connectionString" value="mongodb://localhost:27017"/> </environment> </object-factory> </bindings> <remote-naming/> </subsystem>
Wildfly MongoDB模块配置(module.xml)
<module xmlns="urn:jboss:module:1.3" name="org.mongodb"> <resources> <resource-root path="mongodb-driver-sync-4.6.1.jar"/> <resource-root path="mongodb-driver-core-4.6.1.jar"/> <resource-root path="bson-4.6.1.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> <module name="javax.servlet.api" optional="true"/> </dependencies> </module>
Java注入代码
@Resource(lookup = "java:global/MyMongoClient") private MongoClient mongoClient;
手动查找也报错:
Context ctx = new InitialContext(); mongoClient = (MongoClient) ctx.lookup("java:global/MyMongoClient");
原因分析
这是类加载器隔离导致的类型不兼容问题:
- Wildfly的模块系统为每个模块创建独立的类加载器,
org.mongodb模块中的MongoDB类由Wildfly模块加载器加载。 - Spring Boot WAR包中自带的MongoDB依赖(来自spring-data-mongodb或直接依赖)由Spring Boot的应用类加载器加载。
- JVM中,同一个类的全限定名如果由不同类加载器加载,会被视为完全不同的类型,因此即使类名一致,也无法相互转换。
解决方案
1. 排除Spring Boot WAR中的MongoDB依赖
修改项目的依赖配置,排除Spring Boot自动引入的MongoDB驱动,让应用使用Wildfly模块提供的类:
Maven配置(pom.xml)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> <exclusions> <exclusion> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-sync</artifactId> </exclusion> <exclusion> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-core</artifactId> </exclusion> <exclusion> <groupId>org.mongodb</groupId> <artifactId>bson</artifactId> </exclusion> </exclusions> </dependency>
Gradle配置(build.gradle)
implementation('org.springframework.boot:spring-boot-starter-data-mongodb') { exclude group: 'org.mongodb', module: 'mongodb-driver-sync' exclude group: 'org.mongodb', module: 'mongodb-driver-core' exclude group: 'org.mongodb', module: 'bson' }
2. 配置WAR包依赖Wildfly的MongoDB模块
在WAR包的WEB-INF目录下创建jboss-deployment-structure.xml,声明依赖Wildfly的org.mongodb模块:
<?xml version="1.0" encoding="UTF-8"?> <jboss-deployment-structure> <deployment> <dependencies> <module name="org.mongodb" export="true"/> </dependencies> </deployment> </jboss-deployment-structure>
3. 确保Spring Boot使用Wildfly类加载器
- 你的Spring Boot主类必须继承
SpringBootServletInitializer,这是WAR部署的必要配置:
@SpringBootApplication public class YourApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(YourApplication.class); } public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
- 在
application.properties中添加配置,避免类加载冲突:
spring.jmx.enabled=false
4. 验证版本兼容性
确认Wildfly模块中的MongoDB驱动版本(4.6.1)与Spring Data MongoDB(3.4.13)兼容:Spring Data MongoDB 3.4.x官方兼容MongoDB驱动4.4.x-4.7.x,4.6.1符合要求,无需调整版本。
内容的提问来源于stack exchange,提问作者Haseeb
相关产品推荐
相关产品推荐

