Oliver
Oliver

Reputation: 433

Override bean definition doesn't work as expected

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

Answers (3)

user2724604
user2724604

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

Pushpak Sharma
Pushpak Sharma

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

fps
fps

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

Related Questions