Spring组件注册注解之@ComponentScan,@ComponentScans

目录

1. 说明

2. @ComponentScan注解属性

3. @ComponentScan过滤规则说明

4. 自定义扫描过滤规则

5. @ComponentScan原理分析

6. @ComponentScans


1. 说明

与ComponentScan注解相对应的XML配置就是<context:component-scan/>, 根据指定的配置自动扫描package,将符合条件的组件加入到IOC容器中;

XML的配置方式如下:

	<context:component-scan
		base-package="com.yibai.spring.annotation" use-default-filters="false">
		<context:include-filter type="custom"
			expression="com.yibai.spring.annotation.filter.ColorBeanLoadFilter" />
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Component" />
	</context:component-scan>

2. @ComponentScan注解属性

@ComponentScan有如下属性:

value:指定要扫描的package;
includeFilters=Filter[]:指定只包含的组件
excludeFilters=Filter[]:指定需要排除的组件;
useDefaultFilters=true/false:指定是否需要使用Spring默认的扫描规则:被@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件;

在过滤规则Filter中:
FilterType:指定过滤规则,支持的过滤规则有
    ANNOTATION:按照注解规则,过滤被指定注解标记的类;
    ASSIGNABLE_TYPE:按照给定的类型;
    ASPECTJ:按照ASPECTJ表达式;
    REGEX:按照正则表达式
    CUSTOM:自定义规则;
value:指定在该规则下过滤的表达式;

3. @ComponentScan过滤规则说明

规则表达式说明

1. 扫描指定类文件
   @ComponentScan(basePackageClasses = Person.class)
2. 扫描指定包,使用默认扫描规则,即被@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件;
   @ComponentScan(value = "com.yibai")
3. 扫描指定包,加载被@Component注解标记的组件和默认规则的扫描(因为useDefaultFilters默认为true)
   @ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
4. 扫描指定包,只加载Person类型的组件
   @ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.ASSIGNABLE_TYPE, value = Person.class) }, useDefaultFilters = false)
5. 扫描指定包,过滤掉被@Component标记的组件
   @ComponentScan(value = "com.yibai", excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
6. 扫描指定包,自定义过滤规则
   @ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.CUSTOM, value = ColorBeanLoadFilter.class) }, useDefaultFilters = true)

4. 自定义扫描过滤规则

自定义规则实现类ColorBeanLoadFilter 

/**
 * Project Name:yibai-spring-annotation
 * File Name:ColorBeanLoadFIlter.java
 * Package Name:com.yibai.spring.annotation.filter
 * Date:2019年1月5日下午12:15:54
 * Copyright (c) 2019, www.windo-soft.com All Rights Reserved.
 *
*/

package com.yibai.spring.annotation.filter;

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;

import com.yibai.spring.annotation.bean.color.Color;

public class ColorBeanLoadFilter implements TypeFilter {

	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		// 当前被扫描类的注解信息
		@SuppressWarnings("unused")
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		// 当前被扫描类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		// 当前被扫描类资源信息
		@SuppressWarnings("unused")
		Resource resource = metadataReader.getResource();
		try {
			String className = classMetadata.getClassName();
			Class<?> forName = Class.forName(className);
			if (Color.class.isAssignableFrom(forName)) {
				// 如果是Color的子类,就加载到IOC容器
				return true;
			}
		} catch (ClassNotFoundException e) {
//			e.printStackTrace();
		}
		return false;
	}

}

5. @ComponentScan原理分析

@ComponentScan的解析器是org.springframework.context.annotation.ComponentScanAnnotationParser;

useDefaultFilters = true指定的规则过滤器是 org.springframework.core.type.filter.AnnotationTypeFilter;’

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {

        /** componentScan为@ComponentScan的注解信息:
            {value=[com.yibai.spring.annotation], basePackages=[com.yibai.spring.annotation], lazyInit=false, scopeResolver=class org.springframework.context.annotation.AnnotationScopeMetadataResolver, scopedProxy=DEFAULT, nameGenerator=interface org.springframework.beans.factory.support.BeanNameGenerator, useDefaultFilters=true, basePackageClasses=[], includeFilters=[], resourcePattern=**/*.class, excludeFilters=[]}
*/

		Assert.state(this.environment != null, "Environment must not be null");
		Assert.state(this.resourceLoader != null, "ResourceLoader must not be null");

		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
				componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

		//....
        //..
        //.
        //中间代码省略了,大概做的事情就是创建包扫描器,然后被@CompontentScan注解设置的属性都设置搭配扫描器中,然后准备扫描
        
        // 经过一些列的scanner的属性设置,进入扫描流程
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}

然后进入org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(String...) 进行扫描,并生成组件定义信息;

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
	for (String basePackage : basePackages) {
           
        // 根据扫描规则扫描出符合条件的组件
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

        //下面就是将扫描出的组件实加载到IOC容器中;
		for (BeanDefinition candidate : candidates) {
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

通过org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(String)找出符合条件的组件

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
       Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
	try {
        //classpath*:com/yibai/spring/annotation/**/*.class
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        //resources 就是指定包下的所有类
		Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
        //遍历所有类,判断是否符合规则
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                    //注意这里,根据过滤规则进行判断
					if (isCandidateComponent(metadataReader)) {
                        //如果符合条件,这将组件让如待返回的集合中去;
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);
						}
						else {
							if (debugEnabled) {
								logger.debug("Ignored because not a concrete top-level class: " + resource);
							}
						}
					}
					else {
						if (traceEnabled) {
							logger.trace("Ignored because not matching any filter: " + resource);
						}
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
			else {
				if (traceEnabled) {
					logger.trace("Ignored because not readable: " + resource);
				}
			}
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

通过org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.isCandidateComponent(MetadataReader)方法,根据过滤器规则判断类是否满足条件

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    //是否满足排除的条件
	for (TypeFilter tf : this.excludeFilters) {
		if (tf.match(metadataReader, this.metadataReaderFactory)) {
			return false;
		}
	}
    // 是否满足包含的条件
	for (TypeFilter tf : this.includeFilters) {
        //判断是否过滤器满足
		if (tf.match(metadataReader, this.metadataReaderFactory)) {
            // 判断是否条件满足
			return isConditionMatch(metadataReader);
		}
	}
	return false;
}

当断点到自定义过滤类里面的时候,调用栈如下

6. @ComponentScans

可以一次声明多个@ComponentScan

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)  //指定ComponentScan可以被ComponentScans作为数组使用
public @interface ComponentScan {
}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
    
	ComponentScan[] value();

}
@ComponentScans(value = { @ComponentScan(value = "com.yibai.spring.annotation"),
		@ComponentScan(value = "com.yibai.spring.annotation", includeFilters = {
				@Filter(type = FilterType.CUSTOM, value = ColorBeanLoadFilter.class) }) })
public class MainConfig {

	@Bean(name = "pers", initMethod = "init", destroyMethod = "destory")
	public Person person() {
		return new Person();
	}

}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值