国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一起學(xué)SF框架系列5.8-spring-Beans-Bean注解解析3-解析配置component-scan

這篇具有很好參考價值的文章主要介紹了一起學(xué)SF框架系列5.8-spring-Beans-Bean注解解析3-解析配置component-scan。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

本文主要講述Spring是如何解析“context:component-scan”元素,掃描加載目錄下的BeanDefinition。

解析內(nèi)容

1、解析的元素如下:

	<!-- 注解模式:配置bean掃描路徑(注:自動包含子路徑) -->
	<context:component-scan base-package="com.learnsf.main,com.learnsf.service"/>

注:該元素解析過程中,會自動處理“context:annotation-config/”元素要解析的內(nèi)容。
2、只掃描加載目錄下的BeanDefinition,不對注解進行解析。在AbstractApplicationContext.invokeBeanFactoryPostProcessors統(tǒng)一解析。

解析

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);
		// 分解成包數(shù)組
		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屬性默認值,并設(shè)置 autowireCandidate 屬性
					postProcessBeanDefinition(abstractBeanDefinition, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
					// 對 AnnotatedBeanDefinition 類型的 BeanDefinition 進一步處理:對通用注解的解析處理,通用注解包括 @Lazy、@Primary、@DependsOn、@Role、@Description。例如:如果當(dāng)前類被@Lazy修飾,則會獲取@Lazy 的value 值并保存到 BeanDefinition#lazyInit 屬性中。
                    AnnotationConfigUtils.processCommonDefinitionAnnotations(annotatedBeanDefinition);
				}
				// 檢查給定候選bean的beanName,確定相應(yīng)的bean定義是否需要注冊或與現(xiàn)有定義沖突
				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注釋的類的模式解析結(jié)果。當(dāng)Spring應(yīng)用上下文進行組件掃描時,META-INF/spring.components會被org.springframework.context.index.CandidateComponentsIndexLoader讀取并加載,轉(zhuǎn)換為CandidateComponentsIndex對象,此時組件掃描會讀取CandidateComponentsIndex,而不進行實際掃描,從而提高組件掃描效率,減少應(yīng)用啟動時間。如果使用該功能,需要引入如下依賴:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-indexer</artifactId>
    <version>${spring.version}</version>
    <optional>true</optional>
</dependency>

ClassPathScanningCandidateComponentProvider.scanCandidateComponents(String basePackage)

該方法是從指定的包路徑獲取到字節(jié)碼文件,篩選出可能注入到Spring容器的Bean生成對應(yīng)的ScannedGenericBeanDefinition文章來源地址http://www.zghlxwxcb.cn/news/detail-600883.html

	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// // 形成完整包路徑
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 掃描路徑下的資源(字節(jié)碼文件)
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			// 遍歷所有資源(字節(jié)碼文件),挑選有注解的字節(jié)碼文件生成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(包含文件信息和對應(yīng)類注解信息)
					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);
		// 構(gòu)建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標(biāo)簽的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));
			}
		}

		// 觸發(fā)組件注冊事件
		readerContext.fireComponentRegistered(compositeDef);
	}

