作用
@ComponentScan
用于批量注册bean,这个注解会让spring去扫描某些包及其子包中所有的类,然后将满足一定条件的类作为bean 注册到spring容器中。主要使用于多模块的项目中,在总入口中引入其入模块的Bean注入。
使用范围:可以使用于任意类型,一般作用在配置类上。
定义
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
//与basePackages属性互为别名,作用一样
@AliasFor("basePackages")
String[] value() default {};
// 扫描的基础包,与value只能二选一
@AliasFor("value")
String[] basePackages() default {};
// 扫描的类,会扫描该类所在包及其子包的组件
Class<?>[] basePackageClasses() default {};
// bean id 生成器,定义了一套生成的bean id的规则
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
// 定义扫描的规则
String resourcePattern() default "**/*.class";
// 是否使用默认的过滤器,默认为true
boolean useDefaultFilters() default true;
// 包含过滤器,用来配置被扫描出来的那些类会被作为组件注册到容器中
/*
*指定某些定义Filter满足条件的组件 FilterType有5种类型如:
* ANNOTATION, 注解类型 默认
ASSIGNABLE_TYPE,指定固定类
ASPECTJ, ASPECTJ类型
REGEX,正则表达式
CUSTOM,自定义类型
*/
Filter[] includeFilters() default {};
// 排除过滤器,用来对扫描的类进行排除的,被排除的类不会被注册到容器中
Filter[] excludeFilters() default {};
//是否延迟加载,默认为false,也就是默认bean是立即加载到容器中。
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 {};
}
}
参数
value
或basePackages
该属性配置的是spring要扫描的基础包,定义了之后,spring默认会扫描该包及其子包下的相应注解生成bean组件。
该属性是一个数组,也就是可以定义多个基础包。
当该属性不设置的时候,默认扫描该配置类所在的包及其子包下的组件。
package com.example.demo.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}
package com.example.demo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(value = "com.example.demo.dao")
@Configuration
public class UserConfig {
}
public class injectTest {
@Test
public void test(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
for(String beanName: context.getBeanDefinitionNames()){
System.out.println(String.format("Bean名称:%s,bean对象:%s", beanName, context.getBean(beanName)));
}
}
}
结果输出:
Bean名称:userConfig,bean对象:com.example.demo.config.UserConfig@2c35e847
Bean名称:userDao,bean对象:com.example.demo.dao.UserDao@7bd4937b
basePackageClasses
配置要扫描的类的class对象,默认会扫描该类所在的包及其子包下的组件。
修改上面的配置文件:
@ComponentScan(value = "com.example.demo.dao", useDefaultFilters = true, basePackageClasses = UserService.class)
@Configuration
public class UserConfig {
}
运行输出:
Bean名称:userConfig,bean对象:com.example.demo.config.UserConfig$$EnhancerBySpringCGLIB$$892447e9@2767e23c
Bean名称:userDao,bean对象:com.example.demo.dao.UserDao@710c2b53
Bean名称:userService,bean对象:com.example.demo.service.UserService@5386659f
这里不但扫描并注入了com.example.demo.dao
包下面的userDao
,同时userService
这个bean也被注入到spring容器中。
nameGenerator
配置bean Id的生成规则,默认是如果组件注解@Component、@Controller、@Service、@Repository、@Named、ManagedBean注解都没有显示配置组件id时,就会把类名第一位转化为小写作为该组件的id。如果不同包中有相同名字的类,在扫描时就会报错。
我们可以通过配置nameGenerator属性自定义我们的组件id生成器。
resourcePattern
该属性设置在基础包的前提下,扫描的路径**
表示任意层级,所以默认是从基础包开始任意层级的class文件。
如果修改成*/*.class
就不会扫描子包,只会扫描当前包的class文件。**/Serivce.class
只会扫描当前包下的Serivce.class结尾的文件。
lazyInit
设置是否把扫描到的组件延迟实例化,默认为false,表示立即实例化。如果设置为true,容器会在第一次getBean时实例化该组件。
useDefaultFilters
useDefaultFilters
属性表示是否启用默认的过滤器,默认过滤器是指被@Component
注解 标注的注解,比如Controller
、Service
、Repository
、Component
。也有其他的@Named
等。默认是true,开启。也就是我们可以自定义组件注解,只要用@Component
注解在自定义注解上面,spring默认会扫描到。
includeFilters
该属性配置扫描包含过滤器,只包含、不排除,也就是说,例如useDefaultFilters
默认为true
,默认会对@Compoent
等注解进行扫描。然后使用includeFilters
属性对自定义@MyComponent注解进行包含,那么,spring仍然会对@Compoent
等注解进行扫描,对@MyComponent注解的包含不会导致原有的注解的排除。includeFilters
只包含新的扫描规则,不会排除已有的扫描规则
新建一个UserService2
的类,该类不标注任何注解
public class UserService2 {
}
package com.example.demo.config;
@ComponentScan(value = "com.example.demo", useDefaultFilters = true,includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserService2.class})
})
@Configuration
public class UserConfig {
}
public class injectTest {
@Test
public void test(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
for(String beanName: context.getBeanDefinitionNames()){
System.out.println(String.format("Bean名称:%s,bean对象:%s", beanName, context.getBean(beanName)));
}
}
}
运行输出:
Bean名称:userController,bean对象:com.example.demo.controller.UserController@615f972
Bean名称:userDao,bean对象:com.example.demo.dao.UserDao@285f09de
Bean名称:userService,bean对象:com.example.demo.service.UserService@73393584
Bean名称:userService2,bean对象:com.example.demo.service.UserService2@31500940
从结果可以看出,没有添加任何注解的UserService2
也被注入到了Spring容器中。
excludeFilters
此注解要配置不扫描的规则,比如排除了@Component
注解后,用该注解的类不会被spring实例化为组件。
注意:excludeFilters
的优先级比includeFilters
高,例如,两个属性分别配置了同样的规则,excludeFilters
属性的配置会生效,spring会对该规则进行排除。
总结
1、自定扫描路径下边带有@Controller
、@Service
、@Repository
、@Component
注解的类加入到Spring容器中。
2、通过includeFilters
加入扫描路径下没有以上注解的类加入Spring容器。
3、通过excludeFilters
过滤出不用加入Spring容器的类。
4、自定义增加了@Component
注解的注解方式。
原创文章,作者:jiafegn,如若转载,请注明出处:https://www.techlearn.cn/archives/274