jpa 从Sprint Boot 2.7迁移到3.1.4时,自动配置排除不再起作用

zvms9eto  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(104)

我们正在尝试将后端从Sping Boot 2.7迁移到3.1.4,遇到了自动配置排除的问题。
基本上,它是一个多模块项目,我们有一些使用DB存根类的REST控制器测试
一个小纲要

** Spring 申请**

@SpringBootApplication
@SpringBootConfiguration
@ComponentScan("com.contract.backend")
@EnableFeignClients(basePackages = {"com.contract.backend.*"})
public class Application {}

字符串
控制器SubscriberContractController正在调用一个SubscriberContractService服务,该服务正在调用一个Dao接口SubscriberContractDao(在持久化模块中)
该接口由常规DAO类SubscriberContractDBDao(本身调用JpaRepository)实现

package com.contract.backend.contract.persistence;

@Component
@AllArgsConstructor
@Profile("!stubdb")
public class SubscriberContractDBDao implements SubscriberContractDao {}


通过存根实现SubscriberContractStubDao返回静态数据

package com.contract.backend.contract.persistence;

public class SubscriberContractStubDao implements SubscriberContractDao {}


我们有以下配置类(在应用程序模块中)用于存根DAO

package com.contract.backend.application.configuration;

@Configuration
@Profile("stubdb")
@ComponentScan(
        basePackages = {"com.contract.backend"}
)
public class StubConfiguration {
    @Bean
    public SubscriberContractDao subscriberStubDao() {
        return new SubscriberContractStubDao();
    }
}


在应用程序模块的test/resources部分中,我们定义了要与“Biddb”配置文件bootstrap-Biddb.properties一起使用的排除配置(为了便于阅读,请换行)

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration


测试本身使用MockMvc

@SpringBootTest
@ActiveProfiles({"stubdb, DEV})
@ExtendWith({RestDocumentationExtension.class})
class SubscriberContractControllerDocTest {

    private MockMvc mockMvc;

    @BeforeEach
    public void setUp(WebApplicationContext webApplicationContext,
                      RestDocumentationContextProvider restDocumentation) {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .apply(documentationConfiguration(restDocumentation)
                        .uris()
                        .withScheme("https")
                        .withPort(443))
                .build();
    }
    
    // Test example
    @Test
    void should_retrieve_sub_contract_by_id() throws Exception {
        mockMvc.perform(get("/api/subscriber-contract/{id}", 2)
                        .contentType(APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document("subscriber-contract-by-id",
                        preprocessRequest(prettyPrint()),
                        preprocessResponse(prettyPrint()),
                        pathParameters(
                                parameterWithName("id").description("The id of the subscriber contract we want to retrieve")
                        ),
                        responseFields(
                                subscriberContractDtosFields()
                        )));
    }
}


在Sprint Boot 2.7上,这工作正常,与真实的DB或示例化的JPA无关,调用存根DAO。
迁移到Sping Boot 3.1.4(没有其他问题)后,我们得到以下内容:
保持配置不变,我们在启动任何测试时都会收到以下错误:

java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@379b4e86 testClass = com.contract.backend.application.contract.controller.SubscriberContractControllerDocTest,\
 locations = [], classes = [com.contract.backend.application.Application], contextInitializerClasses = [], activeProfiles = ["stubdb", "dev"], propertySourceLocations = [], \
 propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], \
 contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@e350b40, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@13e344d,\
 org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@740cae06,\
 org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, \
 org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@1ca3b418, \
 org.springframework.boot.test.context.SpringBootTestAnnotation@85e8c2c7],\
 resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]
 
 at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:143)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:127)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:191)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:130)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:241)

`Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaSharedEM_entityManagerFactory': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:377)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:135)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:688)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:512)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:942)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608)
[...]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:893)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1316)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:274)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:365)


但是,如果我们删除HibernateJpaAutoConfiguration排除:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration


所有的GET测试(不使用transactions)开始工作,但是那些命中@ translation的测试尝试通过entityManager示例连接到真实的(dev)DB,我们甚至可以看到HikariPool被示例化了

023-10-13 16:21:38.359  INFO 15604 --- [           main] o.s.b.t.m.w.SpringBootMockServletContext [--/--] : Initializing Spring TestDispatcherServlet ''
2023-10-13 16:21:38.359  INFO 15604 --- [           main] o.s.t.web.servlet.TestDispatcherServlet  [--/--] : Initializing Servlet ''
2023-10-13 16:21:38.360  INFO 15604 --- [           main] o.s.t.web.servlet.TestDispatcherServlet  [--/--] : Completed initialization in 1 ms
2023-10-13 16:21:38.373  INFO 15604 --- [           main] com.zaxxer.hikari.HikariDataSource       [--/--] : HikariPool-1 - Starting...
2023-10-13 16:21:39.378 ERROR 15604 --- [           main] com.zaxxer.hikari.pool.HikariPool        [--/--] : HikariPool-1 - Exception during pool initialization.

java.sql.SQLNonTransientConnectionException: Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused: no further information
    at org.mariadb.jdbc.client.impl.ConnectionHelper.connectSocket(ConnectionHelper.java:137)
    at org.mariadb.jdbc.client.impl.StandardClient.<init>(StandardClient.java:99)
    at org.mariadb.jdbc.Driver.connect(Driver.java:70)
    at org.mariadb.jdbc.Driver.connect(Driver.java:101)
    at org.mariadb.jdbc.Driver.connect(Driver.java:27)
    at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
[...]
Caused by: java.net.ConnectException: Connection refused: no further information
    at java.base/sun.nio.ch.Net.pollConnect(Native Method)
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672)
    at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:547)
    at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602)
    
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:466)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:601)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)
    at com.contract.backend.contract.service.SubscriberContractService$$SpringCGLIB$$0.createOrUpdate(<generated>)
    at com.contract.backend.application.contract.controller.SubscriberContractController.createOrUpdate(SubscriberContractController.java:123)
    at com.contract.backend.application.contract.controller.SubscriberContractController.create(SubscriberContractController.java:103)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    [...]
    at com.contract.backend.application.contract.controller.SubscriberContractControllerDocTest.should_create_subscriber_contract(SubscriberContractControllerDocTest.java:234)


在这种情况下,这里的SubscriberContractService. DataOrUpdate用**@ translation注解。奇怪的是,没有transaction的GET测试可以很好地命中SubscriberContractStubDao,而不是SubscriberContractDBDao.
所以我们迷路了.这在Sping Boot 2.7中再次运行良好,没有问题(包括排除
HibernateJpaAutoConfiguration**)
任何帮助将不胜感激

axzmvihb

axzmvihb1#

最后找到了解决方案,唯一需要的是将以下排除添加到前面的排除中:org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration

相关问题