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

Spring配置類源碼分析詳解

 更新時(shí)間:2022年09月08日 15:36:07   作者:天黑請(qǐng)閉眼丶風(fēng)  
這篇文章主要介紹了Spring配置類解析源碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

spring配置類解析源碼解析

上一篇分析spring的啟動(dòng)過程中,會(huì)把BeanDefinitionRegistryPostProcessor接口類型的子類添加到啟動(dòng)的過程中,其中它的一個(gè)子類ConfigurationClassPostProcessor是用來處理配置類。下面來分析spring如何處理配置類。

那么首先要知道什么是配置類?先簡單來說常見的配置類就是添加了@Configuration、@ComponentScan等注解的類。后續(xù)分析源碼的過程中在詳細(xì)介紹。

配置類解析源碼分析

上一篇分析過spring啟動(dòng)的過程會(huì)添加一些類用于后續(xù)bean的生命周期使用,啟動(dòng)過程中會(huì)執(zhí)行ConfigurationClassPostProcessorprocessConfigBeanDefinitions方法。展示部分重要的代碼

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//拿到啟動(dòng)過程中注入的類的名稱
		String[] candidateNames = registry.getBeanDefinitionNames();
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			//判斷是不是配置類
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}
		// Sort by previously determined @Order value, if applicable
		// 通過@Order可以排序,升序排序,order越下越靠前
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});
		// Parse each @Configuration class
		//構(gòu)建一個(gè)配置類的解析器
		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());
		// 遞歸解析配置類,有可能通過解析一個(gè)配置類,得到了其他的配置類,比如掃描和Import
		do {
			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
			//配置類解析
			parser.parse(candidates);
			parser.validate();
			// 從解析器parse得到配置類,移除已經(jīng)解析過的,剩下的就是新增的
			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());
			}
			// 把parser.parse(candidates);解析到的但是未生成BeanDefinition的配置 生成對(duì)應(yīng)的BeanDefinition
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
			processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
			// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClass
			candidates.clear();
			//loadBeanDefinitions方法會(huì)增加很多BeanDefinition 如果發(fā)現(xiàn)BeanDefinition增加了,則有可能增加了配置類
			//這個(gè)if對(duì)新增的BeanDefinition做處理
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				//遍歷新增的BeanDefinition
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						//判斷新增的BeanDefinition是不是一個(gè)配置類
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							//如果是配置類 添加到這個(gè)集合當(dāng)中 交給do while 循環(huán)解析配置類
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());
	}

整個(gè)流程就是 判斷哪些類是配置類,根據(jù)@order注解排序,構(gòu)建一個(gè)配置類的解析器,利用do while 解析配置類。先來看看spring是如何判斷哪些類是配置類的。

判斷配置類

判斷配置類的方法是ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)

public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
		String className = beanDef.getBeanClassName();
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}
		// AnnotationMetadata表示某個(gè)類的注解信息,但是并一定要加載這個(gè)類
		AnnotationMetadata metadata;
		// 如果AnnotatedBeanDefinition,則直接取AnnotationMetadata
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		// 如果是AbstractBeanDefinition,則解析beanClass得到AnnotationMetadata
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
					EventListenerFactory.class.isAssignableFrom(beanClass)) {
				return false;
			}
			metadata = AnnotationMetadata.introspect(beanClass);
		}
		else {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " +
							className, ex);
				}
				return false;
			}
		}
		//如果該類有@Configuration注解 表示是一個(gè)配置類
		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		// 存在@Configuration,并且proxyBeanMethods不為false(為true或?yàn)閚ull)時(shí),就是Full配置類
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		// 存在@Configuration,并且proxyBeanMethods為false時(shí),是lite配置類
		// 或者不存在@Configuration,但是只要存在@Component、@ComponentScan、@Import、@ImportResource四個(gè)中的一個(gè),就是lite配置類
		// 或者不存在@Configuration,只要存在@Bean注解了的方法,就是lite配置類
		else if (config != null || isConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}
		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		Integer order = getOrder(metadata);
		if (order != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}
		return true;
	}

首先就是拿到這個(gè)類的BeanDefinition的注解,根據(jù)注解判斷有沒有@Configuration,如果有該注解并且其屬性proxyBeanMethods=ture,默認(rèn)也是true,那么就是full配置類,如果為fasle那么就是lite配置類。這兩種配置類跟代理有關(guān)可以先不用管。同時(shí)還有個(gè)或的判斷isConfigurationCandidate(metadata),如果滿足這個(gè)條件那么也是lite配置類。

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
		//如果是一個(gè)接口類型,那么直接返回false 就不是一個(gè)配置類
		if (metadata.isInterface()) {
			return false;
		}
		// 只要存在@Component、@ComponentScan、@Import、@ImportResource四個(gè)中的一個(gè),就是lite配置類
		for (String indicator : candidateIndicators) {
			if (metadata.isAnnotated(indicator)) {
				return true;
			}
		}
		// 只要存在@Bean注解了的方法,就是lite配置類
		return hasBeanMethods(metadata);
	}
