Как обеспечить порядок загрузки классов конфигурации spring?
Я работаю с spring -boot в проекте с несколькими модулями (maven). Каждый модуль имеет собственный класс @Configuration. В основном у меня есть следующий макет
Модуль foo-embedded (запускает только вызов метода 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 (содержит все конфигурации инициализации beans и 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 и связанные классы домена), которая имеет зависимость maven от foo-common
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// configuring HTTP security and defining my UserDetailsService Bean
}
Когда я запускаю приложение, используя класс FooApplication, все работает так, как ожидалось. Вышеупомянутый UserDetailsServiceImpl получает autwired с моим UserRepository, который создается через аннотацию @EnableJpaRepositories.
Поскольку я хочу написать некоторые интеграционные тесты, я добавил тестовый clss в один из моих модулей.
Модуль foo-media (содержащий некоторые связанные с доменом материалы плюс тестовые примеры для этого модуля)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {RepositoryConfig.class, SecurityConfig.class})
@WebAppConfiguration
@IntegrationTest
public class DirectoryIntegrationTest {
// my test code
}
Когда я запускаю тест, кажется, что SecurityConfiguration загружается до того, как RepositoryConfig.class делает. Поскольку в конфиге безопасности определен UserServiceImpl, который должен быть автообновлен, тест не запускается с
NoSuchBeanDefinitionException telling me: No qualifying bean of type [com.foo.rootpackage.security.repository.UserRepository]
Я уже пытался добавить @DependsOn("UserRepository")
в определение bean UserDetailsService
, сообщив, что 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
}
}
Ответы
Ответ 1
Так что я смог решить это. Как он отметил, это не имеет никакого отношения к порядку загрузки классов конфигурации (это была моя первая мысль).
Как вы можете заметить, единственной конфигурацией, в которой была аннотация @ComponentScan
, была FooApplication.class
Spring не смог найти Хранилища, поскольку он не знал, где искать. Предоставление атрибута basePackages следующим образом:
@EnableJpaRepositories(basePackages = "de.foobar.rootpackage")
в TestRepositoryConfig.class сделал трюк здесь.
Ответ 2
Вы можете использовать аннотацию @Order
в ваших классах конфигурации для определения порядка загрузки. Но это странно, потому что Spring должен разрешить правильный порядок - поэтому, пожалуйста, проверьте, если вы добавляете свойство UserRepository
в UserDetailsService