Issue
I am moderately confused about the DI injection mechanism in Spring when having multiple beans with the same name/type. According to the exam slides from the Pivotal's "Core Spring" Course, Spring's behaviour with identical beans can be boiled down to:
- One can define same bean more than once
- Spring injects the bean defined last
- Using
@Order
, the loading mechanism (and thus, which bean is loaded last) can be modified
However, in the following example, Spring will ignore any @Order
annotations and inject the bean from the Config class last mentioned in the @Import
statement.
I'm therefore wondering whether the order of config classes in the @Import
annotation overrides any @Order
annotations. Or do I miss another important point?
Any hints are highly appreciated. Thanks Stack Overflow!
Main Configuration class
@Configuration
@Import({RogueConfig.class,RewardsConfig.class})
public class TestInfrastructureConfig {
// nothing interesting here, just importing configs
}
RewardsConfig
@Configuration
@Order(1)
public class RewardsConfig {
@Bean
public RewardNetwork rewardNetwork() {
System.out.println("This Bean has been loaded from: " + this.getClass().getName());
return new RewardNetworkImpl(null, null, null);
}
}
RogueConfig
@Configuration
@Order(2)
public class RogueConfig {
@Bean
public RewardNetwork rewardNetwork() {
System.out.println("This Bean has been loaded from: " + this.getClass().getName());
return new RewardNetworkImpl(null, null, null);
}
}
Test class
public class RewardNetworkTests {
ApplicationContext applicationContext;
@BeforeEach
void setUp() {
applicationContext = SpringApplication.run(TestInfrastructureConfig.class);
}
@Test
void injectingRewardNetworkBeanWithOrdering() {
RewardNetwork rewardNetwork = applicationContext.getBean(RewardNetwork.class);
assertNotNull(rewardNetwork);
}
}
No matter what values I assign @Order
, or if I use ordering at all, the result will always be:
This Bean has been loaded from: config.RewardsConfig$$EnhancerBySpringCGLIB$$62461c55
The only way to change this is to modify the Import annotation in my TestInfrastructureConfig
like so:
@Import({RewardsConfig.class,RogueConfig.class})
, which yields:
This Bean has been loaded from: config.RogueConfig$$EnhancerBySpringCGLIB$$6ca7bc89
I am wondering what needs to be done to allow the values defined in @Order
to take any effect.
Solution
I've been able to get Spring to use the @Order
annotations by loading the configurations directly ( i.e. without the detour through a @Configuration
class using @Import
):
@SpringJUnitConfig({RogueConfig.class, RewardsConfig.class})
public class CdiTest {
@Test
public void testCdiWithIdenticalBeans(@Autowired RewardNetwork rewardNetwork) {
assertThat(rewardNetwork).isNotNull();
}
}
With the @Order(2)
annotation on the RogueConfig class, this bean got loaded last, as shown in stdout:
This Bean has been loaded from: config.RogueConfig$$EnhancerBySpringCGLIB$$552b937f
It seems that when using @Import
in config classes it will load bean definitions in the order provided in the annotation, thus making any @Order
annotations on the respective config classes useless.
Answered By - Mike Floyd