Reputation: 727
I have a class, lets say 'DefaultService' which implements two interface: 'Service1' and 'Service2'. The Spring java config looks like below:
@Bean
Service1 defaultService() {
return new DefaultService();
}
Now, I have another bean Foo that requires 'Service2'.
public class Foo implements AnotherInterface {
@Autowired
private Service2 service2;
}
and this bean is configured through Java config too:
@Bean
AnotherInterface anotherInterface(){
return new Foo();
}
Spring doesnt like this configuration. I suppose it makes sense, as 'DefaultService' is exposed as 'Service1', and not 'Service2' (which Foo requires).
No qualifying bean of type [...Service2] found for dependency: expected at least 1 bean which qualifies ...
I can, of course, expose DefaultService as Service2. But what if there is another bean that requires Service1? What is Spring recommendation for this scenario? Another (weird) problem that I found, is that the following configuration works:
@Bean
Service2 defaultService(){ // exposing the bean as Service2, to fix dependency on Foo
return new DefaultService();
}
@Bean
AnotherDependant anotherDependant(Service1 service1){
return new AnotherDependant(service1);
}
How can Spring wires Service1 to the configuration declaration of 'AnotherDependant' (where it wasnt happy for @Autowired I had for the first scenario) ? I'm using Spring 3.2.2.RELEASE, although I doubt the version really matters..
The best workaround I have is:
@Bean
DefaultService defaultService(){
return new DefaultService();
}
@Bean
Service1 service1(){
return defaultService();
}
@Bean
Service2 service2(){
return defaultService();
}
But this is quite ugly...
======================================================================= Replying to @Oskar. Basically what @Oskar was suggesting is the same as declaring two in xml.. i.e. create two instances of same class in the spring container.
public interface Driveable {}
public interface Vehicle {}
public class Car implements Vehicle, Driveable{}
@Configuration
public class Config {
@Bean
public Vehicle vehicle() {
return new Car();
}
@Bean
public Driveable driveable() {
return new Car();
}
}
public class Main {
public static void main(String[] args) {
final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
final Driveable driveable = context.getBean("driveable", Driveable.class);
final Vehicle vehicle = context.getBean("vehicle", Vehicle.class);
System.out.println(driveable == vehicle);
}
}
Upvotes: 2
Views: 4292
Reputation: 1755
public interface Driveable {}
public interface Vehicle {}
@Component
public class Car implements Vehicle, Driveable{}
@Configuration
public class Config {
@Autowired
private Car car;
@Bean
public Vehicle vehicle() {
return car;
}
@Bean
public Driveable driveable() {
return car;
}
}
public class Application {
public static void main(String[] args) throws Exception {
final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class, Car.class);
final Driveable driveable = context.getBean("driveable", Driveable.class);
final Vehicle vehicle = context.getBean("vehicle", Vehicle.class);
System.out.println(driveable == vehicle);
}
}
Taking the car example in the question,
Car car
in Config which is autowired.If we are using @ComponentScan
, Car component will be automatically picked. Else, if we are creating context on our own, we can pass the Car class in AnnotationConfigApplicationContext
constructor (as shown in code).
Upvotes: 2