Spring学习笔记(二)---注解@ComponentScan

1.源码解析

@ComponentScan从翻译上我们可以知道它是一个组件扫描器,在这个扫描器里我们可以指定扫描的范围,指定系统为我们设置的相应过滤器,甚至是可以使用我们自定义的过滤器。
[1] 这里我们先从源码中几个主要的方法讲起

public @interface ComponentScan {
	//这个value值就是指定我们扫描包的路径
	//@AliasFor这里指的是使用时可以使用的另一个别名
	@AliasFor("basePackages")
	String[] value() default {};
	//指定包含类型的过滤器,在这里面可以指定Filter来设定我们过滤时通过什么辨别(最常用的是注解和类)
	Filter[] includeFilters() default {};
	//指定需要排除类型的过滤器
	Filter[] excludeFilters() default {};
	@Target({})
	@interface Filter {
		//Filter的类型(默认是注解)
		FilterType type() default FilterType.ANNOTATION;
		@AliasFor("classes")
		Class<?>[] value() default {};		
		@AliasFor("value")
		Class<?>[] classes() default {};
		String[] pattern() default {};

[2] FilterType 这个类中表明我们能填写的值


package org.springframework.context.annotation;

public enum FilterType {

	/**
	 * Filter candidates marked with a given annotation.
	 * @see org.springframework.core.type.filter.AnnotationTypeFilter
	 * 指定的注解(使用较多)
	 */
	ANNOTATION,
	/**
	 * Filter candidates assignable to a given type.
	 * @see org.springframework.core.type.filter.AssignableTypeFilter
	 * 指定的类型,即我们指定扫描哪个类(使用较多)
	 */
	ASSIGNABLE_TYPE,

	/**
	 * Filter candidates matching a given AspectJ type pattern expression.
	 * @see org.springframework.core.type.filter.AspectJTypeFilter
	 */
	ASPECTJ,

	/**
	 * Filter candidates matching a given regex pattern.
	 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
	 * 正则表达式
	 */
	REGEX,

	/** Filter candidates using a given custom
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 * 自定义类型(使用较多)
	 */
	CUSTOM

}

[3] 一脸懵逼,你在说什么呢?我们还是用一个includeFilters实例说明吧

@Configuration
//@Controller  @Service @Respostry @Component
@ComponentScan(value="com.enjoy.cap2", 
	includeFilters= {@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})}
	,useDefaultFilters=false)
public class Cap2MainConfig {

解析: 这个注解使用在类上,其中value指明需要扫描的包(com.enjoy.cap2这是我自己新建的包,这个包中有@Controller @Service @Respostry @Component这几个注解标明的类);接下来includeFilters指明相应的规则,比如通过FilterType.ANNOTATION(即我们的注解进行相应的扫描包含),后面的classes用来表示注解相应的类(Controller类),这样我们最终扫描的到的组件就只有标了@Controller的类了,其余的类就被过滤掉了。
useDefaultFilters=false这又是个什么东西呀,我们带着它再次走进源码

/**
  * Indicates whether automatic detection of classes annotated with {@code @Component}
 * {@code @Repository}, {@code @Service}, or {@code @Controller} should be enabled.
 * 指示是否自动检测用{@code@Component}注释的类应该启用{@code@Repository}、{@code@Service}或{@code@Controller}。
**/
boolean useDefaultFilters() default true;

默认它是打开的,也就是我们设不设定相应的过滤规则,它也会到包下去扫描这几个注解的类。这也就是我们把它设为false的原因了,因为我们现在只需它扫描@Controller相应的类就可以了。(如果这个值为true,我们设定的过滤规则就会失效)

接下来我们用excludeFilters来说明它与上面的区别

@Configuration
//@Controller  @Service @Respostry @Component
@ComponentScan(value="com.enjoy.cap2", 
	excludeFilters= {@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})}
	,useDefaultFilters=false)
public class Cap2MainConfig {

有人就会觉得理所当然了,不就是把includeFilters改为excludeFilters就能实现相应的排除功能吗,这又什么好说的。对,你说的没错,不过需要注意的是useDefaultFilters=false这就是不可以的了,因为我们关闭了它的扫描,那我们怎么排除都一样没有效果,因为我们根本就没有对相应的注解进行相应的扫描,这时我们需要开启扫描,即把上面的改为useDefaultFilters=true就能正常使用了。
[4] 从上面我们已经了解了includeFilter和excludeFilter的相关属性,接下来我们我们将深入了解一下这两个属性中的@Fiter可以使用的相关值。

2. 使用@Filter来自定义过滤类

上面我们已经了解到FilterType类型中有ANNOTATION(默认),ASSIGNABLE_TYPE(指定我们需要扫描的类,如xxxController.class);除了这两个之外我们最常使用的就是 CUSTOM(自定义类型),可以通过这个类型来设定我们自己的过滤规则
FilterType 这个类中最常用的三个值


package org.springframework.context.annotation;

public enum FilterType {
	ANNOTATION,
	ASSIGNABLE_TYPE,
	CUSTOM
}

[1] 编写一个自定义的过滤类(这里可以编写我们自己的过滤规则)
MyTypeFilter这个类需要继承TypeFilter

package com.enjoy.cap2.config;

import java.io.IOException;

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;

public class JamesTypeFilter implements TypeFilter {

	/**
	 * MetadataReader: 读取当前正在扫描类的信息
	 * MetadataReaderFactory: 可以获取到其他类的信息
	 */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		/**这里只是说明它拥有方法**/
		//获取当前类注解的信息
		//AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前的资源(类的路径)
		//Resource resource = metadataReader.getResource();
		
		//获取正在扫描的类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();

		String className = classMetadata.getClassName();
		System.out.println("----->"+className);
		/**
		  获取我们扫描的包中的类名,如果我们只需要得到相应的订单类Order,这时候我们就
		  可以设置它的匹配规则如下
		**/
		if(className.contains("Order")) { 
			//当类包含Order字符,则匹配成功,返回true
			return true;
		}
		return false;
	}

}

[2] 在主配置类中引入我们的自定义过滤规则
这里的FilterType要使用FilterType.CUSTOM,也就是我们的自定义类型。classes就是我们的类名。这样引入之后我们就能按照自己定义的规则进行相应的过滤(比如这里我们的匹配规则时只有Order相关的类才会的到相应的扫描)

@Configuration
//@Controller  @Service @Respostry @Component
@ComponentScan(value="com.enjoy.cap2",includeFilters= {
		@Filter(type= FilterType.CUSTOM,classes= {MyTypeFilter.class})
	}
	,useDefaultFilters=false)
public class Cap2MainConfig {

小结

@ComponentScan(value=“com.enjoy.cap2”,includeFilters= {
@Filter(type= FilterType.CUSTOM,classes= {MyTypeFilter.class})
}
,useDefaultFilters=false)

这基本涵盖了上面所讲的,我们只要知道@ComponentScan是通过value指定的相应的包路径进行扫描的,并通过
includeFilters或excludeFilters来表命满足条件是包含呢还是排除呢,而条件上则是通过@Filte上的FilterType来指定注解,类,自定义类等。

发布了70 篇原创文章 · 获赞 2 · 访问量 5485

猜你喜欢

转载自blog.csdn.net/TheWindOfSon/article/details/105055389