spring 中包自动扫描之 component-scan 解析

news2024/9/9 1:12:50

在 spring 中,为简化 bean 的配置,在 spring-context 模块下提供了包的自动扫描功能,将配置的包及其子包下的所有符合条件的类都注册到 BeanFactory 中。下面来看下具体是怎么实现的。

配置

<context:component-scan base-package="com.icheetor.annotation.service"/>

配置很简单,但背后要实现的功能确比较复杂,先来看看 spring 对这段配置的解析。

解析

在 META-INF/spring.handlers 文件中,找到自定义标签 context 对应的 handler 为 ContextNamespaceHandler,查看 ContextNamespaceHandler#init 方法,name 为 component-scan 对应的解析器为 ComponentScanBeanDefinitionParser,进入 ComponentScanBeanDefinitionParser#parse 方法。

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
	String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
	basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
	String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
			ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	// 扫描 bean 定义,并注册它们
    // 1.配置扫描器
	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    // 2.执行扫描,得到 BeanDefinition 并注册到 BeanFactory
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
    // 3.注册注解相关后置处理器
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}

先是对 basePackage 的解析,此处也支持 "${...}" 占位符,但这种一开始 xml 解析时,由 spring 中的属性解析器 PropertyResolver 可知,所支持的占位字符串很有限。basePackage 也支持多个包的配置,以 "," 或 ";" 分隔即可,将 basePackage 解析为名称为 basePackages 的 String 数组。

此处解析 basePackage 中占位符时采用的策略很宽松,resolvePlaceholders,没有默认值的无法解析占位符将被忽略,并原封不动地传递。

解析完 basePackage,接着进行扫描器的配置,有了路径,还需要工具来执行。

扫描器配置

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
	boolean useDefaultFilters = true;
	// 使用默认过滤器,默认 true
	if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
		useDefaultFilters = Boolean.parseBoolean(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
	}

	// Delegate bean definition registration to scanner class.
	ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
	scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
	scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

	if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
		scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
	}

	try {
        // 解析 name-generator
		parseBeanNameGenerator(element, scanner);
	}
	catch (Exception ex) {
		parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
	}

	try {
		parseScope(element, scanner);
	}
	catch (Exception ex) {
		parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
	}
    
    // 解析子标签,是否存在 include-filter 或 exclude-filter
	parseTypeFilters(element, scanner, parserContext);

	return scanner;
}

protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
	return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
			readerContext.getEnvironment(), readerContext.getResourceLoader());
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
		Environment environment, @Nullable ResourceLoader resourceLoader) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    // registry 即 BeanFactory
	this.registry = registry;

	if (useDefaultFilters) {
		registerDefaultFilters();
	}
    // 全局 Environment,创建 ApplicationContext 时创建
	setEnvironment(environment);
    // ApplicationContext 继承 ResourceLoader,当采用 ClassPathXmlApplicationContext,此处 resourceLoader 即 ClassPathXmlApplicationContext
	setResourceLoader(resourceLoader);
}
// 注册默认过滤器
protected void registerDefaultFilters() {
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
	}
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

注册过滤器,默认只对 @Component 注解标识的类进行注册

设置 ResourceLoader,用于对资源文件进行解析加载。

@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
	this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
	this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
    // 加载 META-INF/spring.components 下配置的候选的 Component,是一个扩展,默认 null
	this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}

此处resourceLoader 若为 ApplicationContext 子类,则获取的 resourcePatternResolver 就是 resourceLoader。

public CachingMetadataReaderFactory(@Nullable ResourceLoader resourceLoader) {
	super(resourceLoader);
	if (resourceLoader instanceof DefaultResourceLoader) {
		this.metadataReaderCache =
				((DefaultResourceLoader) resourceLoader).getResourceCache(MetadataReader.class);
	}
	else {
		setCacheLimit(DEFAULT_CACHE_LIMIT);
	}
}
// CachingMetadataReaderFactory 父类
public SimpleMetadataReaderFactory(@Nullable ResourceLoader resourceLoader) {
	this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
}

// DefaultResourceLoader
public <T> Map<Resource, T> getResourceCache(Class<T> valueType) {
	// resourceCaches 为一 ConcurrentHashMap,对 computeIfAbsent 进行了重写,此时返回值为计算出的值
	return (Map<Resource, T>) this.resourceCaches.computeIfAbsent(valueType, key -> new ConcurrentHashMap<>());
}

类的元数据读取,resourceLoader 若为 AbstractApplicationContext 子类,则就是 DefaultResourceLoader 子类。在 DefaultResourceLoader.resourceCaches 中放入 key 为 MetadataReader.class,value 为一个 ConcurrentHashMap 实例对象。

配置完成,将 ClassPathBeanDefinitionScanner 实例对象返回。

扫描

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	// 遍历 basePackages
	for (String basePackage : basePackages) {
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
            // 解析 @Scope
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            // 设置 AbstractBeanDefinition 属性
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
            // 设置其它注解属性,存在的话,@Lazy/@Primary/@DependsOn/@Role/@Description
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
            // 校验 beanName 是否已经存在
			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;
}

遍历 basePackages,获取 basePackage 下的候选的 BeanDefinition。

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
	// 默认 null
	if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
		return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
	}
	else {
		return scanCandidateComponents(basePackage);
	}
}

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		// classpath*:com/icheetor/annotation/service/**/*.class
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		
		for (Resource resource : resources) {
			
			try {
				MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
				if (isCandidateComponent(metadataReader)) {
					ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
					sbd.setSource(resource);
					if (isCandidateComponent(sbd)) {
						...
						candidates.add(sbd);
					}
					else {
						...
					}
				}
				else {
					...
				}
			}
			catch (FileNotFoundException ex) {
				...
			}
			catch (Throwable ex) {
				...
			}
		}
	}
	catch (IOException ex) {
		...
	}
	return candidates;
}

protected String resolveBasePackage(String basePackage) {
	return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));
}

先将配置的 basePackage 包名解析为包搜索路径的指定模式,此处针对 "com.icheetor.annotation.service" 解析出的 packageSearchPath 为:

classpath*:com/icheetor/annotation/service/**/*.class

此时解析 basePackage 中的 "${...}" 采用严格的解析策略,因为后面要直接根据路径搜索,所以此处遇到无法解析的占位符直接抛出异常。

接着利用创建 ClassPathBeanDefinitionScanner 时调用 setResourceLoader 设置的 resourcePatternResolver 获取资源文件。从上面介绍可知,这就是 AbstractApplicationContext 子类。

// AbstractApplicationContext
@Override
public Resource[] getResources(String locationPattern) throws IOException {
	return this.resourcePatternResolver.getResources(locationPattern);
}
public AbstractApplicationContext() {
	this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
	return new PathMatchingResourcePatternResolver(this);
}

转化为利用创建 AbstractApplicationContext 时创建的 PathMatchingResourcePatternResolver 实例对象,获取资源文件,获取的详细过程参考 spring 中的资源文件加载。

此处根据匹配后缀 "**/*.class" 匹配到的都是 class 字节码文件,接着遍历返回的 resources,此处由于是 class 文件,将其封装为 FileSystemResource。

在前面的扫描器配置 setResourceLoader 中,创建了 CachingMetadataReaderFactory 实例对象,赋值给 metadataReaderFactory,所以此时调用 ClassPathScanningCandidateComponentProvider#getMetadataReaderFactory 时返回的就是前面创建的 CachingMetadataReaderFactory 实例对象。接着调用 CachingMetadataReaderFactory#getMetadataReader。

// CachingMetadataReaderFactory
@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
	if (this.metadataReaderCache instanceof ConcurrentMap) {
		// 先从缓存获取
		MetadataReader metadataReader = this.metadataReaderCache.get(resource);
		if (metadataReader == null) {
			// 不存在,通过父类进行创建
			metadataReader = super.getMetadataReader(resource);
			this.metadataReaderCache.put(resource, metadataReader);
		}
		return metadataReader;
	}
	else if (this.metadataReaderCache != null) {
		synchronized (this.metadataReaderCache) {
			MetadataReader metadataReader = this.metadataReaderCache.get(resource);
			if (metadataReader == null) {
				metadataReader = super.getMetadataReader(resource);
				this.metadataReaderCache.put(resource, metadataReader);
			}
			return metadataReader;
		}
	}
	else {
		return super.getMetadataReader(resource);
	}
}
// SimpleMetadataReaderFactory
@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
	return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}

CachingMetadataReaderFactory 是 SimpleMetadataReaderFactory 子类,相对于父类扩展了缓存 MetadataReader 的功能。

SimpleMetadataReader 的创建可参考 spring 中的字节码文件访问 -- classreading 包。

获取到 metadataReader 实例对象后,调用 ClassPathScanningCandidateComponentProvider#isCandidateComponent,判断是否是合格的候选者。

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
	for (TypeFilter tf : this.excludeFilters) {
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return false;
		}
	}
	for (TypeFilter tf : this.includeFilters) {
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return isConditionMatch(metadataReader);
		}
	}
	return false;
}

通过配置的 excludeFilters 和 includeFilters 对 metadataReader 进行匹配。匹配代码比较长,核心逻辑就是,利用 SimpleMetadataReader 中的 annotations,即 MergedAnnotationsCollection,遍历其中的 AnnotationTypeMappings 数组,接着遍历 AnnotationTypeMappings 中的 AnnotationTypeMapping 集合,获取其中的 annotationType 与指定注解类型进行匹配。

// MergedAnnotationsCollection
private <A extends Annotation> MergedAnnotation<A> find(Object requiredType,
		@Nullable Predicate<? super MergedAnnotation<A>> predicate,
		@Nullable MergedAnnotationSelector<A> selector) {

	if (selector == null) {
		// 默认选择器
		selector = MergedAnnotationSelectors.nearest();
	}

	MergedAnnotation<A> result = null;
	for (int i = 0; i < this.annotations.length; i++) {
		MergedAnnotation<?> root = this.annotations[i];
		AnnotationTypeMappings mappings = this.mappings[i];
		// 遍历 AnnotationTypeMappings 中的 mappings
		for (int mappingIndex = 0; mappingIndex < mappings.size(); mappingIndex++) {
			AnnotationTypeMapping mapping = mappings.get(mappingIndex);
			if (!isMappingForType(mapping, requiredType)) {
				continue;
			}
			// 匹配到了
			MergedAnnotation<A> candidate = (mappingIndex == 0 ? (MergedAnnotation<A>) root :
					TypeMappedAnnotation.createIfPossible(mapping, root, IntrospectionFailureLogger.INFO));
			if (candidate != null && (predicate == null || predicate.test(candidate))) {
				// 判断 distance == 0
				if (selector.isBestCandidate(candidate)) {
					return candidate;
				}
				// result 赋值
				result = (result != null ? selector.select(result, candidate) : candidate);
			}
		}
	}
	return result;
}
private static boolean isMappingForType(AnnotationTypeMapping mapping, @Nullable Object requiredType) {
	if (requiredType == null) {
		return true;
	}
	Class<? extends Annotation> actualType = mapping.getAnnotationType();
	return (actualType == requiredType || actualType.getName().equals(requiredType));
}

注解类型符合过滤条件,创建 BeanDefinition。

public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
	Assert.notNull(metadataReader, "MetadataReader must not be null");
	this.metadata = metadataReader.getAnnotationMetadata();
	setBeanClassName(this.metadata.getClassName());
	setResource(metadataReader.getResource());
}

之后将 ScannedGenericBeanDefinition 实例对象加入 candidates 返回。

接着遍历 candidates。执行 this.scopeMetadataResolver.resolveScopeMetadata(candidate),其目的是查看类上面是否有 @Scope 注解,存在,解析其上的 value 和 proxyMode 属性,之后将封装的 ScopeMetadata 实例对象返回。

ScopeMetadata 中默认 scopeName 为 "singleton"。

接着采用 AnnotationBeanNameGenerator 来生成 beanName。

@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
	if (definition instanceof AnnotatedBeanDefinition) {
		// 解析注解 value 属性获取 beanName
		String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
		if (StringUtils.hasText(beanName)) {
			// Explicit bean name found.
			return beanName;
		}
	}
	// 注解未配置 beanName,创建默认 beanName,类名首字母小写
	return buildDefaultBeanName(definition, registry);
}
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
	AnnotationMetadata amd = annotatedDef.getMetadata();
	// 获取注解类型
	Set<String> types = amd.getAnnotationTypes();
	String beanName = null;
	for (String type : types) {
		// 解析 type 上属性,得到 AnnotationAttributes
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
		if (attributes != null) {
			// 解析 type 上 meta-type 
			// 举例: @Service  meta-type @Component   @Component 上 meta-type @Indexed,所以返回的 metaTypes 会包含 @Component 和 @Indexed
			Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
				Set<String> result = amd.getMetaAnnotationTypes(key);
				return (result.isEmpty() ? Collections.emptySet() : result);
			});
			// metaTypes 是否含有 @Component,attributes 是否含有 value 属性
			if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
				Object value = attributes.get("value");
				if (value instanceof String) {
					String strVal = (String) value;
					if (StringUtils.hasLength(strVal)) {
						if (beanName != null && !strVal.equals(beanName)) {
							throw ...
						}
						beanName = strVal;
					}
				}
			}
		}
	}
	return beanName;
}

注解上存在 value 属性,解析后将其作为 beanName,不存在创建一个默认 beanName,即类名首字母小写。

接着为 beanDefinition 设置相关属性,分别调用 ClassPathBeanDefinitionScanner#postProcessBeanDefinition 和 AnnotationConfigUtils#processCommonDefinitionAnnotations 两个方法。

最后,完成 beanDefintion 注册。也就是说,在扫描的这一步就已经完成了 BeanDefinition 的注册。

注册后置处理器

接着,在 BeanFactory 中注册所有注解相关的后置处理器。

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

	Object source = readerContext.extractSource(element); // null
	CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

	for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
		compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
	}

	// Register annotation config processors, if necessary.
	boolean annotationConfig = true;
	if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
		annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
	}
	if (annotationConfig) {
		Set<BeanDefinitionHolder> processorDefinitions =
				AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
		for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
			compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
		}
	}

	readerContext.fireComponentRegistered(compositeDef);
}

// AnnotationConfigUtils
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			// beanFactory 设置 dependencyComparator
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			// beanFactory 设置 autowireCandidateResolver
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    // BeanDefinitionRegistryPostProcessor 实现类
	// org.springframework.context.annotation.internalConfigurationAnnotationProcessor
	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

    // BeanPostProcessor 实现类,实例化时使用
	// org.springframework.context.annotation.internalAutowiredAnnotationProcessor
	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

    // BeanFactoryPostProcessor 实现类
	// org.springframework.context.event.internalEventListenerProcessor
	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}

    // EventListenerFactory 接口
	// org.springframework.context.event.internalEventListenerFactory
	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}

// 注册内部后置处理器对应的 BeanDefinition
private static BeanDefinitionHolder registerPostProcessor(
		BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

	definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	registry.registerBeanDefinition(beanName, definition);
	return new BeanDefinitionHolder(definition, beanName);
}

只有 beanFactory 中的 dependencyComparator 和 autowireCandidateResolver 属性直接设置的是实例对象,其它内部的后置处理器都是作为 BeanDefinition 先注册在 BeanFactory 中,待 AbstractApplicationContext#refresh 中执行 invokeBeanFactoryPostProcessors 和 registerBeanPostProcessors 时通过 beanFactory.getBean 创建实例对象,完成后置处理器的注册。

此处还有一点要注意,就是 autowireCandidateResolver,看似只创建了 ContextAnnotationAutowireCandidateResolver 一个实例对象,但由于继承关系,实际上也获得了处理处理其它注解的能力。其类结构如下:

这样,就完成了基于注解的包扫描模式下的 BeanDefinition 的注册,也完成了对 context 标签下 component-scan 的解析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1958856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MIT 6.5840(6.824)学习笔记】Raft

1 脑裂 许多容错系统使用一个单主节点来决定主副本。 MapReduce&#xff1a;由单主节点控制计算复制。GFS&#xff1a;主备复制数据&#xff0c;并由单主节点确定主拷贝的位置。VMware FT&#xff1a;主虚机和备份虚机之间复制指令&#xff0c;需要单点的Test-and-Set服务确认…

[0729] X-CMD 发布 v0.4.3:借助 fzf ,提升用户使用体验

目录 X-CMD 发布 v0.4.3&#x1f50e; ll&#x1f50e; jq&#x1f50e; yq&#x1f50e; man X-CMD 发布 v0.4.3 &#x1f50e; ll 新增 --fzf 子命令 该命令借助 fzf 为用户提供了一种高效查找文件和目录的相关信息的方法&#xff0c;类似于文件管理器。 # 使用 fzf 查找文…

AI智能名片O2O商城小程序源码在社区团购中的应用与红利深度探索

摘要&#xff1a;在数字化转型的浪潮中&#xff0c;社区团购以其独特的商业模式和强大的市场渗透力&#xff0c;成为新零售领域的一股不可忽视的力量。而AI智能名片O2O商城小程序源码&#xff0c;作为技术创新的集大成者&#xff0c;正逐步渗透并深刻改变着社区团购的运作模式和…

从零开始编写一个Chrome插件:详细教程

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…

科普文:抽屉合同/协议

抽屉协议是指一种在特定情境下&#xff0c;当事人之间私下签订的、不公开披露的协议。通常情况下&#xff0c;除了协议双方外&#xff0c;其他人并不知道这份协议的存在。这种协议在需要时会被拿出来&#xff0c;因为它已经过双方签字盖章&#xff0c;同样具有法律效应。 背景…

SN65MLVD080使用手册

8通道半双工M-LVDS线路收发器 特性 低压差分30欧姆至55欧姆线路驱动器和接收器&#xff0c;支持信号速率高达250 Mbps&#xff1b;时钟频率高达125 MHz 满足或超过M-LVDS标准TIA/EIA-899多点数据交换规范 受控驱动器输出电压转换时间&#xff0c;提高信号质量 -1V至3.4V共模…

【C++版本】protobuf与gRPC

文章目录 一、Protobuf二、安装以及使用protoc参考 一、Protobuf Google Protocol Buffers&#xff08;protobuf&#xff09;是一种语言中立、平台中立的序列化协议&#xff0c;旨在高效地将结构化数据进行序列化和反序列化。它主要用于通信协议、数据存储和其他需要高效编码和…

【CAN通讯系列5】CAN数据帧及其仲裁

在CAN通讯系列3-CAN通讯如何传递信号中&#xff0c;由于传递信号的分析需要&#xff0c;引出了CAN数据帧的ID&#xff0c;长度和数据段的概念&#xff0c;它们都与CAN协议帧相关。CAN协议帧有5种类型&#xff0c;如下表&#xff1a; 而我们当前使用到的是数据帧&#xff0c;故本…

【Qwen-Audio部署实战】Qwen-Audio-Chat模型之FastApi部署实战

系列篇章&#x1f4a5; No.文章1【Qwen部署实战】探索Qwen-7B-Chat&#xff1a;阿里云大型语言模型的对话实践2【Qwen2部署实战】Qwen2初体验&#xff1a;用Transformers打造智能聊天机器人3【Qwen2部署实战】探索Qwen2-7B&#xff1a;通过FastApi框架实现API的部署与调用4【Q…

10 BERT

目录 1 综述 1.1 BERT的核心思想 1.2 BERT的关键技术&#xff1a;预训练阶段 1.3 微调阶段 2 BERT的架构 2.1 输入处理 3. 特征选择/学习模块 BERT 的自注意力过程 4. 预训练任务&#xff1a;同时进行 4.1 Next Sentence Prediction (NSP) 4.2 Masked Language Model…

Url图标实现

Url图标实现 效果如下&#xff1a; 1.引入样式 <link rel"icon" href"favicon.ico"> favicon.ico和对应的html一般需要在同一个目录下&#xff08;同级别&#xff09;。 2.title是用来设置在url页签中显示的名称。 可能存在的问题&#xff1a; …

如何通过前端表格控件实现自动化报表?

背景 最近伙伴客户的项目经理遇见一个问题&#xff0c;他们在给甲方做自动化报表工具&#xff0c;项目已经基本做好了&#xff0c;但拿给最终甲方&#xff0c;业务人员不太买账&#xff0c;项目经理为此也是天天抓狂&#xff0c;没有想到合适的应对方案。 现阶段主要面临的问…

filament 初使用记录

安装初始化 一、环境准备 官网要的 我安装的 二、下载安装 安装laravel composer create-project --prefer-dist laravel/laravel 项目名称 10.*导入 filament composer require filament/filament注册 filament 管理面板 php artisan filament:install --panels初始化…

KubeSphere部署:(一)环境准备

本文介绍windows系统&#xff0c;安装wsl虚拟机&#xff08;ubuntu&#xff09;&#xff0c;并在ubruntu中配置连接私有harbor及阿里云镜像等。 在确定该方式前&#xff0c;博主也曾尝试过通过安装Docker Desktop的方式&#xff0c;但每次重启电脑之后&#xff0c;docker桌面端…

Photoshop 2023:创意无限的图像编辑神器

Photoshop 2023 是一款专为 Mac 和 Windows 系统设计的强大图像编辑软件&#xff0c;为专业设计师和业余爱好者提供了无与伦比的创作工具和功能。 一、强大的编辑工具 Photoshop 2023 拥有丰富的编辑工具&#xff0c;如选择工具、画笔工具、橡皮擦工具等。其选择工具能够精确…

Matlab编程资源库(14)常微分方程初值问题的数值解法

一、 龙格&#xff0d;库塔法简介 龙格-库塔法&#xff08;Runge-Kutta method&#xff09;是一种常用的数值解微分方程的方法&#xff0c;由德国数学家卡尔龙格&#xff08;Carl Runge&#xff09;和马丁威尔海尔姆库塔&#xff08;Martin Wilhelm Kutta&#xff09;在20世纪…

Windows11下 Visual Studio 2022 + Qt6 的 WebSocket 线程池异步 客户端

Windows11下 Visual Studio 2022 + Qt6 的 WebSocket 线程池异步 客户端 1 开发 WebSocket 客户端1.1 开发环境1.1.1 为Qt 6安装 websockets1.2 .基于Qt6的 QWebSocket 客户端示例1.2.1 实现 WebSocket 客户端1.2.2 创建 QtQWesocketClient1.2.3 创建QWebsocket对象1.2.3.1 添加…

轻松实现人声与伴奏分离,轻松获取纯净音质

SpleeterGui是一款用于人声与伴奏分离的开源软件&#xff0c;基于Python的Spleeter库开发而成。SpleeterGui支持的操作系统包括Windows、macOS和Linux&#xff0c;用户可以根据自己的需求选择合适的版本进行下载和使用。 使用教程 1、解压 人声伴奏分离软件-SpleeterGUI_2.9.5…

前端必知必会-html实体与保留字转换和符号

文章目录 HTML 实体HTML 字符实体一些有用的 HTML 字符实体HTML 符号HTML 符号实体数学符号希腊字母其他一些实体总结 HTML 实体 HTML 中的保留字符必须用实体替换&#xff1a; <&#xff08;小于&#xff09; < >&#xff08;大于&#xff09; >HTML 字符实体 …

C#体检系统源码,医院健康体检系统PEIS,C#+VS2016+SQLSERVER

体检中心/医院体检科PEIS系统源码&#xff0c;C#健康体检信息系统源码&#xff0c;PEIS源码 开发环境&#xff1a;C/S架构C#VS2016SQLSERVER 2008 检前&#xff1a; 多种预约方式网站预约、电话预约、微信平台预约及检前沟通&#xff0c;提前制作套餐&#xff0c;客人到达体检…