Reputation: 433
I'm confused by Spring's annotation based configuration.
I have an interface MyInterface and two classes (MyClass1 and MyClass2) which implement this interface.
@Component("MyInterface")
public class MyClass1 implements MyInterface {
public void execute() {
System.out.println("MyClass1 executed");
}
}
public class MyClass2 implements MyInterface {
public void execute() {
System.out.println("MyClass2 executed");
}
}
MyClass1 is created by using Component-Scan, MyClass2 is defined as a bean:
@Configuration
@ComponentScan(basePackageClasses = MyClass1Configuration.class)
public class MyClass1Configuration {
}
@Configuration
public class MyClass2Configuration {
@Bean(name = "MyInterface")
public MyInterface myClass2() {
return new MyClass2();
}
}
I build the application context by using Spring Test's ContextConfiguration annotation:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MyClass1Configuration.class, MyClass2Configuration.class})
public class SpringTestCase1 {
@Autowired
private MyInterface myInterface;
@Test
public void testMethod() {
System.out.println("testMethod invoked");
Assert.assertEquals(MyClass2.class, myInterface.getClass());
myInterface.execute();
}
}
Unfortunately the test failes as Class1 is autowired instead of Class2. The expected behaviour is that MyClass2Configuration overrides beans which are defined by MyClass1Configuration. What's my fault.
I created this example at GitHub, if you would like to take a look at a working example: https://github.com/OLibutzki/spring-test-configuration/tree/master/simple-sprint-test
Thanks for your help.
Kind regards Oliver
Upvotes: 2
Views: 20546
Reputation: 87
Some spring version is having issues and i tried to changed version from 2.1.3 to 2.0.2.RELEASE. It started working
Upvotes: 0
Reputation: 659
Or You can override it by using
spring.main.allow-bean-definition-overriding=true
in main/resource/application.properties
But it's error-prone
Upvotes: 5
Reputation: 34450
You're quite near... First, you cannot have 2 beans with the same name in the same Spring context, unless you're specifically allowing it, which I don't recommend since it's error-prone.
Besides that, you should use the @Primary
annotation, which can be applied both at method and type level. In your case, you should apply it at the method level in MyClass2Configuration
:
@Configuration
public class MyClass2Configuration {
@Bean
@Primary
public MyInterface myClass2() {
return new MyClass2();
}
}
As you're autowiring by type (and not by name), it doesn't seem to be useful to specifically allow overriding of bean definitions. You could let both beans live within Spring context, and then, by means of the @Primary
annotation, Spring will autowire your "primary" bean instance.
Upvotes: 3