【问题标题】:How to enforce loading order of spring configuration classes?如何强制执行弹簧配置类的加载顺序?
【发布时间】:2014-08-08 20:03:50
【问题描述】:

我正在一个多模块项目(maven)上使用 spring-boot。每个模块都有自己的 @Configuration 类。基本上我确实有以下布局

模块 foo-embedded (runs 只调用 SpringApplication.run()) 方法:

@Configuration
@EnableAutoConfiguration
@ComponentScan("de.foobar.rootpackage")
@Import({ApplicationConfig.class, RepositoryConfig.class, SecurityConfig.class})
public class FooApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(FooApplication.class, args);
    }
}

模块 foo-common(包含所有 bean 和 spring-data-jpa 初始化配置)

@Configuration
@EnableJpaRepositories
@EnableTransactionManagement(entityManagerFactoryRef="entityManagerFactory")
public class RepositoryConfig {

    @Bean(destroyMethod = "shutdown")
    public DataSource getDataSource() {
        // returning a Hikari CP here
    }

    @Bean(name = "entityManagerFactory") // overriding spring boots default
    public EntityManagerFactory getEntityManagerFactory() {
        // returning a new LocalEntityManagerFactoryBean here
    }
}

模块 foo-security(包含 spring-securiy 配置和相关域类),对 foo-common 有一个 maven 依赖

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // configuring HTTP security and defining my UserDetailsService Bean
}

当我使用 FooApplication 类启动应用程序时,一切都按预期工作。上面提到的 UserDetailsS​​erviceImpl 与我的 UserRepository 自动装配,这是通过 @EnableJpaRepositories 注释创建的。

因为我想编写一些集成测试,所以我在我的一个模块中添加了一个测试类。

模块 foo-media(包含一些与领域相关的内容以及该模块的测试用例)

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {RepositoryConfig.class, SecurityConfig.class})
@WebAppConfiguration
@IntegrationTest
public class DirectoryIntegrationTest {
    // my test code
}

当我运行测试时,似乎 SecurityConfiguration 在 RepositoryConfig.class 之前加载。由于安全配置定义了必须自动装配的 UserServiceImpl,因此测试无法以 a 开始

NoSuchBeanDefinitionException telling me: No qualifying bean of type [com.foo.rootpackage.security.repository.UserRepository]

我已经尝试在 UserDetailsService 的 bean 定义中添加 @DependsOn("UserRepository"),告诉我 spring 找不到该名称的 bean。

任何提示或帮助将不胜感激!提前致谢!

---- EDIT(因为我被要求提供更多代码)----

为了测试,我不使用实际的 RepositoryConfig.class,但在公共模块中有一个 TestRepositoryConfig.class。看起来像这样

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", basePackages = "de.foobar.rootpackage")
public class TestRepositoryConfig extends RepositoryConfig {

    @Bean
    @Override
    public DataSource getDataSource() {
        // returning the ds for testing
    }
}

【问题讨论】:

  • 尝试通过 @Configuration("RepositoryConfig") 显式命名 RepositoryConfig bean,然后执行 @DependsOn("RepositoryConfig")
  • 不幸的是没有帮助。但是,从我现在的想法来看,订单是不相关的。启动时找不到存储库,因为没有定义要搜索的基本包。添加 @EnableJpaRespositores(basePackages = {"de.foobar.rootpacke"}) 至少给了我存储库。一旦正确运行,我将提供完整配置
  • 你能发布小的可编译代码,重现你的问题吗?一个可能的原因 - 在测试课上缺少 @ComponentScan("de.foobar.rootpackage")

标签: java spring maven spring-boot


【解决方案1】:

您可以在配置类上使用@Order 注释来定义加载顺序。但这很奇怪,因为 Spring 应该解决正确的顺序 - 所以请检查您是否在 UserDetailsService 中注入了 UserRepository 属性

【讨论】:

    【解决方案2】:

    所以我能够解决这个问题。正如它指出的那样,它与配置类的加载顺序无关(这是我的第一个想法)。

    您可能会注意到,唯一具有 @ComponentScan 注释的配置是 FooApplication.class Spring 无法找到存储库,因为它不知道在哪里寻找。像这样提供 basePackages 属性:

    @EnableJpaRepositories(basePackages = "de.foobar.rootpackage")
    

    在 TestRepositoryConfig.class 中做到了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-04
      • 1970-01-01
      • 2010-12-23
      • 2016-04-26
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      • 2021-10-03
      相关资源
      最近更新 更多