https://segmentfault.com/a/1190000020802458
深入理解 spring 注解之@ComponentScan 注解liu20111590 的专栏-CSDN 博客@componentscan 注解
1 @ComponentScan 注解是什么
其实很简单,@ComponentScan 主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到 spring 的 bean 容器中
2 @ComponentScan 注解的详细使用
做过 web 开发的同学一定都有用过@Controller,@Service,@Repository 注解,查看其源码你会发现,他们中有一个共同的注解@Component,没错@ComponentScan 注解默认就会装配标识了@Controller,@Service,@Repository,@Component 注解的类到 spring 容器中,好下面咱们就先来简单演示一下这个例子
2.1 准备数据
在包 com. Zhang. Controller 下新建一个 UserController 带@Controller 注解如下:
package com.zhang.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}在包 com. Zhang. Service 下新建一个 UserService 带@Service 注解如下:
package com.zhang.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
}在包 com. Zhang. Dao 下新建一个 UserDao 带@Repository 注解如下:
package com.zhang.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}新建一个配置类如下:
@ComponentScan(value="com.zhang")
@Configuration
public class MainScanConfig {
}新建测试方法如下:
AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainScanConfig.class);
String[] definitionNames = applicationContext2.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}运行结果如下:
mainScanConfig
userController
userDao
userService
怎么样,包扫描的方式比以前介绍的通过@Bean 注解的方式是不是方便很多,这也就是为什么 web 开发的同学经常使用此方式的原因了
2.2 对@ComponentScan 的详细解释
上面只是简单的介绍了@ComponentScan 注解检测包含指定注解的自动装配,接下来让我们来看看@ComponentScan 注解的更加详细的配置,在演示详细的配置之前,让我们先看看@ComponentScan 的源代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
/**
* 对应的包扫描路径 可以是单个路径,也可以是扫描的路径数组
* @return
*/
@AliasFor("basePackages")
String[] value() default {};
/**
* 和value一样是对应的包扫描路径 可以是单个路径,也可以是扫描的路径数组
* @return
*/
@AliasFor("value")
String[] basePackages() default {};
/**
* 指定具体的扫描的类
* @return
*/
Class<?>[] basePackageClasses() default {};
/**
* 对应的bean名称的生成器 默认的是BeanNameGenerator
* @return
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
* 处理检测到的bean的scope范围
*/
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
/**
* 是否为检测到的组件生成代理
* Indicates whether proxies should be generated for detected components, which may be
* necessary when using scopes in a proxy-style fashion.
* <p>The default is defer to the default behavior of the component scanner used to
* execute the actual scan.
* <p>Note that setting this attribute overrides any value set for {@link #scopeResolver}.
* @see ClassPathBeanDefinitionScanner#setScopedProxyMode(ScopedProxyMode)
*/
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
/**
* 控制符合组件检测条件的类文件 默认是包扫描下的 **/*.class
* @return
*/
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
/**
* 是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的
* @return
*/
boolean useDefaultFilters() default true;
/**
* 指定某些定义Filter满足条件的组件 FilterType有5种类型如:
* ANNOTATION, 注解类型 默认
ASSIGNABLE_TYPE,指定固定类
ASPECTJ, ASPECTJ类型
REGEX,正则表达式
CUSTOM,自定义类型
* @return
*/
Filter[] includeFilters() default {};
/**
* 排除某些过来器扫描到的类
* @return
*/
Filter[] excludeFilters() default {};
/**
* 扫描到的类是都开启懒加载 ,默认是不开启的
* @return
*/
boolean lazyInit() default false;
}2.3 案例
2.3.1 basePackageClasses
演示 basePackageClasses 参数,如我们把配置文件改成如下
@ComponentScan(value="com.zhang.dao",useDefaultFilters=true,basePackageClasses=UserService.class)
@Configuration
public class MainScanConfig {
}测试结果如下:
mainScanConfig
userDao
userService
只有 userDao 外加basePackageClasses指定的 userService 加入到了 spring 容器中
2.3.2 includeFilters
在 com. Zhang. Service 包下新建一个 UserService 2 类如下:注意没有带@Service 注解
package com.zhang.service;
public class UserService2 {
}配置类改成:
@ComponentScan(value="com.zhang",useDefaultFilters=true,
includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={UserService2.class})
})
@Configuration
public class MainScanConfig {
}运行结果如下:
mainScanConfig
userController
userDao
userService
userService2
UserService 2 同样被加入到了 spring 容器
新增一个自定义的实现了 TypeFilter 的 MyTypeFilter 类如下:
public class MyTypeFilter implements TypeFilter {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
ClassMetadata classMetadata = metadataReader.getClassMetadata();
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
// 检测名字包含Service的bean
if(className.contains("Service")){
return true;
}
return false;
}
}修改主配置如下:
@ComponentScan(value="com.zhang",useDefaultFilters=true,
includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
})
@Configuration
public class MainScanConfig {
}运行结果如下:
mainScanConfig
userController
userDao
userService
userService2
可以发现同样 userService 2 被加入到了 spring 容器中
3 XML 中配置 component-scan
情况一:最基本的扫描方式
<context:component-scan base-package="com.atguigu.spring6">
</context:component-scan>情况二:指定要排除的组件
<context:component-scan base-package="com.atguigu.spring6">
<!-- context:exclude-filter标签:指定排除规则 -->
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的全类名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>情况三:仅扫描指定组件
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
<!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
<!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的全类名
-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>4 总结
总结一下@ComponentScan 的常用方式如下
- 自定扫描路径下边带有@Controller,@Service,@Repository,@Component 注解加入 spring 容器
- 通过 includeFilters 加入扫描路径下没有以上注解的类加入 spring 容器
- 通过 excludeFilters 过滤出不用加入 spring 容器的类
- 自定义增加了@Component 注解的注解方式