欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析SpringBoot自動(dòng)裝配的實(shí)現(xiàn)

 更新時(shí)間:2022年02月22日 08:19:57   作者:chenzw93  
springboot開(kāi)箱即用,其實(shí)實(shí)現(xiàn)了自動(dòng)裝配,本文重點(diǎn)給大家介紹SpringBoot是如何做到自動(dòng)裝配的,感興趣的朋友跟隨小編一起看看吧

背景

眾所周知,如下即可啟動(dòng)一個(gè)最簡(jiǎn)單的Spring應(yīng)用。查看@SpringBootApplication注解的源碼,發(fā)現(xiàn)這個(gè)注解上有一個(gè)重要的注解@EnableAutoConfiguration,而這個(gè)注解就是SpringBoot實(shí)現(xiàn)自動(dòng)裝配的基礎(chǔ)

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

@EnableAutoConfiguration

EnableAutoConfiguration注解上通過(guò)@Import引入了兩個(gè)類(lèi),org.springframework.boot.autoconfigure.AutoConfigurationImportSelectororg.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar。通過(guò)@Import標(biāo)注的類(lèi),會(huì)在解析@Import所在的配置類(lèi)時(shí),將標(biāo)注類(lèi)引入容器解析,并進(jìn)行注冊(cè)。

有眾多的組件都是通過(guò)在配置類(lèi)上加@EnableAutoConfiguration注解將組件引入的

  • ImportBeanDefinitionRegistrar實(shí)現(xiàn)了org.springframework.context.annotation.ImportBeanDefinitionRegistrarorg.springframework.boot.context.annotation.DeterminableImports
  • AutoConfigurationImportSelector實(shí)現(xiàn)了org.springframework.context.annotation.DeferredImportSelector
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ....
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
    ...
}

解析

起始

通過(guò)BeanFactoryPostProcessor對(duì)需要注冊(cè)的Bean進(jìn)行解析。即org.springframework.context.support.AbstractApplicationContext#refresh,在AbstractApplicationContext#invokeBeanFactoryPostProcessors方法調(diào)用時(shí),就開(kāi)始了對(duì)服務(wù)配置bean的解析,為對(duì)象的生成做準(zhǔn)備

 @Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			...

			try {
				...
                    
				invokeBeanFactoryPostProcessors(beanFactory);
			}
			catch (BeansException ex) {
			finally {
		}
	}

具體解析

調(diào)用org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors,通過(guò)獲取到的BeanFactoryPostProcessor實(shí)現(xiàn)類(lèi)對(duì)各種配置類(lèi)進(jìn)行解析,具體的BeanFactoryPostProcessor解析后面我們?cè)诰唧w分析。

這里有一個(gè)很重要的類(lèi)org.springframework.context.annotation.ConfigurationClassPostProcessor,首先會(huì)調(diào)用postProcessBeanDefinitionRegistry方法

// ConfigurationClassPostProcessor類(lèi)部門(mén)源碼

	/**
	 * Derive further bean definitions from the configuration classes in the registry.
	 */
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
					"postProcessBeanFactory already called on this post-processor against " + registry);
		this.registriesPostProcessed.add(registryId);
	
                // 處理配置類(lèi)
		processConfigBeanDefinitions(registry);
	}
	 * Build and validate a configuration model based on the registry of
	 * {@link Configuration} classes.
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		...
		// Parse each @Configuration class
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
                // configCandidates為待解析的Configuration類(lèi),如配置了@SpringBootApplication的類(lèi)
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
                        // 開(kāi)始解析
			parser.parse(candidates);
			parser.validate();
			...
		while (!candidates.isEmpty());

通過(guò)源碼可知,具體的解析操作是在org.springframework.context.annotation.ConfigurationClassParser類(lèi)中

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
                                        // 將配置類(lèi)進(jìn)行解析。以當(dāng)前配置類(lèi)為原配置類(lèi),解析@PropertySource、@ComponentScan、@Import、@ImportResource、					 
                                        // @Bean等標(biāo)注的類(lèi)或方法,生成對(duì)應(yīng)的
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
			}
			...
		}

   		// 解析通過(guò)@Import引入的配置類(lèi),自動(dòng)配置類(lèi)的解析也在于此
		this.deferredImportSelectorHandler.process();
	}
	public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				Predicate<String> exclusionFilter = grouping.getCandidateFilter();
                                // grouping.getImports()方法獲取到了所有配置的可用自動(dòng)配置類(lèi),然后遍歷,以配置類(lèi)原點(diǎn)又開(kāi)始一輪解析。自動(dòng)裝配就是在此處
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
					try {
                                                // import的解析
						processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
								Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
								exclusionFilter, false);
					}
					catch (BeanDefinitionStoreException ex) {
						throw ex;
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to process import candidates for configuration class [" +
										configurationClass.getMetadata().getClassName() + "]", ex);
				});

