spring-bootcomponent-scan

Spring Boot: scanning components into an injectable list or set


Spring Boot here. I have dozens and dozens of classes that are all subclass/implementations of the same interface:

public interface AnimalService {
    void eat();
    // etc.
}

@Component
public class DogService implements AnimalService {
    @Override
    public void eat() { return ... }

    // etc.
}

// many many many of these

I have a @Service-annotated class (AnimalService) that needs to be injected with each one of these subclasses:

@Service
public class AnimalProcessingService {

    @Autowired
    private List<AnimalService> allAnimalServices; // DogService, SharkService, etc.

    // the rest of the class definition is omitted intentionally

}

Now I could do this injection the hard way:

@Configuration
public class AnimalConfig {

    private DogService dogService;
    private SharkService sharkService;
    // ...etc.

    @Bean
    public List<AnimalService> allAnimalServices() {
        return Arrays.asList(dogService, sharkService /*, ...etc. */);
    }

}

But there's gotta be an easier way to do this, right?

How can inject this List<AnimalService> without having to manually create the list? Does this method allow you to filter out certain candidates (like if I just want a subset of the animal services)? Ideally something annotation-based (even if I have to define my own annotations) that works with Spring autowiring/DI/component scanning. Thanks for any and all help here!


Solution

  • Essentially you're looking for @ComponentScan, which is a Spring (not Boot) annotation. It allows you to define a list of packages for Spring to scan for @Components (or "sub-annotations" such as @Service), to automatically instantiate beans of those classes and add them to the Spring context. So you can consider it a more automated way of the more manual @Bean method declaration.

    Since you're using Spring Boot, however, you might want to look into @SpringBootApplication which, when used, enables component scan automatically. All you have to do is making sure your @Component classes are defined in the same package as, or sub-packages of, the @SpringBootApplication-annotated class.

    Once you've enabled component scanning, you can just inject a List<AnimalService> where you need it, like in a constructor, and do your processing (filtering?) there.