Home Spring Framework Filter Types in Spring @ComponentScan

Filter Types in Spring @ComponentScan

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.

  1. ANNOTATION
  2. ASSIGNABLE_TYPE
  3. ASPECTJ
  4. REGEX
  5. 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.

@ComponentScan Filter Type

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.

9. References

  1. Spring Reference Document
  2. Spring Java Document

Other Related Tutorials:

  1. Spring @Autowired
  2. Spring @Lazy
  3. Spring Boot XML Configuration
  4. Spring Injecting Collection
  5. Spring @Order
  6. Spring @Primary
  7. Spring @Import
  8. Spring @ComponentScan

LEAVE A REPLY

Please enter your comment!
Please enter your name here