Spring Boot 3.4.4升级后JUnit测试报jpaMappingContext元模型非空错误
问题现象
将Spring Boot版本从3.4.3升级到3.4.4后,某个JUnit测试抛出以下异常:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.health.HealthContributor]: Factory method 'dbHealthContributor' threw exception with message: Error creating bean with name 'jpaMappingContext': Metamodel must not be null
该测试在3.4.3版本下可正常运行,移除测试类中的以下代码后,3.4.4版本测试恢复正常,但暂不清楚原因:
@MockBean EntityManagerFactory entityManagerFactory;
可复现代码
主类
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
测试代码
Base类
import org.apache.camel.Message; public class Base { protected Exchange getExchange(final String body) { final Message message = new Message() { // 方法的默认实现 }; message.setBody(body); DefaultExchange exchange = new DefaultExchange(MyProcessorTest.EarlyConfiguration.camelContext); exchange.setMessage(message); return exchange; } }
测试类
import jakarta.persistence.EntityManagerFactory; @ExtendWith(SpringExtension.class) @SpringBootTest(properties = { "test.configuration.class=MyProcessorTest" }) @EnableAutoConfiguration(exclude = { CamelAutoConfiguration.class }) class MyProcessorTest extends Base { @Test void test() { assertEquals(1, 1); } @TestConfiguration @ConditionalOnProperty(name = "test.configuration.class", havingValue = "MyProcessorTest") public static class EarlyConfiguration { @MockBean public static CamelContext camelContext; @MockBean EntityManagerFactory entityManagerFactory; } }
pom.xml
<parent> <!-- spring-boot-starter-parent 3.4.4 --> </parent> <properties> <java.version>17</java.version> <camel.version>4.10.2</camel.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-spring-boot</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jms</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency> </dependencies>
application.yaml
server: port: 9102 shared_root: "tmp/shared/tfd" spring: datasource: url: jdbc:h2:mem:mydb;Mode=Oracle;NON_KEYWORDS=KEY,VALUE username: sa password: password driverClassName: org.h2.Driver jpa: show-sql: true hibernate: ddl-auto: none test: database: replace: none
问题原因分析
Spring Boot 3.4.4中,Actuator的数据库健康检查组件(dbHealthContributor)依赖JPA的jpaMappingContext,而jpaMappingContext需要从EntityManagerFactory获取JPA元模型(Metamodel)。
用@MockBean手动模拟EntityManagerFactory时,默认的Mock对象不会初始化元模型相关属性。3.4.3版本中,健康检查组件对元模型的校验更宽松,或者初始化顺序不同,未触发校验;但3.4.4版本强化了这部分依赖校验,导致Mock的EntityManagerFactory因缺少元模型抛出异常。
移除@MockBean EntityManagerFactory后,Spring Boot会自动配置基于H2内存数据库的真实EntityManagerFactory实例,该实例会正确初始化元模型,因此jpaMappingContext能正常创建,健康检查组件也能正常工作,测试恢复正常。
如果测试不需要操作JPA,也可考虑排除Actuator的数据库健康检查自动配置,或在测试中禁用健康检查相关配置,避免依赖EntityManagerFactory。
内容的提问来源于stack exchange,提问作者zilberman