到了這里,關(guān)于一起學(xué)SF框架系列5.8-spring-Beans-Bean注解解析3-解析配置component-scan的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【Spring框架全系列】方法注解@Bean的使用

    【Spring框架全系列】方法注解@Bean的使用

    ????哈嘍,大家好,我是小浪。上篇博客我們介紹了五大類注解的使用方法,以及如何解決Spring使用五大類注解生成bean-Name的問題;那么,談到如何更簡單的讀取和存儲對象,這里我們還需要介紹另外一個\\\"方法注解@Bean\\\"的使用,快來一起學(xué)習(xí)叭!???? ??目錄 一、如何使

    2024年02月04日
    瀏覽(22)
  • Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definiti

    Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definiti

    Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true 解決方法: 在application.yml或你項目對應(yīng)的配置文件中添加如下代碼: 實踐驗證: 為了驗證該配置信息是否會造成覆蓋問題,現(xiàn)模擬一下情況: 項目中有feign模塊、service_user模塊、serv

    2024年02月04日
    瀏覽(30)
  • Spring6.0官方文檔示例:(26)配置文件中beans配置的default-init-method優(yōu)先級低于bean上配置的init-method
  • Spring框架中的Bean

    在Spring框架中,Bean是指一個由Spring容器管理的對象。這個對象可以是任何一個Java類的實例,例如數(shù)據(jù)庫連接、業(yè)務(wù)邏輯類、控制器等等。Bean實例的創(chuàng)建和管理是由Spring容器負責(zé)的,而不是由應(yīng)用程序本身負責(zé)。 Bean的主要優(yōu)勢是可以將對象的創(chuàng)建和管理與業(yè)務(wù)邏輯分離。這

    2023年04月09日
    瀏覽(14)
  • Spring系列三:基于注解配置bean

    Spring系列三:基于注解配置bean

    上文中, 我們學(xué)習(xí)到了 Spring系列二:基于XML配置bean 接下來我們學(xué)習(xí), 通過注解配置bean 基于注解的方式配置 bean , 主要是項目開發(fā)中的組件, 比如 Controller, Service 和 Dao. 組件注解的形式有 1. @Component 表示當(dāng)前注解標(biāo)識的是一個組件 2. @Controller 表示當(dāng)前注解標(biāo)識的是一個控制器

    2024年02月13日
    瀏覽(22)
  • Spring系列篇 -- Bean的生命周期

    Spring系列篇 -- Bean的生命周期

    目錄 經(jīng)典面試題目: 一,Bean的生命周期圖 二,關(guān)于Bean的生命周期流程介紹: 三,Bean的單例與多例模式 總結(jié): 前言:今天小編給大家?guī)淼氖顷P(guān)于Spring系列篇中的Bean的生命周期講解。在了解Bean的生命周期建議先看Spring 的AOP的講解。希望大家看了能夠?qū)δ銈儗W(xué)習(xí),工作帶

    2024年02月12日
    瀏覽(20)
  • 4.3---Spring框架之Spring中bean的注入方式---(深入版本)

    Spring基于xml注入bean的幾種方式: set()方法注入; 2.構(gòu)造器注入:①通過index設(shè)置參數(shù)的位置;②通過type設(shè)置參數(shù)類型; 靜態(tài)工廠注入; 實例工廠; Spring IOC注入方式用得最多的是(1)(2)種; 注意:通過Spring創(chuàng)建的對象默認是單例的,如果需要創(chuàng)建多實例對象可以在標(biāo)簽后面添

    2023年04月10日
    瀏覽(20)
  • 【框架源碼】Spring源碼解析之Bean生命周期流程

    【框架源碼】Spring源碼解析之Bean生命周期流程

    觀看本文前,我們先思考一個問題,什么是Spring的bean的生命周期?這也是我們在面試的時候,面試官常問的一個問題。 在沒有Spring之前,我們創(chuàng)建對象的時候,采用new的方式,當(dāng)對象不在被使用的時候,由Java的垃圾回收機制回收。 而 Spring 中的對象是 bean,bean 和普通的 J

    2024年02月09日
    瀏覽(21)
  • 【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

    【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

    問題:Spring中是如何初始化單例bean的? 我們都知道Spring解析xml文件描述成BeanDefinition,解析BeanDefinition最后創(chuàng)建Bean將Bean放入單例池中,那么Spring在創(chuàng)建Bean的這個過程都做了什么。 Spring核心方法refresh()中最最重要的一個方法 finishBeanFactoryInitialization() 方法,該方法負責(zé)初始化

    2024年02月09日
    瀏覽(19)
  • Spring框架Bean對象的五個作用域

    Spring框架Bean對象的五個作用域

    ? 在Spring項目中,那些 由Spring?IoC容器所管理的對象,稱為bean 。簡單地講,bean就是由Spring容器初始化、裝配及管理的對象,除此之外,bean就與應(yīng)用程序中的其他對象沒有什么區(qū)別了。?而bean定義以及bean相互間的依賴關(guān)系將通過配置元數(shù)據(jù)來描述。 上一段描述簡析: spri

    2024年03月09日
    瀏覽(17)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包