☰ See All Chapters |
Spring @ComponentScan annotation Filters - includeFilters, excludeFilters
includeFilters and excludeFilters are used with @ComponentScan annoatation to excluded from bean creation. When no filters used and when you apply package to @ComponentScan annotation, spring instantiate components from specified packages for all those classes annotated with @Component, @Controller, @Service, and @Repository.
Spring provides different type of filters to configure component scanning. Filters can be of two types: include and exclude filters. As their names suggest, include filters specify which types are eligible for component scanning, while exclude filters specify which types are not.
The value for includeFilters, excludeFilters attribues should be of type @ComponentScan.Filter. We should specify the type of filter for type attribute of ComponentScan.Filter.
There are five types of filters available for ComponentScan.Filter :
ANNOTATION
ASSIGNABLE_TYPE
ASPECTJ
REGEX
CUSTOM
FilterType.ANNOTATION
The ANNOTATION filter type includes or excludes classes which are marked with given annotations.
Let's say, for example, we have created @ExcludeAnnotation annotation as below:
package com.java4coding.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ExcludeAnnotation { } |
We have annotated ClassA1 with @ExcludeAnnotation annotation.
package com.java4coding.packageA;
import org.springframework.stereotype.Component; import com.java4coding.annotation.ExcludeAnnotation;
@Component @ExcludeAnnotation public class ClassA1 { } |
Now we are using @ExcludeAnnotation to the filter:
package com.java4coding; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import com.java4coding.annotation.ExcludeAnnotation; @Configuration @ComponentScan(basePackages = {"com.java4coding.packageA","com.java4coding.packageB" }, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = ExcludeAnnotation.class)) public class SpringComponentScanAnnotationExample { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); try { ctx.register(SpringComponentScanAnnotationExample.class); ctx.refresh(); System.out.println("classA1 available?: " + ctx.containsBean("classA1")); System.out.println("classA2 available?: " + ctx.containsBean("classA2")); System.out.println("classA3 available?: " + ctx.containsBean("classA3")); System.out.println("classB1 available?: " + ctx.containsBean("classB1")); System.out.println("classB2 available?: " + ctx.containsBean("classB2")); } finally { ctx.close(); } } } |
Output:
FilterType.ASSIGNABLE_TYPE
The ASSIGNABLE_TYPE filter type includes or excludes classes which are extending the given class or implementing the given interface.
Let's say, for example, we have created Car annotation as below:
package com.java4coding.vehicles; import org.springframework.stereotype.Component;
@Component public class Car { } |
We have created class Audi which extends Car class.
package com.java4coding.vehicles;
import org.springframework.stereotype.Component;
@Component public class Audi extends Car{ } |
We have created class Train which does not extends Car class.
package com.java4coding.vehicles;
import org.springframework.stereotype.Component;
@Component public class Audi extends Car{ } |
Now, let's see How ASSIGNABLE_TYPE filter works to exclude beans:
package com.java4coding; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import com.java4coding.vehicles.Car;
@Configuration @ComponentScan(basePackages = {"com.java4coding.vehicles"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = Car.class)) public class SpringComponentScanAnnotationExample { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); try { ctx.register(SpringComponentScanAnnotationExample.class); ctx.refresh(); System.out.println("Car Bean available?: " + ctx.containsBean("car")); System.out.println("Audi Bean available?: " + ctx.containsBean("audi")); System.out.println("Train Bean available?: " + ctx.containsBean("train")); } finally { ctx.close(); } } } |
Output:
The REGEX filter type includes or excludes classes whose names match the regex pattern. Fully qualified names of class (along with package name) are used to compare with regex.
Now, let's see How REGEX filter works to exclude beans whose names starts with M.
package com.java4coding; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType;
@Configuration @ComponentScan(basePackages = {"com.java4coding.fruits"}, excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*[M](.*?)")) public class SpringComponentScanAnnotationExample { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); try { ctx.register(SpringComponentScanAnnotationExample.class); ctx.refresh(); System.out.println("Apple Bean available?: " + ctx.containsBean("apple")); System.out.println("Avacado Bean available?: " + ctx.containsBean("avacado")); System.out.println("Mango Bean available?: " + ctx.containsBean("mango")); } finally { ctx.close(); } } } |
Output:
FilterType. ASPECTJ
If you want to use AspectJ type pattern expression to filter the beans you have to use this filter on @ComponentScan. Make sure you have included dependency spring-aspects in the project. Below is our pom.xml.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.java4coding</groupId> <artifactId>ComponentScan_AspectJ_Filter</artifactId> <version>0.0.1-SNAPSHOT</version>
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> </dependencies>
<properties> <spring.version>4.2.4.RELEASE</spring.version> </properties>
</project> |
Now let us see how to exclude beans whose names starts with M using Aspectj pattern.
package com.java4coding; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType;
@Configuration @ComponentScan(basePackages = {"com.java4coding.fruits"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.java4coding.fruits.*M*")) public class SpringComponentScanAnnotationExample { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); try { ctx.register(SpringComponentScanAnnotationExample.class); ctx.refresh(); System.out.println("Apple Bean available?: " + ctx.containsBean("apple")); System.out.println("Avacado Bean available?: " + ctx.containsBean("avacado")); System.out.println("Mango Bean available?: " + ctx.containsBean("mango")); } finally { ctx.close(); } } } |
Output:
FilterType. CUSTOM
The CUSTOM filter type includes or excludes beans by using the custom programmatic filtering logic implemented in a class which extends TypeFilter class. By extending TypeFilter class we should implement match() method to write our filtering logic. Now we shall see an example to filter the class name which has particular string in its name. Below example will match if class name has “an” in its name. Fully qualified name (class name with package name) is used while matching.
package com.java4coding.customfilter;
import java.io.IOException;
import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter;
public class MyTypeFilter implements TypeFilter { private static final String filterStr = "an";
@Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { ClassMetadata classMetadata = metadataReader.getClassMetadata();
if (classMetadata.getClassName().contains(filterStr)) { return true; } return false; } } |
Now let us see how to exclude beans by using above custom Typefilter implementation.
package com.java4coding; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType;
import com.java4coding.customfilter.MyTypeFilter;
@Configuration @ComponentScan(basePackages = {"com.java4coding.fruits"}, excludeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class )) public class SpringComponentScanAnnotationExample { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); try { ctx.register(SpringComponentScanAnnotationExample.class); ctx.refresh(); System.out.println("Banana Bean available?: " + ctx.containsBean("banana")); System.out.println("Avacado Bean available?: " + ctx.containsBean("avacado")); System.out.println("Mango Bean available?: " + ctx.containsBean("mango")); } finally { ctx.close(); } } } |
Output:
All Chapters