21
votes

I'm working with spring-boot on a multi module project (maven). Each module has it's own @Configuration class. Basically I do have the following layout

Module foo-embedded (runs just calls the SpringApplication.run()) method:

@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);
    }
}

Module foo-common (contains all beans and spring-data-jpa initialization config)

@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
    }
}

Module foo-security (containing spring-securiy configuration and related domain classes), which has a maven dependency on foo-common

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

When I start the application using the FooApplication class, everything works as expected. The above mentioned UserDetailsServiceImpl get's autowired with my UserRepository which is being created through the @EnableJpaRepositories annotation.

Since I want to write some integration tests I've added a test clss to one of my modules.

Module foo-media (containing some domain related stuff plus test cases for that module)

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

When I run the test it seems that the SecurityConfiguration get's loaded before the RepositoryConfig.class does. Since the security config defined the UserServiceImpl which must be autowired, the test fails to start with a

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

I already tried to add @DependsOn("UserRepository") at the bean definition of UserDetailsService, telling me that spring can't find a bean by that name.

Any hints or help would be greatly appreciated! Thanks in advance!

---- EDIT (since I was asked to provide more code) ----

For testing I do not use the actual RepositoryConfig.class, but have a TestRepositoryConfig.class in the common module. Looking like this

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

    @Bean
    @Override
    public DataSource getDataSource() {
        // returning the ds for testing
    }
}
2
Try explicitly name the RepositoryConfig bean by doing @Configuration("RepositoryConfig") and then do @DependsOn("RepositoryConfig")billc.cn
That unfortunately didn't help. However from what I've figured now is, that the order is not relevant. On startup it's failing to find the repositories since there are no base packages defined to search for. Adding @EnableJpaRespositores(basePackages = {"de.foobar.rootpacke"}) gave me the repositories at least. I'll provide a full configuration once it's running correctlyMarkus
Can you post small compilable code, that reproduce you problem? One possible reason - missing @ComponentScan("de.foobar.rootpackage") on test class.Alexander Kudrevatykh

2 Answers

9
votes

You can use @Order annotation on your configuration classes to define load ordering. But it's strange because Spring should resolve proper order - so please check if you property inject UserRepository in UserDetailsService

6
votes

So I was able to solve this. As it pointed out it had nothing to do with the loading order of the configuration classes (which was my first thought).

As you may notice, the only Configuration that had a @ComponentScan annotation was the FooApplication.class Spring was not able to find the Repositories, as it didn't know where to look for. Providing the basePackages attribute like this:

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

at the TestRepositoryConfig.class did the trick here.