Reputation: 5289
I have an @Service
class which contains a List
of other @Service
classes. That List
basically contains all the services which implements UniformEventsResearchApi
.
Being a rookie with Spring, I'm not sure how I can get Spring to allow me to follow the Open-Closed Principle and thus having that list automagically injected with all of the concrete implementations.
Here is an incomplete UML class diagram:
And here is some "code":
@Service
public class EventsResearchService {
// todo: this should be Injected automatically
private List<UniformEventsResearchApi> eventsResearchApis = Arrays.asList(new EventbriteApi());
// Already tried, but without success:
//
// @Autowired
// private List<UniformEventsResearchApi> eventsResearchApis2;
//
// @Autowired
// @Qualifier("EventsResearchApi")
// public void setXList(List<UniformEventsResearchApi> apis) {
// this.eventsResearchApis2 = apis;
// }
}
@Service
@Qualifier("EventsResearchApi")
public interface UniformEventsResearchApi { /* ... */ }
public abstract class EventsResearchApi implements UniformEventsResearchApi { /* ... */ }
/** Any class like this one which extends EventsResearchApi should be automatically injected in the List */
public class EventbriteApi extends EventsResearchApi { /* ... */ }
Upvotes: 2
Views: 7678
Reputation: 42531
This is an easy task for spring actually:
You can auto wire a list of beans just like a regular bean In this case spring will indeed find all the beans that implement the interface and inject:
public interface SomeInterface {
}
@Component
public class SomeImpl1 implements SomeInterface {}
@Component
public class SomeImpl2 implements SomeInterface {}
@Service
public сlass SampleBean {
@Autowired
private List<SomeInterface> beans;
}
One note, there should be at least one implementation of beans available,
Otherwise Spring won’t let you such an injection. If you know that such a situation is possible you can inject Optional<List<SomeInterface>>
With field injection it looks rather ugly, but you can use constructor injection (which is better anyway) or consider using “java configuration”:
@Service
public class SampleBean {
private final List<SomeInterface> beans;
// I haven’t checked this with compiler, should work
@Autowired // optional, if you have a single constructor, you can omit it
public SampleBean(Optional<List<SomeInterface>> beans) {
this.beans = beans.orElse(Collections.emptyList());
}
}
Upvotes: 10