Spring Filter Components From Component Scanning
When using auto component scanning, only the special marker interfaces and annotations that itself are annotated with @Component
are eligible. We can modify and/or extend this behavior by applying custom filters. We can use include-filters or exclude-filters, these filters can be configured as a sub-element of the component-scan element or @ComponentScan annotation. At the moment of writing there are 5 filter types which we can use, we’ll list them below:
- annotation
com.memorynotfound.SomeAnnotation
– filter by precense annotation. - assignable
com.memorynotfound.SomeClass
– filter by class/interface. - aspectj
com.memorynotfound..*Repository+
– filter by AspectJ type expression. - regex
com\.memorynotfound\.Default.*
– filter by regex expression. - custom
com.memorynotfound.MyTypeFilter
– filter by custom implementation ofTypeFilter
.
Filter Components
To demonstrate the exclude filter we created a bean and annotated it with @Component
, so this bean would normally be automatically picked up by spring component scanner.
package com.memorynotfound.spring.core.component;
import org.springframework.stereotype.Component;
@Component
public class ExcludeBean {
}
Next we create two beans which are not annotated with @Component
or any of the other marker annotations. So this bean isn’t eligible for component scanning by the default scanner.
package com.memorynotfound.spring.core.component;
import org.springframework.beans.factory.annotation.Autowired;
public class UserService {
@Autowired
private UserRepository userRepository;
public void save(){
userRepository.save();
}
}
Also no @Component
registered.
package com.memorynotfound.spring.core.component;
public class UserRepository {
public void save(){
System.out.println("saving user");
}
}
Filter Components From Component Scanning XML
The include-filter can be used to specify which beans should be included. The exclude-filter can be used to ignore beans. Both filters have a type and a expression attribute which is used to configure the filter. In this example we include all beans which have Service or Repository in their name. Note that these beans are not annotated with the @Component
annotation. But they could have.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.memorynotfound">
<context:include-filter type="regex" expression=".*Service"/>
<context:include-filter type="regex" expression=".*Repository"/>
<context:exclude-filter type="assignable" expression="com.memorynotfound.spring.core.component.ExcludeBean"/>
<context:exclude-filter type="annotation" expression="org.springframework.context.annotation.Configuration"/>
</context:component-scan>
</beans>
Filter Components From Component Scanning Java Config
Here is the same configuration as above using java configuration. We use the includeFilters and excludeFilters to add appropriate filters to component scanning. We register a filter using the @Filter
.
package com.memorynotfound.spring.core.component;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan(basePackages = "com.memorynotfound",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Service.*Repository"),
excludeFilters = {
@Filter(type = FilterType.ASSIGNABLE_TYPE, value = ExcludeBean.class),
@Filter(Configuration.class)
})
public class AppConfig {
}
First we make sure our include-filters work. We invoke the UserService#save()
method to show the beans are available in the spring container. Next we try to get a reference to the ExcludeBean
but this will throw a NoSuchBeanDefinitionException
because no bean definition exists of type ExcludeBean
in the spring container.
package com.memorynotfound.spring.core.component;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Run {
public static void main(String... args) {
//ApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.save();
// this will fail
ExcludeBean excludeBean = context.getBean(ExcludeBean.class);
System.out.println(excludeBean);
}
}
Output.
saving user
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.memorynotfound.spring.core.component.ExcludeBean] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:372)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1066)
at com.memorynotfound.spring.core.component.Run.main(Run.java:16)