static {
		candidateIndicators.add(Component.class.getName());
		candidateIndicators.add(ComponentScan.class.getName());
		candidateIndicators.add(Import.class.getName());
		candidateIndicators.add(ImportResource.class.getName());
	}

其中candidateIndicators是一個(gè)集合,包含了@Component、@ComponentScan、@Import、@ImportResource這幾個(gè)注解。

因此根據(jù)上述代碼可以知道什么是配置類

類上有@Component、@ComponentScan、@Import、@ImportResource、@Configuration任意一個(gè)注解的類,或者包含有@bean注解的類都是配置類。

解析配置類

拿到了配置類,排序后,構(gòu)建一個(gè)配置類的解析器就開始解析。開頭講的do while 就是用來解析配置類的。核心代碼在于parser.parse(candidates);,這個(gè)方法中核心處理在于processConfigurationClass這個(gè)方法。

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		// 條件注解判斷
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				// OrderService導(dǎo)入了AccountService,UserService也導(dǎo)入了AccountService,就會(huì)符合這個(gè)條件
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}
		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass, filter);
		//循環(huán) 解析了該類后 解析父類
		do {
			//核心方法 真正解析類 --> 解析類上的各種配置注解并做出對(duì)應(yīng)處理
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);
		// ConfigurationClass重寫了equals方法,只要兩個(gè)ConfigurationClass對(duì)應(yīng)的className相等就可以
		this.configurationClasses.put(configClass, configClass);
	}

其中核心代碼在于doProcessConfigurationClass(configClass, sourceClass, filter)開始解析配置類,這里也有個(gè)do while ,這個(gè)do while 就是循環(huán)解決配置類的父類,如果配置類存在父類,那么就會(huì)執(zhí)行解析的邏輯,如果沒有就會(huì)推出循環(huán)。那么接著看如何解析配置類。

	protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
		//對(duì)@Component注解做處理
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// 處理內(nèi)部類
			processMemberClasses(configClass, sourceClass, filter);
		}
		//對(duì)@PropertySource注解做處理
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}
		//對(duì)@ComponentScan注解做處理
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				// 底層調(diào)用doScan 進(jìn)行掃描所有的bean得到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
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					// 檢查掃描出來的BeanDefinition是不是配置類(full和lite)
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						//如果是配置類遞歸執(zhí)行 解析配置類的方法
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		// getImports(sourceClass)會(huì)拿到所有導(dǎo)入的類
		//對(duì)@Import注解做處理
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
		//對(duì)@ImportResource注解做處理 @ImportResource導(dǎo)入一個(gè)xml作為配置文件 這里暫時(shí)沒有解析xml文件
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}
		// Process individual @Bean methods
		// 解析配置類中的@Bean,但并沒有真正處理@Bean,只是暫時(shí)找出來
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}
		// Process default methods on interfaces
		// 解析配置類所實(shí)現(xiàn)的接口中的@Bean,但并沒有真正處理@Bean,只是暫時(shí)找出來
		processInterfaces(configClass, sourceClass);
		// Process superclass, if any
		//如果有父類就返回父類
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}
		//如果沒有父類 那么這個(gè)類就解析完了
		return null;
	}

大致流程就是解析配置類上的注解,根據(jù)得到的注解,做出不同的處理。如何處理通過下面的流程圖來分析。doProcessConfigurationClass方法流程圖:

需要注意的是除了@ComponentScan的處理會(huì)把掃描到的類注冊(cè)成BeanDefinition以外,其他的處理都是記錄到相關(guān)屬性,后續(xù)在把這些類拿出來做處理。

那么到此parser.parse(candidates);方法就執(zhí)行完成。

配置類的處理

解析完配置類后,會(huì)得到很多新的配置類,或者bean對(duì)象。通過this.reader.loadBeanDefinitions(configClasses);方法創(chuàng)建這些新的類的BeanDefinition。該方法的底層核心方法是loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);

private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}
		//將Importe和@component的內(nèi)部類 生成BeanDefinition
		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		//解析所有的@bean 生成對(duì)應(yīng)的BeanDefinition
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
		//解析導(dǎo)入進(jìn)來的xml文件 生成bean對(duì)應(yīng)的BeanDefinition
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		//執(zhí)行實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口的方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

doProcessConfigurationClass(configClass, sourceClass, filter)方法會(huì)把根據(jù)配置類上的注解做處理,比如吧Importe導(dǎo)入的類和@component的內(nèi)部類,收集起來,所有@bean需要?jiǎng)?chuàng)建的bean封裝成BeanMethod對(duì)象收集起來,ImportedResources導(dǎo)入的xml文件等都沒有處理。那么loadBeanDefinitionsForConfigurationClass這個(gè)方法就是處理這些類的,把這類的對(duì)應(yīng)的BeanDefinition創(chuàng)建出來。

由于創(chuàng)建出很多BeanDefinition,那么還需要判斷哪些BeanDefinition是配置類。如果是配置加入到集合當(dāng)中。通過開頭講的do while去處理這個(gè)集合。

總結(jié)

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

一:在啟動(dòng)Spring時(shí),需要傳入一個(gè)配置類,例如上面?zhèn)魅階ppConfig.class。ApplicationContext會(huì)根據(jù)AppConfig類封裝為一個(gè)BeanDefinition,這種BeanDefinition我們把它稱為配置類BeanDefinition。

二:ConfigurationClassPostProcessor中會(huì)把配置類BeanDefinition取出來

三:構(gòu)造一個(gè)ConfigurationClassParser用來解析配置類BeanDefinition,并且會(huì)生成一個(gè)配置類對(duì)象ConfigurationClass

四:如果配置類上存在@Component注解,那么解析配置類中的內(nèi)部類(這里有遞歸,如果內(nèi)部類也是配置類的話)

五:如果配置類上存在@PropertySource注解,那么則解析該注解,并得到PropertySource對(duì)象,并添加到environment中去

六:如果配置類上存在@ComponentScan注解,那么則解析該注解,進(jìn)行掃描,掃描得到一系列的BeanDefinition對(duì)象,然后判斷這些BeanDefinition是不是也是配置類BeanDefinition(只要存在@Component注解就是配置類,所以基本上掃描出來的都是配置類),如果是則繼續(xù)解析該配置類,(也有遞歸),并且會(huì)生成對(duì)應(yīng)的ConfigurationClass

七:如果配置類上存在@Import注解,那么則判斷Import的類的類型:

如果是ImportSelector,那么調(diào)用執(zhí)行selectImports方法得到類名,然后在把這個(gè)類當(dāng)做配置類進(jìn)行解析 也是遞歸如果是ImportBeanDefinitionRegistrar,那么則生成一個(gè)ImportBeanDefinitionRegistrar實(shí)例對(duì)象,并添加到配置類對(duì)象中(ConfigurationClass)的importBeanDefinitionRegistrars屬性中。

八:如果配置類上存在@ImportResource注解,那么則把導(dǎo)入進(jìn)來的資源路徑存在配置類對(duì)象中的importedResources屬性中

九:如果配置類中存在@Bean的方法,那么則把這些方法封裝為BeanMethod對(duì)象,并添加到配置類對(duì)象中的beanMethods屬性中

十:如果配置類實(shí)現(xiàn)了某些接口,則看這些接口內(nèi)是否定義了@Bean的默認(rèn)方法

十一:如果配置類有父類,則把父類當(dāng)做配置類進(jìn)行解析

十二:AppConfig這個(gè)配置類會(huì)對(duì)應(yīng)一個(gè)ConfigurationClass,同時(shí)在解析的過程中也會(huì)生成另外的一些ConfigurationClass,接下來就利用reader來進(jìn)一步解析ConfigurationClass

  • 如果ConfigurationClass是通過@Import注解導(dǎo)入進(jìn)來的,則把這個(gè)類生成一個(gè)BeanDefinition,同時(shí)解析這個(gè)類上@Scope,@Lazy等注解信息,并注冊(cè)BeanDefinition
  • 如果ConfigurationClass中存在一些BeanMethod,也就是定義了一些@Bean,那么則解析這些@Bean,并生成對(duì)應(yīng)的BeanDefinition,并注冊(cè)
  • 如果ConfigurationClass中導(dǎo)入了一些資源文件,比如xx.xml,那么則解析這些xx.xml文件,得到并注冊(cè)BeanDefinition
  • 如果ConfigurationClass中導(dǎo)入了一些ImportBeanDefinitionRegistrar,那么則執(zhí)行對(duì)應(yīng)的registerBeanDefinitions進(jìn)行BeanDefinition的注冊(cè)

擴(kuò)展點(diǎn)

通過spring對(duì)配置類處理,可以了解一些知識(shí)點(diǎn),

  • @Import 可以導(dǎo)入一些類,并且這些以配置類的形式注冊(cè)到spring容器中(當(dāng)然也會(huì)生成Bean對(duì)象)導(dǎo)入的類還可以實(shí)現(xiàn)ImportSelector或ImportBeanDefinitionRegistrar這兩個(gè)接口做出額外的擴(kuò)展
  • @ImportResource 導(dǎo)入xxx.xml配置文件
  • @PropertySource 導(dǎo)入xxx.properties文件到環(huán)境變量中

Import使用demo

//定義一個(gè)類
public class Aaaa {
	public void test(){
		System.out.println("-----------Aaaa----------");
	}
}
//定義一個(gè)Import類
public class ImportDemo {
	@Bean
	public Aaaa aaaa(){
		return new Aaaa();
	}
}

測(cè)試代碼

@ComponentScan(basePackages = {"service","config","aop"})
@Configuration
@Import(ImportDemo.class)
public class AppConfig {
}
public class Test {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		Aaaa aaaa = (Aaaa)context.getBean("aaaa");
		aaaa.test();
	}
}

這樣可以把Aaaa這個(gè)類放入到spring容器中。 通過這種形式可以控制那些bean在那些條件下才導(dǎo)入到spring中 例如在某個(gè)注解上加上@Import(ImportDemo.class)。這樣只有使用了該注解后才會(huì)導(dǎo)入這個(gè)bean。

到此這篇關(guān)于Spring配置類源碼分析詳解的文章就介紹到這了,更多相關(guān)Spring配置類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決SpringBoot項(xiàng)目讀取yml文件中值為中文時(shí),在視圖頁面顯示亂碼

    解決SpringBoot項(xiàng)目讀取yml文件中值為中文時(shí),在視圖頁面顯示亂碼

    這篇文章主要介紹了解決SpringBoot項(xiàng)目讀取yml文件中值為中文時(shí),在視圖頁面顯示亂碼的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Java本地緩存工具之LoadingCache的使用詳解

    Java本地緩存工具之LoadingCache的使用詳解

    緩存,在我們?nèi)粘i_發(fā)中是必不可少的一種解決性能問題的方法。簡單的說,cache?就是為了提升系統(tǒng)性能而開辟的一塊內(nèi)存空間。本文將為大家介紹一個(gè)Java本地緩存的工具——LoadingCache,感興趣的可以了解一下
    2021-12-12
  • Java、C++中子類對(duì)父類函數(shù)覆蓋的可訪問性縮小的區(qū)別介紹

    Java、C++中子類對(duì)父類函數(shù)覆蓋的可訪問性縮小的區(qū)別介紹

    這篇文章主要給大家介紹了關(guān)于Java、C++中子類對(duì)父類函數(shù)覆蓋的可訪問性縮小的區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • Java While循環(huán) do-while循環(huán)用法

    Java While循環(huán) do-while循環(huán)用法

    循環(huán)語句就是讓計(jì)算機(jī)根據(jù)條件做循環(huán)計(jì)算,在條件滿足時(shí)繼續(xù)循環(huán),條件不滿足時(shí)退出循環(huán),需要的朋友可以參考下
    2020-11-11
  • Springboot接口項(xiàng)目如何使用AOP記錄日志

    Springboot接口項(xiàng)目如何使用AOP記錄日志

    這篇文章主要介紹了Springboot接口項(xiàng)目如何使用AOP記錄日志,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 使用自定義注解實(shí)現(xiàn)加解密及脫敏方式

    使用自定義注解實(shí)現(xiàn)加解密及脫敏方式

    這篇文章主要介紹了使用自定義注解實(shí)現(xiàn)加解密及脫敏方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • JAVA WEB中Servlet和Servlet容器的區(qū)別

    JAVA WEB中Servlet和Servlet容器的區(qū)別

    這篇文章主要介紹了JAVA WEB中Servlet和Servlet容器的區(qū)別,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • SpringBoot使用Mybatis注解實(shí)現(xiàn)分頁動(dòng)態(tài)sql開發(fā)教程

    SpringBoot使用Mybatis注解實(shí)現(xiàn)分頁動(dòng)態(tài)sql開發(fā)教程

    這篇文章主要為大家介紹了SpringBoot使用Mybatis注解實(shí)現(xiàn)分頁及動(dòng)態(tài)sql開發(fā)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • SpringBoot啟動(dòng)器Starters使用及原理解析

    SpringBoot啟動(dòng)器Starters使用及原理解析

    這篇文章主要介紹了SpringBoot啟動(dòng)器Starters使用及原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Java線程中斷interrupt的常用方法

    Java線程中斷interrupt的常用方法

    本文主要介紹了Java線程中斷interrupt的常用方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評(píng)論