In this tutorial, we will see the different type of @ComponentScan.Filter type options and including/excluding components from Spring component scanning.
1. @ComponentScan Filter Types
@ComponentScan.Filter declares the type filter to be used as an include filter or exclude filter. There are 5 types available.
- ANNOTATION
- ASSIGNABLE_TYPE
- ASPECTJ
- REGEX
- CUSTOM
Before we explore how to use above filter types let’s have a look at component classes available in application. We apply @ComponentScan Filter on these packages/classes.
2. FilterType.ANNOTATION
The ANNOTATION filter type filters candidates marked with a given annotation. You can either include or exclude components those are marked with specific annotation. Let’s see an example, suppose that we have @Mammal annotation.
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Mammal { }
Following are the components those are annotation with @Mammal annotation.
@Mammal public class Bear { } @Mammal public class Tiger { } @Mammal public class Whale { }
Let’s use the FilterType.ANNOTATION to tell Spring to scan for annotated classes with @Mammal annotation.
useDefaultFilters indicates whether automatic detection of classes annotated with @Component @Repository, @Service, or @Controller should be enabled, by default is true. We are disabling it to find components specifically annotated with @Mammal.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Mammal.class)) public class ScanAnnotationFilterConfig { }
Testing:
public class ScanAnnotationFilterConfigDemo { public static void main(String[] args) { ApplicationContext ctxt = new AnnotationConfigApplicationContext(ScanAnnotationFilterConfig.class); String[] springComponents = ctxt.getBeanDefinitionNames(); for(String bean : springComponents) System.out.println(bean); } }
Results:
You will see following spring-beans available in application context.
scanAnnotationFilterConfig bear tiger whale
3. FilterType.ASSIGNABLE_TYPE
The ASSIGNABLE_TYPE filter type filter candidates assignable to a given type. The component classes can be implementation classes if the given type is interface OR can be child classes if given types is a concrete class.
Implementing Amphibian interface.
public interface Amphibian { } public class Frog implements Amphibian { } public class Newt implements Amphibian { } public class Toad implements Amphibian { }
Extending Crocodle class.
public class Crocodle { } public class DwarfCrocodle extends Crocodle { } public class NileCrocodle extends Crocodle{ } public class OrinocoCrocodle extends Crocodle{ } public class SiameseCrocodle extends Crocodle{ }
Let’s use the FilterType.ASSIGNABLE_TYPE to tell Spring to scan for the classes which extending Crocodle class or implementing Amphibian interface.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Amphibian.class, Crocodle.class})) public class ScanAssignableTypeFilterConfig { }
Testing:
public class ScanAssignableTypeFilterConfigDemo { public static void main(String[] args) { ApplicationContext ctxt = new AnnotationConfigApplicationContext(ScanAssignableTypeFilterConfig.class); String[] springComponents = ctxt.getBeanDefinitionNames(); for(String bean : springComponents) System.out.println(bean); } }
Results:
scanAssignableTypeFilterConfig frog newt toad crocodle dwarfCrocodle nileCrocodle orinocoCrocodle siameseCrocodle
4. FilterType.ASPECTJ
The ASPECTJ filter type, Filter candidates matching a given AspectJ type pattern expression. which is useful to filter complex matched patterns.
Let’s say we need to scan classes only whose name ends with Cobra and does not contain Mono within reptiles
package. Let’s see an example, to filter components using ASPECTJ expression.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal.reptiles", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "*..*Cobra && !(*..Mono*)")) // pattern = "*..Black* || *..E*)" public class ScanAspectJFilterConfig { }
Testing:
public class ScanAspectJFilterConfigDemo { public static void main(String[] args) { ApplicationContext ctxt = new AnnotationConfigApplicationContext(ScanAspectJFilterConfig.class); String[] springComponents = ctxt.getBeanDefinitionNames(); for(String bean : springComponents) System.out.println(bean); } }
Results:
Refer the snakes
package to understand results.
scanAspectJFilterConfig capeCobra egyptianCobra equatorialCobra
5. FilterType.REGEX
The REGEX filter type, filter candidates matching a given regular expression type pattern expression. which is useful to filter simple or fully-qualified class names.
Let’s say we need to scan classes whose name ends with Mamba. Let’s see an example, to filter components using REGEX expression.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*(Mamba)")) public class ScanRegexFilterConfig { }
Testing:
public class ScanRegexFilterConfigDemo { public static void main(String[] args) { ApplicationContext ctxt = new AnnotationConfigApplicationContext(ScanRegexFilterConfig.class); String[] springComponents = ctxt.getBeanDefinitionNames(); for(String bean : springComponents) System.out.println(bean); } }
Results:
Refer the snakes
package to understand results.
scanRegexFilterConfig blackMamba easternGreenMamba
6. FilterType.CUSTOM
Sometimes the above filter types sufficient for our requirement to filter components, in such cases we can create custom filter and can apply that using CUSTOM filter type.
In order to create our custom filter, need to implements org.springframework.core.type.filter.TypeFilter interface and provide the implementation for match method.
Let’s implement Custom Filter Type to filter classes those are implements Amphibian interface or class name ends with Crocodle.
public class CustomTypeFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { ClassMetadata classMetadata = metadataReader.getClassMetadata(); String[] interfaces = classMetadata.getInterfaceNames(); if (Arrays.stream(interfaces).anyMatch(Amphibian.class.getName()::equals)) return true; String className = classMetadata.getClassName(); if(className.endsWith("Crocodle")) return true; return false; } }
Let’s use the FilterType.CUSTOM to tell Spring to scan for the classes those names are ending with Crocodle or implementing Amphibian interface.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM, classes = CustomTypeFilter.class)) public class ScanCustomTypeFilterConfig { }
Testing:
public class ScanCustomFilterTypeConfigDemo { public static void main(String[] args) { ApplicationContext ctxt = new AnnotationConfigApplicationContext(ScanCustomTypeFilterConfig.class); String[] springComponents = ctxt.getBeanDefinitionNames(); for(String bean : springComponents) System.out.println(bean); } }
Results:
Refer amphibians
and crocodles
packages to understand results.
scanCustomTypeFilterConfig frog newt toad crocodle dwarfCrocodle nileCrocodle orinocoCrocodle siameseCrocodle
We have learned, how to use different Filter Types using @ComponentScan. Now let’s have a look at including and excluding specific classes or packages.
7. Including or Excluding using @ComponentScan Filter
We can exclude specific classes or packages to not detect them while scanning components using excludeFilters attribute. In all the above examples we have used includeFilters attribute.
7.1. Including Specific Classes
We can use FilterType.ASSIGNABLE_TYPE to filter specific classes for inclusion.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal.reptiles", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BlackMamba.class, NileCrocodle.class} )) public class IncludeSpecificClassesConfig { }
Results:
Like above examples, run the above configuration, you will see following results.
includeSpecificClassesConfig nileCrocodle blackMamba
7.2. Excluding Specific classes
Let’s say, only specific classes exclude from base package, you can use FilterType.ASSIGNABLE_TYPE.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal.reptiles", excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BlackMamba.class, EgyptianCobra.class, DwarfCrocodle.class})) public class ReptilesExcludeSpecificClassesConfig { }
Results:
reptilesExcludeSpecificClassesConfig crocodle snake turtle nileCrocodle orinocoCrocodle siameseCrocodle capeCobra easternGreenMamba equatorialCobra monocledCobra
7.3. Excluding Specific classes using Regex
Following example demonstrates how to exclude class name ends with Cobra from reptiles
package in component scanning using REGEX.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal.reptiles", excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*(Cobra)")) public class ReptilesExcludeClassesConfig { }
Results:
reptilesExcludeClassesConfig snake turtle dwarfCrocodle nileCrocodle orinocoCrocodle siameseCrocodle blackMamba easternGreenMamba
7.4. Excluding Specific Packages
Following example demonstrates excluding components from reptiles
package using filter.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal.reptiles", excludeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.javabydeveloper.spring.bean.animal.reptiles.*")) public class ReptilesExcludePackageConfig { }
Results:
reptilesExcludePackageConfig dwarfCrocodle nileCrocodle orinocoCrocodle siameseCrocodle blackMamba capeCobra easternGreenMamba egyptianCobra equatorialCobra monocledCobra
7.5. Excluding sub packages
In the above example, we have filtered excluding components from reptiles
package. If you wants to exclude only from sub packages but not from base package, the following example demonstrates how to do that.
@Configuration @ComponentScan(basePackages = "com.javabydeveloper.spring.bean.animal.reptiles", excludeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.javabydeveloper.spring.bean.animal.reptiles.*..*")) public class ReptilesExcludeAllSubPackagesConfig { }
Results:
reptilesExcludeAllSubPackagesConfig crocodle snake turtle
8. Conclusion
In this tutorial we have covered how to use different types of filters using @ComponentScan and including and excluding specific classes/packages using filters.
You can get source code at our GitHub repository.
9. References
Other Related Tutorials:
- Spring @Autowired
- Spring @Lazy
- Spring Boot XML Configuration
- Spring Injecting Collection
- Spring @Order
- Spring @Primary
- Spring @Import
- Spring @ComponentScan