springBean注册之@ComponentScan注解解析

相关文章 SpringIOC源码:@Configuration配置类解析过程

@ComponentScan的使用

@ComponentScan只会扫描有以下四种注解中某一注解的类,并管理他们把他们加载到上下文中
@Component:基本注解,标识了一个受Spring管理的组件,实际上只会扫描@Component,只是其他3个都继承于他
@Repository:标识持久层组件
@Service:标识服务层(业务层)组件
@Controller:标识表现层组件

他们可以混用,因为Spring还没有聪明到能判断我们写的代码是那一层的,但最好那一层的注解,就用那一层,因为未来有可能有别的寓意
对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写(如UserService其默认id就是:userService)。也可以在注解中通过value属性值标识组件的名称

@ComponentScan的属性

//定义包路径
String[] value() default {}
String[] basePackages() default {}
//指定dean生成器,默认BeanNameGenerator
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
//处理与检测到的bean的scope范围,默认AnnotationScopeMetadataResolver
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class
//是否为检测到的组件生成代理
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
//控制符合组件检测条件的类文件   默认是包扫描下的  **/*.class
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
//是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的
boolean useDefaultFilters() default true;
//扫描到的类是都开启懒加载 ,默认是不开启的
boolean lazyInit() default false
//包扫描过滤与包括设置
Filter[] includeFilters() default {}
Filter[] excludeFilters() default {}

Filter信息说明

FilterType.ANNOTATION//注解类型 默认
FilterType.ASSIGNABLE_TYPE//指定固定类
FilterType.ASPECTJ//ASPECTJ类型
FilterType.REGEX//正则表达式
FilterType.CUSTOM//自定义类型

说明excludeFilters是过滤规则,是在基础规则上的进一步排除,includeFilters是包括,他和基础规则设置冲突,
基础规则会覆盖他,所以当我要使用includeFilters时应该使用useDefaultFilters=false禁用基础规则或者不定义

案例

@ComponentScan(
  value ={"hello”},
  useDefaultFilters = false,
  includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}
  )

源码解析

@ComponentScan注解注解解析发生在配置类解析1阶段,其解析类是ComponentScanAnnotationParser

class ConfigurationClassParser {

   //调用ConfigurationClassParser构造器时会实例化ComponentScanAnnotationParser对象
   private final ComponentScanAnnotationParser componentScanParser;

   private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();

   protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
        
        //处理内部类
        
		//处理@PropertySource注解
		
		//处理@ComponentScan注解
		//读取@ComponentScan注解信息,组装成AnnotationAttributes信息放到集合中
		//至于为什么是集合,因为@ComponentScans可以一次声明多个@ComponentScan
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		//如果读取到了
		if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		     //循环处理
			for (AnnotationAttributes componentScan : componentScans) {
				//利用@ComponentScan解析器ComponentScanAnnotationParser,获取扫描到的类,并注册到Spring中
				//具体详情看下面
				Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			   //检查扫描的定义集以获取任何进一步的配置类,并在需要时递归解析
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					   //递归调用processConfigurationClass方法
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		// 处理任何@Import注释

		// 处理任何@ImportResource注释
		
		// 处理单个@Bean方法
		
		// 处理接口上的默认方法
	
	}

1、读取@ComponentScan注解信息,组装成AnnotationAttributes信息放到集合中
2、循环处理AnnotationAttributes对象,利用ComponentScanAnnotationParser解析器解析他,获取扫描到的类,并注册到Spring中
3、检查扫描的定义集,循环他们,再次进行一阶段解析,防止其中还有配置类

下面再来具体了解下ComponentScanAnnotationParser是怎么解析@ComponentScan注解信息组装成的AnnotationAttributes

class ComponentScanAnnotationParser {

    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

		 //忽略代码,这里都是提取@ComponentScan注解的具体信息,然后利用ClassPathBeanDefinitionScanner装载他们
        
        //利用注册器ClassPathBeanDefinitionScanner注册扫描到的类
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}

ClassPathBeanDefinitionScanner作用就是将指定包下的类通过一定规则过滤后 将Class 信息包装成 BeanDefinition 的形式注册到IOC容器中。

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

    private final BeanDefinitionRegistry registry;

	private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();

	@Nullable
	private String[] autowireCandidatePatterns;

	/**
	 * 用于为bean定义生成bean名称的策略接口
	 */
	private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

	/**
	 * 解决bean定义范围的策略接口
	 */
	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

	private boolean includeAnnotationConfig = true;

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
			Assert.notEmpty(basePackages, "At least one base package must be specified");
			Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
			
			for (String basePackage : basePackages) {
				Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
				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);
						//注册当前BeanDefinition
						registerBeanDefinition(definitionHolder, this.registry);
					}
				}
			}
			return beanDefinitions;
		}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值