一起学SF框架系列5.8-spring-Beans-Bean注解解析3-解析配置component-scan

本文主要讲述Spring是如何解析“context:component-scan”元素,扫描加载目录下的BeanDefinition。

解析内容

1、解析的元素如下:

	
	<context:component-scan base-package="com.learnsf.main,com.learnsf.service"/>

注:该元素解析过程中,会自动处理“context:annotation-config/”元素要解析的内容。
2、只扫描加载目录下的BeanDefinition,不对注解进行解析。在AbstractApplicationContext.invokeBeanFactoryPostProcessors统一解析。

解析

ComponentScanBeanDefinitionParser.parse(Element element, ParserContext parserContext)

解析元素“context:component-scan”。

	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		// 获取属性“base-package”(多个包路径)
		String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
		// 对包路径中占位符进行替换处理
		basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
		// 分解成包数组
		String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

		// 生成BeanDefinition扫描器
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
		// 扫描生成beanDefinition
		Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
		// 注册BeanDefinition
		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

		return null;
	}

ClassPathBeanDefinitionScanner.doScan(String… basePackages)

在包里扫描BeanDefinition。

	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) {
			// 获取候选BeanDefinition
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			// 每个侯选者处理
			for (BeanDefinition candidate : candidates) {
				// 解析Bean作用域
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				// 生成beanName 
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition abstractBeanDefinition) {
					// 对 AbstractBeanDefinition类型的BeanDefinition 进一步处理:赋值BeanDefinition属性默认值,并设置 autowireCandidate 属性
					postProcessBeanDefinition(abstractBeanDefinition, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
					// 对 AnnotatedBeanDefinition 类型的 BeanDefinition 进一步处理:对通用注解的解析处理,通用注解包括 @Lazy、@Primary、@DependsOn、@Role、@Description。例如:如果当前类被@Lazy修饰,则会获取@Lazy 的value 值并保存到 BeanDefinition#lazyInit 属性中。
                    AnnotationConfigUtils.processCommonDefinitionAnnotations(annotatedBeanDefinition);
				}
				// 检查给定候选bean的beanName,确定相应的bean定义是否需要注册或与现有定义冲突
				if (checkCandidate(beanName, candidate)) {
					// 封装候选BeanDefinition为BeanDefinitionHolder 
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					// 对 BeanDefinitionHolder 填充代理信息
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					// 加入到返回集合
					beanDefinitions.add(definitionHolder);
					// 注册BeanDefinitionHolder 到bean工厂容器中
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

ClassPathScanningCandidateComponentProvider.findCandidateComponents(String basePackage)

ClassPathScanningCandidateComponentProvider是ClassPathBeanDefinitionScanner父类。
获取注解的Bean的BeanDefinition。

	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
			// @Indexed 注解的处理 注1
			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
		}
		else {
			// 非@Indexed 注解的处理
			return scanCandidateComponents(basePackage);
		}
	}

注1:@Indexed注解Spring在5.0版本引入的,主要解决启动时注解模式解析太长的问题。处理方式是在项目编译打包时,会自动生成META-INF/spring.components文件,文件包含被@Indexed注释的类的模式解析结果。当Spring应用上下文进行组件扫描时,META-INF/spring.components会被org.springframework.context.index.CandidateComponentsIndexLoader读取并加载,转换为CandidateComponentsIndex对象,此时组件扫描会读取CandidateComponentsIndex,而不进行实际扫描,从而提高组件扫描效率,减少应用启动时间。如果使用该功能,需要引入如下依赖:

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-context-indexerartifactId>
    <version>${spring.version}version>
    <optional>trueoptional>
dependency>

ClassPathScanningCandidateComponentProvider.scanCandidateComponents(String basePackage)

该方法是从指定的包路径获取到字节码文件,筛选出可能注入到Spring容器的Bean生成对应的ScannedGenericBeanDefinition

	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// // 形成完整包路径
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 扫描路径下的资源(字节码文件)
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			// 遍历所有资源(字节码文件),挑选有注解的字节码文件生成BeanDefinition
			for (Resource resource : resources) {
				String filename = resource.getFilename();
				if (filename != null && filename.contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
					// Ignore CGLIB-generated classes in the classpath
					continue;
				}
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				try {
					// 获得资源的MetadataReader(包含文件信息和对应类注解信息)
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					// 校验是否是候选组件,条件是:包含在include-filters(扫描时需要实例化的类,默认都包含)且 @Conditional注解中不跳过的类(默认都不跳过)
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setSource(resource);
						// 校验是否是候选组件:bean是独立且具体的类 或者 是抽象类但被@Lookup注解修饰
						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 (FileNotFoundException ex) {
					if (traceEnabled) {
						logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

ComponentScanBeanDefinitionParser.registerComponents( XmlReaderContext readerContext, Set beanDefinitions, Element element)

	protected void registerComponents(
			XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

		Object source = readerContext.extractSource(element);
		// 构建CompositeComponentDefinition
		CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
		// 将所有BeanDefinition添加到compositeDef的nestedComponents属性中
		for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
			compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
		}

		// Register annotation config processors, if necessary.
		// 处理“annotation-config”:假定annotation-config是存在,这意味着配置了“context:component-scan”,则不需要再配置“context:annotation-config”
		boolean annotationConfig = true;
		if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
			// 获取component-scan标签的annotation-config属性值(默认为true)
			annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
		}
		if (annotationConfig) {
			// 获取所有处理注解类的BeanPostProcessors(BeanPostProcessor本身也是bean)
			Set<BeanDefinitionHolder> processorDefinitions =
					AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
			// 将所有BeanPostProcessors的BeanDefinition添加到compositeDef的nestedComponents属性中
			for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
				compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
			}
		}

		// 触发组件注册事件
		readerContext.fireComponentRegistered(compositeDef);
	}

你可能感兴趣的:(Spring学习系列,spring,java,开发语言)