通過(guò)DeferredImportSelectorGrouping.getImports()方法解析。在org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry方法中開(kāi)始了autoConfiguration的解析。

/**
	 * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
	 * of the importing {@link Configuration @Configuration} class.
	 * @param annotationMetadata the annotation metadata of the configuration class
	 * @return the auto-configurations that should be imported
	 */
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
                // 解析@EnableAutoConfiguration注解中的屬性exclude、excludeName
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
                // 使用SpringFactoriesLoader獲取META-INF/spring.properties中配置的EnableAutoConfiguration實(shí)現(xiàn)類(lèi),獲取所有配置的自動(dòng)裝配類(lèi)
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
                // 去重
		configurations = removeDuplicates(configurations);
                // 獲取需要排除的自動(dòng)裝配類(lèi)
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
                //getConfigurationClassFilter()方法就是獲取spring.factories中配置的AutoConfigurationImportFilter實(shí)現(xiàn)類(lèi)。然后調(diào)用filter		//法對(duì)自動(dòng)裝配類(lèi)進(jìn)行有效性校驗(yàn)
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

再繼續(xù)看org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.ConfigurationClassFilter#filter

List<String> filter(List<String> configurations) {
			long startTime = System.nanoTime();
			String[] candidates = StringUtils.toStringArray(configurations);
			boolean skipped = false;
			for (AutoConfigurationImportFilter filter : this.filters) {
                                // autoConfigurationMetadata為通過(guò)META-INF/spring-autoconfigure-metadata.properties配置文件的內(nèi)容
                                // 使用filter及autoConfigurationMetadata對(duì)candidates進(jìn)行校驗(yàn)
				boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
				for (int i = 0; i < match.length; i++) {
					if (!match[i]) {
						candidates[i] = null;
						skipped = true;
					}
				}
			}
			if (!skipped) {
				return configurations;
			}
        	...
			return result;
		}

再繼續(xù)看match方法,org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition#match

@Override
	public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
                // 抽象方法,不同的filter進(jìn)行不同的處理。這里會(huì)獲取每一個(gè)自動(dòng)裝配類(lèi)的條件判斷情況
		ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
		boolean[] match = new boolean[outcomes.length];
		for (int i = 0; i < outcomes.length; i++) {
			match[i] = (outcomes[i] == null || outcomes[i].isMatch());
			if (!match[i] && outcomes[i] != null) {
				logOutcome(autoConfigurationClasses[i], outcomes[i]);
				if (report != null) {
					report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
				}
			}
		}
		return match;
	}

通過(guò)match方法,經(jīng)過(guò)多種filter的過(guò)濾,返回的就是每一個(gè)自動(dòng)配置類(lèi)是否可用

結(jié)論

  • SpringBoot項(xiàng)目有一個(gè)子項(xiàng)目org.springframework.boot:spring-boot-autoconfigure:xx,這個(gè)子項(xiàng)目主要就是做自動(dòng)裝配的。SpringBoot提前配置了眾多已經(jīng)實(shí)現(xiàn)自動(dòng)配置功能的配置類(lèi)(org.springframework.boot.autoconfigure.EnableAutoConfiguration接口的實(shí)現(xiàn)類(lèi))。當(dāng)容器啟動(dòng)的時(shí)候,通過(guò) SpringFactoriesLoader將配置類(lèi)加載進(jìn)容器中
  • 啟動(dòng)中,容器通過(guò)BeanFactoryPostProcessor接口解析、修改對(duì)象的定義。有一個(gè)很重要的配置解析實(shí)現(xiàn)類(lèi)org.springframework.context.annotation.ConfigurationClassPostProcessor,用來(lái)解析項(xiàng)目中標(biāo)注@Configuration 的類(lèi)
  • 在進(jìn)行配置類(lèi)解析時(shí)(即解析配置了@SpringBootApplication注解的類(lèi)),需要經(jīng)過(guò)解析類(lèi)的 @PropertySource、@ComponentScan、@Import、@ImportResource、@Bean、接口默認(rèn)實(shí)現(xiàn)、父類(lèi)等(org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass)。對(duì)于自動(dòng)裝配來(lái)說(shuō),最重要的就是解析@Import
  • 通過(guò)@Import引入了org.springframework.boot.autoconfigure.AutoConfigurationImportSelector,在進(jìn)行解析@Import引入的配置類(lèi)時(shí),org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry獲取到所有配置的自動(dòng)裝配類(lèi)(通過(guò)META-INF/spring.factories文件配置EnableAutoConfiguration實(shí)現(xiàn)類(lèi)),通過(guò)org.springframework.context.annotation.Condition定義過(guò)濾器,判斷自動(dòng)裝配置是否需要自動(dòng)裝配。默認(rèn)的過(guò)濾器有OnClassCondition、OnWebApplicationConditionOnBeanCondition,對(duì)應(yīng)常見(jiàn)的condition注解ConditionalOnClass、ConditionalOnBean、@ConditionalOnWebApplication
  • 通過(guò)過(guò)濾判斷,將需要自動(dòng)配置的類(lèi)進(jìn)行configuration解析,從而將需要配置的類(lèi)轉(zhuǎn)換成對(duì)應(yīng)的BeanDefinition進(jìn)行注冊(cè)

備注

  • SpringBoot將自動(dòng)裝配類(lèi)及過(guò)濾條件通過(guò)配置文件的形式放在了META-INF目錄下,META-INF/spring.factoriesMETA-INF/spring-autoconfigure-metadata.properties
  • BeanFactoryPostProcessor進(jìn)行調(diào)用時(shí),有兩種處理。首先是通過(guò)BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry解析更多的BeanDefinition,在這里就包含了所有標(biāo)注類(lèi)的掃描解析,自動(dòng)裝配類(lèi)的解析,自動(dòng)裝配類(lèi)引入類(lèi)的解析。在進(jìn)行BeanFactoryPostProcessor#postProcessBeanFactory調(diào)用,進(jìn)行CGLIB-enhanced配置類(lèi)。這里最重要的一個(gè)類(lèi)就是org.springframework.context.annotation.ConfigurationClassPostProcessor,以下為此類(lèi)的繼承關(guān)系

到此這篇關(guān)于SpringBoot是如何做到自動(dòng)裝配的的文章就介紹到這了,更多相關(guān)SpringBoot自動(dòng)裝配內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 最新hadoop安裝教程及hadoop的命令使用(親測(cè)可用)

    最新hadoop安裝教程及hadoop的命令使用(親測(cè)可用)

    這篇文章主要介紹了最新hadoop安裝教程(親測(cè)可用),本文主要講解了如何安裝hadoop、使用hadoop的命令及遇到的問(wèn)題解決,需要的朋友可以參考下
    2022-06-06
  • java讀取txt文件并輸出結(jié)果

    java讀取txt文件并輸出結(jié)果

    這篇文章主要介紹了java讀取txt文件并輸出結(jié)果,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java OpenCV實(shí)現(xiàn)人臉識(shí)別過(guò)程詳解

    Java OpenCV實(shí)現(xiàn)人臉識(shí)別過(guò)程詳解

    這篇文章主要介紹了Java OpenCV實(shí)現(xiàn)人臉識(shí)別過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java上傳文件大小受限問(wèn)題的解決方法

    Java上傳文件大小受限問(wèn)題的解決方法

    這篇文章主要介紹了Java上傳文件大小受限怎么解決,本文給大家分享問(wèn)題分析及解決方案,需要的朋友可以參考下
    2023-09-09
  • SpringCloudGateway使用Skywalking時(shí)日志打印traceId解析

    SpringCloudGateway使用Skywalking時(shí)日志打印traceId解析

    這篇文章主要為大家介紹了SpringCloudGateway使用Skywalking時(shí)日志打印traceId解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Java編程中應(yīng)用的GUI設(shè)計(jì)基礎(chǔ)

    Java編程中應(yīng)用的GUI設(shè)計(jì)基礎(chǔ)

    這篇文章主要介紹了Java編程中應(yīng)用的GUI設(shè)計(jì)基礎(chǔ),為一些Java開(kāi)發(fā)CS類(lèi)型應(yīng)用的基礎(chǔ)概念知識(shí),需要的朋友可以參考下
    2015-10-10
  • review引發(fā)的有關(guān)于單例模式的思考

    review引發(fā)的有關(guān)于單例模式的思考

    一次代碼調(diào)試中發(fā)現(xiàn)一個(gè)情況,即我在查看memcached的connection時(shí),發(fā)現(xiàn)總是維持在100來(lái)個(gè)左右,當(dāng)然這看似沒(méi)什么問(wèn)題,因?yàn)閙emcached默認(rèn)connection有1024個(gè)。
    2013-04-04
  • Java常用數(shù)字工具類(lèi) 數(shù)字轉(zhuǎn)漢字(1)

    Java常用數(shù)字工具類(lèi) 數(shù)字轉(zhuǎn)漢字(1)

    這篇文章主要為大家詳細(xì)介紹了Java常用數(shù)字工具類(lèi),數(shù)字轉(zhuǎn)漢字,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 解決MyBatis中Enum字段參數(shù)解析問(wèn)題

    解決MyBatis中Enum字段參數(shù)解析問(wèn)題

    本文主要介紹了解決MyBatis中Enum字段參數(shù)解析問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • SpringMVC請(qǐng)求亂碼處理的2種方式

    SpringMVC請(qǐng)求亂碼處理的2種方式

    這篇文章主要介紹了SpringMVC請(qǐng)求亂碼處理的2種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評(píng)論