Solution with invalid SpringBoot @ CompentScan excludeFilters configuration

  • 2021-12-11 07:19:48
  • OfStack

Directory @ CompentScan excludeFilters Configuration Invalid FilterType @ ComponentScan excludeFilters Custom Filter 1. @ ComponentScan Role 2. Define Components 3. Test in Main Program Class 4. @ excludeFilters Use in ComponentScan

@ CompentScan excludeFilters configuration is invalid

@ CompentScan annotations configure packages to scan

excludeFilters is one of the configuration items to exclude classes that do not need to be scanned

FilterType

ANNOTATION : Exclude according to annotations ASSIGNABLE_TYPE Exclude based on class type ASPECTJ Exclude from AspectJ expression REGEX Exclude from regular expressions CUSTOM : To customize FilterClass exclusion, you need to implement org. springframework. core. type. filter. TypeFilter interface

In our project, module with one core, It stores package common to each project. However, some developers have also put an unrelated initialization operation into the core project. This leads to some useless initialization operations if the A project references core. Because there are too many sub-packages of core, it is the fastest to use exclusion method, and use REGEX for exclusion operation. However, after many attempts, the excluded classes are still scanned and initialized by spring. Is it ineffective? After many searches, I got inspiration in this article.

Each component scan does filtering individually. While you exclude Starter.class from SimpleTestConfig, SimpleTestConfig initializes Application, which does it's own @ComponentScan without excluding Starter. The clean way of using ComponentScan is for each ComponentScan to scan separate packages, that way each filter work fine. When 2 separate ComponentScans scan the same package (as in your tests), this does not work.

Each component scan is filtered individually. When you exclude Starter. class from SimpleTestConfig, SimpleTestConfig initializes Application, which executes @ ComponentScan without excluding Starter. A neat way to use ComponentScan is to scan individual packets for each ComponentScan so that each filter works properly. This will not work when two separate ComponentScans scans the same packet (as in testing).

In general, if you use the exlucde configuration in the A class, and some of the classes you don't need to exclude use @ ComponentScan in the annotation of B, but the exclude operation is not performed in the annotation of this class B, then your exclude in the A class will not take effect. Results After scanning the classes under core package under 1, there is indeed one class B that uses @ ComponentScan, so in A class, B class is also excluded, and exclude in A class is all effective.


@ComponentScan(
    basePackages = {"com.scio.core"},
    excludeFilters = {
      @Filter(type = FilterType.REGEX, pattern = "com\\.scio\\.core\\.B"),
      @Filter(type = FilterType.REGEX, pattern = "com\\.scio\\.core\\.message\\..*")
    })

@ ComponentScan excludeFilters Custom Filter

1. The role of @ ComponentScan

@ ComponentScan is used on a class or interface to specify the scan path and register the class with the specified annotation in the Spring container.

Annotations that will be automatically assembled include @ Component, @ Bean, @ Controller, @ Service, @ Repository, and so on.

2. Define components

1. @ Service annotated classes

When the MyService class is scanned, an instance named myBeanService is generated


package info.pigg.study.java.service;
import org.springframework.stereotype.Service;
@Service("myBeanService")
public class MyService {
}

2. @Configuration+@Bean

When the MyConfig class is scanned, two instances named myBeanPerson and myBeanUser are generated


package info.pigg.study.java.config;
@Configuration
public class MyConfig {
    @Bean(name = "myBeanPerson")
    public Person myBeanPerson(){
        return new Person("king", 31);
    }
    @Bean(name = "myBeanUser")
    public User myBeanUser(){
        return new User("king", 31);
    }
}

3. Test in the main program class

The components defined above all belong to "info. pigg. study. java", so add @ ComponentScan (value = "info. pigg. study. java")


@SpringBootApplication
@ComponentScan(value = "info.pigg.study.java")
public class DictApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DictApplication.class, args);
        String[] names = run.getBeanDefinitionNames();
  
  // Print out the name containing myBean Example of 
        for (String name : names) {
            if (name.contains("myBean")) {
                System.out.println(name);
            }
        }
    }
}

The test results are as follows:

myBeanService

myBeanPerson

myBeanUser

4. Use of excludeFilters in @ ComponentScan

You can set includeFilters and excludeFilters at @ ComponentScan to customize filters. 1 excludeFilters is used more.

1. Filter the specified class name

type = FilterType. ASSIGNABLE_TYPE is filtered according to the class class, followed by classes pointing to the class name


@SpringBootApplication
@ComponentScan(value = "info.pigg.study.java", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {MyService.class})})
public class DictApplication {
 // And above 1 Sample, omission 
}

The test results are as follows:

myBeanPerson

myBeanUser

2. Filter the specified comments

Under the "info. pigg. study. java" package and subpackages, exclude classes with @ Service annotations


@SpringBootApplication
@ComponentScan(value = "info.pigg.study.java", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class})})
public class DictApplication {
}

The test results are as follows:

myBeanPerson

myBea

3. Custom Filtering

type = FilterType. CUSTOM is a custom filter. The class specified by classes should implement TypeFilter interface, and the information of the currently scanned class, such as annotation, class name and class path, can be obtained in match method.


@SpringBootApplication
@ComponentScan(value = "info.pigg.study.java", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})})
public class DictApplication {
}

For example, the match method returns true when the class name contains "MyService", so that the class containing "MyService" is excluded when excludeFilters.


package info.pigg.study.java.filter;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
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;
import java.io.IOException;
public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        // Gets the information of the current class annotation 
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        
        // Get the current class resource ( The path of the class )
        Resource resource = metadataReader.getResource();
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println(" Class name of the class currently being scanned " + classMetadata.getClassName());
        if (classMetadata.getClassName().contains("MyService")){
            return true;
        }
        return false;
    }
}

The test results are as follows:

myBeanPerson

myBea


Related articles: