Search code examples
javaspringspring-ioc

Inject all beans with a specific annotation


I've been using Spring for decades, but never ran into this use-case before.

Is there a way to inject all the beans annotated with a specific annotation, e.g. all beans with @Service or all with @CustomAnnotation?

The only idea I have is to inject the context, get all the beans and filter manually. If this is the only way, does Spring expose a method that recursively scans a class hierarchy for (meta) annotations (as most Spring annotations can be used as meta-annotations)?


Solution

  • The @ComponentScan annotation specifies includeFilters and excludeFilters attributes.
    To scan only classes decorated with @Service you could disable useDefaultFilters and include only the Service annotation :

    @ComponentScan(useDefaultFilters = false,
                    includeFilters = @Filter(Service.class))
    

    To scan only custom annotations, you could write a similary thing :

    @ComponentScan(useDefaultFilters = false,
                    includeFilters = @Filter(CustomAnnotation.class))
    

    As multiples classes are specified in value/classes of @Filter, a OR logic is applied.


    Note that the @Filter annotation accepts class(es) as value/classes attribute but these are interpreted by Spring according to the type value of @Filter.
    By default, type has as value FilterType.ANNOTATION.
    To filter on a specific annotation (as you in your case), this default value suits as you want to filter candidates on the annotation itself.

    Here values defined in the FilterType enum class :

    public enum FilterType {     
        ANNOTATION,    
        ASSIGNABLE_TYPE,
        ASPECTJ,
        REGEX,
        CUSTOM    
    }
    

    Note also that @Filter works with classes/value but not only.
    You have indeed two alternative ways :

    • valuing the classes/value attribute (as in your case)

    • valuing pattern attribute.

    The first way expects to have as type : ANNOTATION, ASSIGNABLE_TYPE or CUSTOM.
    While the second way expects to have as type : REGEX or ASPECTJ.