@ComponentScan Attribute basePackages and ValuebasePackageClassesincludeFiltersexcludeFilters add custom filtering rules @ Component @ ComponentScanscontext: Component – scanSpringBootApp 4 methods in LICATION annotation summary references
@ComponentScan
The use of the @ComponentScan annotation is described briefly in the @Configuration start container +@Component registration Bean section.
@ComponentScan automatically scans and loads qualified component or bean definitions, and eventually loads those bean definitions into the container. You can specify the scope that @ComponentScan automatically scans with backPackages and other attributes. If you do not specify this, the default Spring framework implementation scans from the package that declares @ComponentScan. By default, this is not specified. So SpringBoot’s boot class is best placed under the root Package.
First look at @ComponentScan source code:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<? >[] basePackageClasses()default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy(a) default ScopedProxyMode.DEFAULT;
String resourcePattern(a) default"* */*.class";
boolean useDefaultFilters() default true;
ComponentScan.Filter[] includeFilters() default {};
ComponentScan.Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<? >[] value() default {};
@AliasFor("value")
Class<? >[] classes() default {};
String[] pattern() default {};
}
}
Copy the code
The key attributes are as follows:
- BasePackages and Value: used to specify the packet path for scanning.
- BasePackageClasses: specifies the path of a class’s package to scan;
- NameGenerator: the generator of the bean’s name;
- UseDefaultFilters: Specifies whether to enable class detection for @Component, @repository, @service, and @controller. Default is true.
- IncludeFilters: include filter criteria FilterType.ANNOTATION: Filter by ANNOTATION; Filtertype. ASSIGNABLE_TYPE: according to the given type; Filtertype. ASPECTJ: Uses ASPECTJ expressions; Filtertype. REGEX: REGEX; Filtertype. CUSTOM: user-defined rule.
- ExcludeFilters: Filter criteria for exclusion. Use the same as includeFilters.
attribute
BasePackages and value
@ComponentScan(basePackages = “”) / / a single
@ComponentScanBasePackages = {" com.example.dao ", "aaa", "..." })/ / multiple
/ / the value in the same way
Copy the code
Note: “basePackages =” can be omitted.
@Configuration
@ComponentScan("com.example.dao")
public class MyConfig {}
@Configuration
@ComponentScan("com.example.dao"."com.example.service")
public class MyConfig {}
@Configuration
@ComponentScan("com.example.*") // Wildcard matches all packets
public class MyConfig {}
Copy the code
basePackageClasses
@ComponentScan(basePackageClasses = “”) / / a single
@ComponentScanBasePackageClasses = {" helloController.class ", "BBB", "..." })/ / multiple
Copy the code
Note: do not omit “basePackageClasses =”
@Configuration
@ComponentScan(basePackageClasses = HelloController.class)
public class MyConfig {
}
Copy the code
includeFilters
Let’s test with the following code.
Repository annotation class:
package com.example.dao;
@Repository
public class BusinessDAO {
public void update(a){
System.out.println("Dao layer update method called....");
}
}
Copy the code
Service annotation class:
package com.example.service;
@Service
public class BusinessService {
@Autowired
private BusinessDAO businessDAO;
public void service(a){
System.out.println("The service() method of the service layer is called.....");
businessDAO.update();
}
}
Copy the code
Controller annotation class:
package com.example.controller;
@Controller
public class BusinessController {
@Autowired
private BusinessService service;
public void request(a) {
System.out.println("Called the Controller's request() method...");
service.service();
}
}
Copy the code
Configuration Configuration class:
package com.example.configuration;
@Configuration
//@ComponentScan(basePackages = {"com.example.dao","com.example.service","com.example.controller"})
@ComponentScan(value = {"com.example.dao"."com.example.service"."com.example.controller"},
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Repository.class)},
useDefaultFilters = false)
public class ScanConfig {
}
Copy the code
Test class code:
public class ScanConfigTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScanConfig.class);
String[] definitionNames = context.getBeanDefinitionNames();
for(String name:definitionNames){
System.out.println(name);
}
}
}
Copy the code
The execution result is as follows:
19:22:48.157 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'scanConfig'
19:22:48.162 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'businessDAO'
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
scanConfig
businessDAO
Copy the code
In addition to some beans registered by Spring itself, you can see on the last line that the ScanConfig class and BusinessDAO have been registered in the container.
The includeFilters take a Filter[] array and specify that the FilterType is ANNOTATION (Filter by ANNOTATION) and the final value is the Repository ANNOTATION class. When configured, spring scans will filter all classes annotated by the @repository annotation from the three com.example packages.
Note: useDefaultFilters need to be set to false, otherwise the @ComponentScan annotation will register the classes annotated by @Component, @Repository, @Service, and @Controller into the container. And because we’re associating other classes (@autowired) in the Controller and Service annotated classes, So it’s best not to set controller.class or service.class in the Filter property of the includeFilters.
excludeFilters
Modify the configuration class:
@Configuration
//@ComponentScan(basePackages = {"com.example.dao","com.example.service","com.example.controller"})
@ComponentScan(value = {"com.example.dao"."com.example.service"."com.example.controller"},
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)})
public class ScanConfig {
}
Copy the code
Like the excludeFilters property, when configured, spring will skip all classes marked by the @Controller annotation in the three packages under com.Example when scanned.
The execution result is as follows:
19:44:39.191 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'scanConfig'
19:44:39.195 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'businessDAO'
19:44:39.195 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'businessService'
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
scanConfig
businessDAO
businessService
Copy the code
Add a user-defined filtering rule
We used the @filter annotation earlier, where the type attribute is an enumerated type of FilterType:
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM
}
Copy the code
Using the CUSTOM type, you can implement CUSTOM filtering rules.
package com.example.filter;
public class CustomTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// Get the annotation metadata of the currently scanned class
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// Get the metadata of the currently scanned class
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// Get the resource information of the currently scanned class
Resource resource = metadataReader.getResource();
if (classMetadata.getClassName().contains("Business")) {
return true;
}
return false;
}
}
Copy the code
Add a Service annotated class:
package com.example.service;
@Service
public class UserService {
}
Copy the code
Modify the configuration class:
@Configuration
@ComponentScan(value = {"com.example.dao"."com.example.service"."com.example.controller"},
excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,classes = CustomTypeFilter.class)})
public class ScanConfig {
}
Copy the code
Execute the test class code with the result:
19:56:25.419 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'scanConfig'
19:56:25.424 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userService'
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
scanConfig
userService
Copy the code
Here we simply judge the scanned class name. If the class name contains “Business”, it will be removed and will not be injected into the container.
@Component
1. Do not specify the name of the bean. Default is the first letter of the class name, lowercase university
@Component
public class BeanWithComponent {
public void sayHello(a){
System.out.println("BeanWithComponent sayHello...");
}
public void start(a){
System.out.println("BeanWithComponent initializes...");
}
public void cleanUp(a){
System.out.println("BeanWithComponent destroys...");
}
}
Copy the code
Method of obtaining bean:
@Autowired
BeanWithComponent beanWithComponent;
Copy the code
or
ApplicationContext context = new AnnotationConfigApplicationContext(ComfigureWithScan.class);
BeanWithComponent bean = (BeanWithComponent) context.getBean("beanWithComponent");
Copy the code
2. Specify the bean name
@Component("bean2")
public class BeanWithComponent {
}
Copy the code
Method of obtaining bean:
@Autowired
BeanWithComponent bean2;
Copy the code
or
ApplicationContext context = new AnnotationConfigApplicationContext(ComfigureWithScan.class);
BeanWithComponent bean = (BeanWithComponent) context.getBean("bean2");
Copy the code
conclusion
@ComponentScan Annotations have the following features:
-
Add the @Controller, @Service, @Repository, and @Component annotations to the spring container below the custom scan path
-
Add classes that do not have the above annotations in the scan path to the Spring container through includeFilters
-
Filter out classes that do not need to be added to the Spring container through excludeFilters
-
Custom added annotation method for @Component annotation
Here are two extensions to the @ComponentScan annotation.
@ComponentScans
The source code is as follows:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
Copy the code
The configuration class:
@Configuration
@ComponentScans(value = @ComponentScan("com.example.dao"))
public class ScanConfig {
}
Copy the code
The execution result is as follows:
20:07:45.908 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'scanConfig'
20:07:45.914 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'businessDAO'
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
scanConfig
businessDAO
Copy the code
context:component-scan
The above code is loaded by @Configuration + @ComponentScan annotation. Of course, you can also add the scanned Configuration in the Configuration file.
spring-context.xml
<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-3.0.xsd">
<! --<context:component-scan base-package="com.example.dao" annotation-config="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>-->
<context:component-scan base-package="com.example.dao" />
<context:component-scan base-package="com.example.controller" />
<context:component-scan base-package="com.example.service" />
</beans>
Copy the code
Modify the test class code:
public class ScanConfigTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
String[] definitionNames = context.getBeanDefinitionNames();
for(String name:definitionNames){
System.out.println(name);
}
}
}
Copy the code
The following results are obtained:
14:59:12.773 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'businessDAO'
14:59:12.778 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'businessController'
14:59:12.789 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'businessService'
14:59:12.789 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userService'
businessDAO
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
businessController
businessService
userService
Copy the code
For details about the use of attributes, please refer to: detailed explanation
Note: Contains an annotation-config property, This property is primarily registered implicitly with the Spring container InternalConfigurationAnnotationProcessor, internalAutowiredAnnotationProcessor, internalCommonAnnotationProcessor, internal EventListenerProcessor and internalEventListenerFactory these five bean class.
When the annotation-config property is set to false, these five classes are not registered. But the @ComponentScan annotation does not have this property. This is because in almost all cases, using @ComponentScan assumes the default annotation configuration handling (for example, handling @AutoWired and Friends). In addition, the use of AnnotationConfigApplicationContext annotation configuration processor will always be registered, this means that in any attempt to disable them @ ComponentScan level will be ignored.
Four methods in the SpringBootApplication annotation
@SpringBootApplication contains not only the three important annotations above, but also four methods:
Class[] exclude() default {};
To exclude a particular Class from the Spring container, pass in the Class parameter.String[] excludeName() default {};
To exclude a specific Class from the Spring container by Class Name, pass in an array of Class names.String[] scanBasePackages() default {};
Specifies a string array of package names to scan.Class[] scanBasePackageClasses() default {};
Specifies the scan package as an array of type Class.
summary
Here’s a summary of the characteristics of three important annotations in @SpringBootApplication:
@Configuration
Define the configuration classes for the Spring Ioc container.
@EnableAutoConfiguration
From the classpath to search all META/spring. Factories configuration files, and will be one of org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration corresponding configuration items, That is, a list of auto-configuration classes loaded into the Ioc container. Simple says, is that @ EnawebleAutoConfiguration let Spring Boot according to the classpath jar packages depend on automatic configuration for the current project, for example, to add the Spring – the Boot – starter – web dependence, Tomcat and Spring MVC dependencies are automatically added. ConfigurationClassParser is used for all @Configuration classes.
@ComponentScan
Automatically scans and loads qualified component or bean definitions.
reference
Spring4.0 bis: use of @configuration
SpringBootApplication annotations for the SpringBoot series