简体   繁体   中英

Spring: Injecting list of all concrete classes implementing an interface

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:

uml类图

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 { /* ... */ }

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());   
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM