最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring @ComponentScan注解掃描組件原理

 更新時間:2023年01月10日 09:31:33   作者:xuguofeng2016  
這篇文章主要介紹了Spring @ComponentScan自動掃描組件使用,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

本文將通過閱讀spring源碼,分析@ComponentScan注解掃描組件的原理。

和@Bean注解一樣,@ComponentScan注解也是通過ConfigurationClassPostProcessor后置處理器完成掃描工作的。

在《Spring-@Bean注解源碼分析》中,詳細介紹了spring注冊、調(diào)用ConfigurationClassPostProcessor后置處理器的流程,本文不再重復記錄。

ConfigurationClassPostProcessor類

ConfigurationClassPostProcessor實現(xiàn)了BeanDefinitionRegistryPostProcessor接口,spring容器在refresh過程中,會調(diào)用所有BeanDefinitionRegistryPostProcessor處理器的postProcessBeanDefinitionRegistry方法:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	// ...
	// Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		parser.parse(candidates);
		parser.validate();
		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		configClasses.removeAll(alreadyParsed);
		// Read the model and create bean definitions based on its content
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
		this.reader.loadBeanDefinitions(configClasses);
		// ...

重點邏輯在parser.parse(candidates)處,作用是解析@Configuration類。

Parse each @Configuration class

parser.parse(candidates);

最終調(diào)用到:

protected final SourceClass doProcessConfigurationClass(
		ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
		throws IOException {
	// ...
	// 1. 解析@ComponentScan注解元數(shù)據(jù)
	Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    // 2. 判斷標注了@ComponentScan注解且不skip該類
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(
                sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        // 可能標注多個@ComponentScan注解
		for (AnnotationAttributes componentScan : componentScans) {
			// 3. 通過@ComponentScan解析組件BeanDefinition集
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			// Check the set of scanned definitions for any further config classes and
            // parse recursively if needed
            // 4. 遞歸解析
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					bdCand = holder.getBeanDefinition();
				}
				if (ConfigurationClassUtils
                    	.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}
	// ...
}

重點在第3點,通過@ComponentScan解析組件BeanDefinition集:

this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

componentScanParser是ComponentScanAnnotationParser類型對象,parse方法解析ComponentScan注解,掃描組件。

ComponentScanAnnotationParser類

parse方法解析ComponentScan注解,掃描組件:

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
	Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
	boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
	scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
			BeanUtils.instantiateClass(generatorClass));
	ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
	if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
		scanner.setScopedProxyMode(scopedProxyMode);
	} else {
		Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
		scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
	}
	scanner.setResourcePattern(componentScan.getString("resourcePattern"));
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addIncludeFilter(typeFilter);
		}
	}
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addExcludeFilter(typeFilter);
		}
	}
	boolean lazyInit = componentScan.getBoolean("lazyInit");
	if (lazyInit) {
		scanner.getBeanDefinitionDefaults().setLazyInit(true);
	}
	Set<String> basePackages = new LinkedHashSet<>();
	String[] basePackagesArray = componentScan.getStringArray("basePackages");
	for (String pkg : basePackagesArray) {
		String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		Collections.addAll(basePackages, tokenized);
	}
	for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
		basePackages.add(ClassUtils.getPackageName(clazz));
	}
	if (basePackages.isEmpty()) {
		basePackages.add(ClassUtils.getPackageName(declaringClass));
	}
	scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
		@Override
		protected boolean matchClassName(String className) {
			return declaringClass.equals(className);
		}
	});
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}

ClassPathBeanDefinitionScanner類

doScan方法掃描指定包下面的組件:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	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);
				// 注冊到容器
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
	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 {
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		for (Resource resource : resources) {
			if (resource.isReadable()) {
				try {
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    // 判斷是否是需要掃描的spring組件,遍歷excludeFilters和includeFilters集來進行判斷
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							candidates.add(sbd);
						}
					}
				} catch (Throwable ex) {
					throw new BeanDefinitionStoreException("");
				}
			}
		}
	} catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

到此這篇關(guān)于Spring @ComponentScan注解掃描組件原理的文章就介紹到這了,更多相關(guān)Spring @ComponentScan注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Shiro安全框架的主要組件及認證過程簡介

    Shiro安全框架的主要組件及認證過程簡介

    這篇文章主要介紹了Shiro安全框架的主要組件及認證過程簡介,Shiro?是一個強大靈活的開源安全框架,可以完全處理身份驗證、授權(quán)、加密和會話管理,本文就來介紹一下此框架的核心組成,需要的朋友可以參考下
    2023-08-08
  • Java 8實現(xiàn)任意參數(shù)的單鏈表

    Java 8實現(xiàn)任意參數(shù)的單鏈表

    這篇文章主要為大家詳細介紹了Java 8實現(xiàn)任意參數(shù)的單鏈表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • springboot整合mqtt的詳細圖文教程

    springboot整合mqtt的詳細圖文教程

    MQTT是一種基于發(fā)布/訂閱(publish/subscribe)模式的“輕量級”通訊協(xié)議,該協(xié)議構(gòu)建于TCP/IP協(xié)議上,由IBM在1999年發(fā)布,下面這篇文章主要給大家介紹了關(guān)于springboot整合mqtt的詳細圖文教程,需要的朋友可以參考下
    2023-02-02
  • 示例解析java面向?qū)ο缶幊谭庋b與訪問控制

    示例解析java面向?qū)ο缶幊谭庋b與訪問控制

    這篇文章主要為大家介紹了java封裝與訪問控制的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Java?8?Time?Api?使用方法技巧

    Java?8?Time?Api?使用方法技巧

    這篇文章主要介紹了Java?8?Time?Api?使用方法技巧,Java?8為Date和Time引入了新的API,以解決舊java.util.Date和java.util.Calendar的缺點,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-05-05
  • JAVA實現(xiàn)讀取txt文件內(nèi)容的方法

    JAVA實現(xiàn)讀取txt文件內(nèi)容的方法

    本篇文章主要介紹了JAVA實現(xiàn)讀取txt文件內(nèi)容的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • java必學必會之equals方法

    java必學必會之equals方法

    java必學必會之equals方法,equals方法是 java.lang.Object 類的方法,想要了解更多關(guān)于equals方法的朋友,可以參考下文
    2015-12-12
  • Java使用utf8格式保存文本文件的方法

    Java使用utf8格式保存文本文件的方法

    這篇文章主要介紹了Java使用utf8格式保存文本文件的方法,涉及Java針對字符流編碼操作的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • idea 實現(xiàn)搜索jdk中的類和包操作

    idea 實現(xiàn)搜索jdk中的類和包操作

    這篇文章主要介紹了idea 實現(xiàn)搜索jdk中的類和包操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Struts之logic標簽庫詳解

    Struts之logic標簽庫詳解

    本文就Struts之logic標簽庫進行詳細介紹,需要的朋友可以參考下
    2012-11-11

最新評論

枣庄市| 丹江口市| 忻州市| 辉县市| 新丰县| 开阳县| 河北区| 郯城县| 华池县| 东兰县| 马关县| 湘潭县| 长白| 名山县| 乾安县| 昌吉市| 县级市| 子长县| 专栏| 洛宁县| 长沙县| 浦江县| 信阳市| 黔江区| 福贡县| 阳东县| 江津市| 罗城| 马山县| 武城县| 东丽区| 新蔡县| 江川县| 杭锦后旗| 阿拉善盟| 酒泉市| 禄丰县| 大庆市| 马关县| 昆明市| 宜兰市|