1.@ComponentScan 是什么
主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中。注解定义如下
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
@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 "**/*.class";
/**
* 是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的
* @return
*/
boolean useDefaultFilters() default true;
/**
* 指定某些定义Filter满足条件的组件 FilterType有5种类型如:
* ANNOTATION, 注解类型 默认
ASSIGNABLE_TYPE,指定固定类
ASPECTJ, ASPECTJ类型
REGEX,正则表达式
CUSTOM,自定义类型
* @return
*/
ComponentScan.Filter[] includeFilters() default {};
/**
* 排除某些过滤器扫描到的类
* @return
*/
ComponentScan.Filter[] excludeFilters() default {};
/**
* 扫描到的类是都开启懒加载 ,默认是不开启的
* @return
*/
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 {};
}
}
basePackages与value: 用于指定包的路径,进行扫描
basePackageClasses: 用于指定某个类的包的路径进行扫描
nameGenerator: bean的名称的生成器
useDefaultFilters: 是否开启对@Component,@Repository,@Service,@Controller的类进行检测
includeFilters: 包含的过滤条件
FilterType.ANNOTATION:按照注解过滤
FilterType.ASSIGNABLE_TYPE:按照给定的类型
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:正则
FilterType.CUSTOM:自定义规则
excludeFilters: 排除的过滤条件,用法和includeFilters一样,使用excludeFilters时,useDefaultFilters 要为true。
2.@ComponentScan注解的详细使用
做过web开发的同学一定都有用过@Controller,@Service,@Repository注解,查看其源码你会发现,他们中有一个共同的注解@Component,没错@ComponentScan注解默认就会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中,好下面咱们就先来简单演示一下这个例子
分别创建带注解的service,dao,controller类,目录如下
Controller带@Controller
Service带@Service
Dao带@Repository
再建一个配置类MainConfig
//配置类 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2")
public class MainConfig {
//给aop容器注册一个bean,类型为返回值类型,默认bean id 是方法名,可以自定义
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
测试类
测试一:默认拦截规则
@Test
public void test01(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
//System.out.println(names);
for (String name : names) {
System.out.println(name);
}
}`
测试结果:
把所有带注解的bean都注册进去了
测试二:includeFilters 修改Mainconfig如下,使用注解拦截器。过滤类型是ANNOTATION(注解),只过滤controller,关闭默认的过滤器
//配置类 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
},useDefaultFilters = false)
public class MainConfig {
//给aop容器注册一个bean,类型为返回值类型,默认bean id 是方法名,可以自定义
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
运行测试类,测试结果:
除了自己本身和自定义的bean之外,系统只注入了controller
测试三:excludeFilters 修改Mainconfig如下,使用注解拦截器。过滤类型是ANNOTATION(注解),排除controller,开启默认的过滤器
//配置类 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
},useDefaultFilters = true)
public class MainConfig {
//给aop容器注册一个bean,类型为返回值类型,默认bean id 是方法名,可以自定义
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
测试结果:没有注册controller类
测试四:过滤方式为 ASSIGNABLE_TYPE,指定过滤类型,配置类如下
//配置类 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {OrderController.class})
},useDefaultFilters = false)
public class MainConfig {
//给aop容器注册一个bean,类型为返回值类型,默认bean id 是方法名,可以自定义
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
测试结果:只有指定的orderController类被注册进容器
测试五:自定义过滤方式
1.新建一个CustomTypeFilter类实现TypeFilter接口,并实现其 match 方法。
public class CustomTypeFilter implements TypeFilter {
/**
*
* @param metadataReader:读取到当前正在扫描类的信息
* @param metadataReaderFactory:可以获取到其任何类信息
* @return
* @throws IOException
*/
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);
if(className.contains("con")){ //当类包含con字符串,匹配成功,返回true
return true;
}
return false;
}
这里简单对扫描到的类名进行判断,如果类名包含”con“的就符合条件,也就会注入到容器中。
2.修改配置类:type = FilterType.CUSTOM, classes = {CustomTypeFilter.class}
//配置类 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {CustomTypeFilter.class})
},useDefaultFilters = false)
public class MainConfig {
//给aop容器注册一个bean,类型为返回值类型,默认bean id 是方法名,可以自定义
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
测试结果: