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

Spring?@Bean注解深入分析源碼執(zhí)行過程

 更新時(shí)間:2023年01月10日 09:27:26   作者:xuguofeng2016  
隨著SpringBoot的流行,我們現(xiàn)在更多采用基于注解式的配置從而替換掉了基于XML的配置,所以本篇文章我們主要探討基于注解的@Bean以及和其他注解的使用

本文將通過閱讀spring源碼,分析@Bean注解導(dǎo)入Bean的原理。

從AnnotationConfigApplicationContext對(duì)象的創(chuàng)建講起,因?yàn)樵趧?chuàng)建他的過程中,spring會(huì)先注入一系列的處理器,使用這些處理器解析@Configuration Class進(jìn)而將@Bean標(biāo)注的方法轉(zhuǎn)為BeanDefinition注入到容器。

其他的ApplicationContext實(shí)現(xiàn)在原理上也是一致的,只是入口不同而已。

AnnotationConfigApplicationContext創(chuàng)建

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
	this();
	register(componentClasses);
	refresh();
}

做了以下事情:

  • 創(chuàng)建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
  • 注冊(cè)Configuration Bean Class
  • refresh()加載、刷新容器:包含著@Configuration Class解析

創(chuàng)建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner

  • AnnotatedBeanDefinitionReader - 用于編程注冊(cè)Bean類的方便適配器,ClassPathBeanDefinitionScanner的替代方案,支持使用注解方式顯示的注冊(cè)Bean類。有幾個(gè)重載的registerBean方法,可以將給定的Bean類注冊(cè)到spring容器,注冊(cè)的是AnnotatedGenericBeanDefinition對(duì)象,他提供了獲取Bean類meta信息的方法。
  • ClassPathBeanDefinitionScanner - 從類路徑掃描組件并注冊(cè)到容器

在創(chuàng)建AnnotatedBeanDefinitionReader時(shí),會(huì)向容器注冊(cè)幾個(gè)注解驅(qū)動(dòng)處理器:

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

org.springframework.context.annotation.internalConfigurationAnnotationProcessor: ConfigurationClassPostProcessor

  • BeanFactoryPostProcessor實(shí)現(xiàn),用于解析@Configuration類。
  • 這個(gè)處理器是按優(yōu)先級(jí)排序的,因?yàn)樵贎Configuration類中聲明的任何Bean方法都必須在任何其他BeanFactoryPostProcessor執(zhí)行之前注冊(cè)其對(duì)應(yīng)的BeanDefinition。

org.springframework.context.annotation.internalAutowiredAnnotationProcessor: AutowiredAnnotationBeanPostProcessor

  • BeanPostProcessor implementation that autowires annotated fields, setter methods, and arbitrary config methods. Such members to be injected are detected through annotations: by default, Spring’s @Autowired and @Value annotations.
  • Also supports JSR-330’s @Inject annotation, if available, as a direct alternative to Spring’s own @Autowired.
  • @Autowired支持處理器。

org.springframework.context.annotation.internalCommonAnnotationProcessor: CommonAnnotationBeanPostProcessor

  • BeanPostProcessor implementation that supports common Java annotations out of the box.
  • 支持Resource、PostConstruct、PreDestroy等注解。

org.springframework.context.event.internalEventListenerProcessor: EventListenerMethodProcessor

org.springframework.context.event.internalEventListenerFactory: DefaultEventListenerFactory

ConfigurationClassPostProcessor中有支持@Bean注解的邏輯。

注冊(cè)Configuration Bean Class

register(componentClasses);

調(diào)用到AnnotatedBeanDefinitionReader的register方法:

this.reader.register(componentClasses);

AnnotatedBeanDefinitionReader類支持使用注解方式顯示的注冊(cè)Bean類。幾個(gè)重載的registerBean方法,可以將給定的Bean類注冊(cè)到spring容器,注冊(cè)的是AnnotatedGenericBeanDefinition對(duì)象,他提供了獲取Bean類meta信息的方法:

public void registerBean(Class<?> beanClass) {
	doRegisterBean(beanClass, null, null, null, null);
}
private <T> void doRegisterBean(Class<T> beanClass, String name,
		Class<? extends Annotation>[] qualifiers, Supplier<T> supplier,
		BeanDefinitionCustomizer[] customizers) {
    // 1. 創(chuàng)建AnnotatedGenericBeanDefinition對(duì)象,封裝StandardAnnotationMetadata用于獲取Bean的注解元信息
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    // skip判斷,暫時(shí)不做分析
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}
    // 2. scope、primary、lazy判斷,獲取beanName等
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			} else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			} else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}
    // 3. 封裝 BeanDefinitionHolder注冊(cè)到容器
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	definitionHolder = 
        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

創(chuàng)建AnnotatedGenericBeanDefinition需要稍微注意一下:

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// AnnotatedGenericBeanDefinition構(gòu)造方法
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
	setBeanClass(beanClass);
	this.metadata = AnnotationMetadata.introspect(beanClass);
}
// AnnotationMetadata.introspect方法
static AnnotationMetadata introspect(Class<?> type) {
	return StandardAnnotationMetadata.from(type);
}
// StandardAnnotationMetadata.from方法
static AnnotationMetadata from(Class<?> introspectedClass) {
	return new StandardAnnotationMetadata(introspectedClass, true);
}

以上的代碼片段分散在不同的類里面,最終AnnotatedGenericBeanDefinition對(duì)象會(huì)保存一個(gè)StandardAnnotationMetadata對(duì)象,用于獲取BeanMeta信息。

StandardAnnotationMetadata后文會(huì)有專門章節(jié)進(jìn)行介紹。

至此,spring只是將@Configuration Class作為一個(gè)AnnotatedBeanDefinition注冊(cè)到了容器中,@Configuration Class解析工作是在refresh時(shí)做的。

@Configuration Class解析

refresh方法

這段代碼在AbstractApplicationContext類中,此處只截取了與本文相關(guān)部分:

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);
		try {
			// Allows post-processing of the bean factory in context subclasses.
            // 只有web應(yīng)用的實(shí)現(xiàn)類重寫了這個(gè)方法,此處不展開分析
			postProcessBeanFactory(beanFactory);
			// Invoke factory processors registered as beans in the context.
            // 這里開始調(diào)用BeanFactory處理器
			invokeBeanFactoryPostProcessors(beanFactory);

invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate
        .invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法:

  • 先調(diào)用BeanDefinitionRegistryPostProcessor
  • 再調(diào)用BeanFactoryPostProcessor

調(diào)用BeanFactoryPostProcessor與本文分析的內(nèi)容關(guān)系不大,暫時(shí)不展開分析,重點(diǎn)看調(diào)用BeanDefinitionRegistryPostProcessor的邏輯。

入口在這里:

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

進(jìn)入到invokeBeanDefinitionRegistryPostProcessors方法:

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors,
        BeanDefinitionRegistry registry) {
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessBeanDefinitionRegistry(registry);
	}
}

此時(shí),就會(huì)調(diào)用到ConfigurationClassPostProcessor類的postProcessBeanDefinitionRegistry方法。

ConfigurationClassPostProcessor類

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	// 略
    // Derive further bean definitions from the configuration classes in the registry.
    // 從容器中已有的的@Configuration Class定義進(jìn)一步解析BeanDefinition
    // 此處不只會(huì)解析@Bean注解,其他的比如@Import、@ComponentScan等注解他也會(huì)解析
	processConfigBeanDefinitions(registry);
}

processConfigBeanDefinitions方法代碼比較多,此處只截取相關(guān)部分:

// 1. 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());
// 此處是一個(gè)do while循環(huán)
// 因?yàn)榻馕鲆槐橹?,容器里面可能?huì)有新的被注入的@Configuration Class定義,需要進(jìn)一步解析
// 比如@Import、@ComponentScan等注解就有可能注入新的@Configuration Class定義
do {
	parser.parse(candidates);
	parser.validate();
	Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
	configClasses.removeAll(alreadyParsed);
	// 2. Read the model and create bean definitions based on its content
	this.reader.loadBeanDefinitions(configClasses);
	// ...
} while (!candidates.isEmpty());
// ...

以上代碼做了兩件事:

  • Parse @Configuration class
  • 解析ConfigurationClass集注冊(cè)BeanDefinition

Parse @Configuration class

這個(gè)步驟是將容器里面的@Configuration Class Bean定義解析成ConfigurationClass集,ConfigurationClass封裝著@Configuration Class的元信息,包括:

  • AnnotationMetadata metadata - 注解元信息
  • beanName - bean名字
  • Set<BeanMethod> beanMethods - 這個(gè)就是這個(gè)配置類里面使用@Bean導(dǎo)出的Bean集合
  • 以及Import相關(guān)信息

入口在這里:

parser.parse(candidates);

parse方法:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			if (bd instanceof AnnotatedBeanDefinition) {
                // 進(jìn)入這個(gè)分支
				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());
			}
		}
	}
	this.deferredImportSelectorHandler.process();
}

之后進(jìn)入processConfigurationClass方法:

protected void processConfigurationClass(
    ConfigurationClass configClass, Predicate<String> filter) throws IOException {
    // skip判斷
	if (this.conditionEvaluator.shouldSkip(
        	configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}
	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			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.
    // 遞歸從本@Configuration Class將其父類解析ConfigurationClass
	SourceClass sourceClass = asSourceClass(configClass, filter);
	do {
		sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
	} while (sourceClass != null);

	this.configurationClasses.put(configClass, configClass);
}

doProcessConfigurationClass方法,該方法負(fù)責(zé)解析@Configuration Class,包括以下內(nèi)容:

  • 遞歸處理內(nèi)部類
  • 處理@PropertySource注解
  • 處理@ComponentScan注解
  • 處理@Import注解
  • 處理@ImportResource注解
  • 處理@Bean注解
  • 最后獲取以下當(dāng)前@Configuration Class的父類,如果有,則需要繼續(xù)解析該父類

此處只截取與@Bean解析相關(guān)的代碼片段:

// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
    // 封裝 BeanMethod添加到ConfigurationClass
	configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

retrieveBeanMethodMetadata方法:

// Retrieve the metadata for all @Bean methods
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
    // 獲取注解元數(shù)據(jù)
	AnnotationMetadata original = sourceClass.getMetadata();
    // 獲取被@Bean標(biāo)注的Method元數(shù)據(jù)集
	Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
	if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
		// Try reading the class file via ASM for deterministic declaration order...
		// Unfortunately, the JVM's standard reflection returns methods in arbitrary
		// order, even between different runs of the same application on the same JVM.
        // 此處會(huì)將無序的beanMethods集轉(zhuǎn)為有序的beanMethods集,
        // 因?yàn)镾tandardAnnotationMetadata使用的是反射方式獲取meta信息,
        // 這個(gè)不保證順序,所以需要將其轉(zhuǎn)為SimpleAnnotationMetadata類型,
        // 他內(nèi)部使用ClassVisitor通過讀取字節(jié)碼文件,按順序解析獲取meta信息。
        // 后續(xù)會(huì)有專門的章節(jié)介紹StandardAnnotationMetadata和SimpleAnnotationMetadata類
		try {
			AnnotationMetadata asm = this.metadataReaderFactory.getMetadataReader(
                original.getClassName()).getAnnotationMetadata();
			Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
			if (asmMethods.size() >= beanMethods.size()) {
				Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
				for (MethodMetadata asmMethod : asmMethods) {
					for (MethodMetadata beanMethod : beanMethods) {
						if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
							selectedMethods.add(beanMethod);
							break;
						}
					}
				}
				if (selectedMethods.size() == beanMethods.size()) {
					// All reflection-detected methods found in ASM method set -> proceed
					beanMethods = selectedMethods;
				}
			}
		} catch (IOException ex) {
			// No worries, let's continue with the reflection metadata we started with...
		}
	}
	return beanMethods;
}

到此,解析BeanMethod和MethodMetadata的流程就結(jié)束了,后續(xù)的邏輯就是封裝 BeanDefinition并將其注冊(cè)到容器。

解析ConfigurationClass集注冊(cè)BeanDefinition

將ConfigurationClass集進(jìn)一步解析,將導(dǎo)出、掃描出的組件封裝成BeanDefinition注冊(cè)到容器:

this.reader.loadBeanDefinitions(configClasses);

loadBeanDefinitionsForConfigurationClass方法:

// Read a particular ConfigurationClass,
// registering bean definitions for the class itself and all of its Bean methods.
private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    // skip判斷
	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;
	}
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
    // Read the given BeanMethod,
    // registering bean definitions with the BeanDefinitionRegistry based on its contents.
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}
    // Import相關(guān)
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

loadBeanDefinitionsForBeanMethod方法,讀取指定的BeanMethod對(duì)象,將其封裝成BeanDefinition注冊(cè)到容器:

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	ConfigurationClass configClass = beanMethod.getConfigurationClass();
	MethodMetadata metadata = beanMethod.getMetadata();
	String methodName = metadata.getMethodName();
	// Do we need to mark the bean as skipped by its condition?
	if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
		configClass.skippedBeanMethods.add(methodName);
		return;
	}
	if (configClass.skippedBeanMethods.contains(methodName)) {
		return;
	}
	AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
	Assert.state(bean != null, "No @Bean annotation attributes");
	// Consider name and any aliases
	List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
	String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
	// Register aliases even when overridden
	for (String alias : names) {
		this.registry.registerAlias(beanName, alias);
	}
	// Has this effectively been overridden before (e.g. via XML)?
	if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
		if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
			throw new BeanDefinitionStoreException("");
		}
		return;
	}
	ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(
        configClass, metadata, beanName);
	beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
	if (metadata.isStatic()) {
		// static @Bean method
		if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
			beanDef.setBeanClass(
                ((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
		} else {
			beanDef.setBeanClassName(configClass.getMetadata().getClassName());
		}
		beanDef.setUniqueFactoryMethodName(methodName);
	} else {
		// instance @Bean method
		beanDef.setFactoryBeanName(configClass.getBeanName());
		beanDef.setUniqueFactoryMethodName(methodName);
	}
	if (metadata instanceof StandardMethodMetadata) {
		beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
	}
	beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
	beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
			SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
	AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
	Autowire autowire = bean.getEnum("autowire");
	if (autowire.isAutowire()) {
		beanDef.setAutowireMode(autowire.value());
	}
	boolean autowireCandidate = bean.getBoolean("autowireCandidate");
	if (!autowireCandidate) {
		beanDef.setAutowireCandidate(false);
	}
	String initMethodName = bean.getString("initMethod");
	if (StringUtils.hasText(initMethodName)) {
		beanDef.setInitMethodName(initMethodName);
	}
	String destroyMethodName = bean.getString("destroyMethod");
	beanDef.setDestroyMethodName(destroyMethodName);
	// Consider scoping
	ScopedProxyMode proxyMode = ScopedProxyMode.NO;
	AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
	if (attributes != null) {
		beanDef.setScope(attributes.getString("value"));
		proxyMode = attributes.getEnum("proxyMode");
		if (proxyMode == ScopedProxyMode.DEFAULT) {
			proxyMode = ScopedProxyMode.NO;
		}
	}
	// Replace the original bean definition with the target one, if necessary
	BeanDefinition beanDefToRegister = beanDef;
	if (proxyMode != ScopedProxyMode.NO) {
		BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
				new BeanDefinitionHolder(beanDef, beanName), this.registry,
				proxyMode == ScopedProxyMode.TARGET_CLASS);
		beanDefToRegister = new ConfigurationClassBeanDefinition(
				(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
	}
	this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

至此,@Bean注解的核心原理就分析完成了。后續(xù)將簡單介紹一下AnnotationMetadata和MethodMetadata這兩個(gè)接口。

AnnotationMetadata接口

Interface that defines abstract access to the annotations of a specific class, in a form that does not require that class to be loaded yet.

用于獲取類的注解元數(shù)據(jù)。

他繼承了ClassMetadata接口,所以也可以獲取類的相關(guān)信息:比如類名、實(shí)現(xiàn)的接口、繼承的父類等信息。另外,他還支持獲取類的MethodMetadata集,即把類的所有方法解析之后封裝成MethodMetadata集。

實(shí)現(xiàn)類:

  • StandardAnnotationMetadata - Uses standard reflection to introspect a given Class.
  • SimpleAnnotationMetadata - ASM based.

StandardAnnotationMetadata類

這個(gè)類使用反射方式獲取類的注解元數(shù)據(jù)。

我們?cè)谏衔慕榻B創(chuàng)建AnnotatedGenericBeanDefinition的過程中,看到過這個(gè)類對(duì)象的創(chuàng)建方式:

// AnnotationMetadata.introspect方法
static AnnotationMetadata introspect(Class<?> type) {
	return StandardAnnotationMetadata.from(type);
}
// StandardAnnotationMetadata.from方法
static AnnotationMetadata from(Class<?> introspectedClass) {
	return new StandardAnnotationMetadata(introspectedClass, true);
}

實(shí)際上只是把類封裝到里面,實(shí)現(xiàn)方法里面使用反射獲取對(duì)應(yīng)元數(shù)據(jù)。

SimpleAnnotationMetadata類

StandardAnnotationMetadata類獲取出來的元數(shù)據(jù)不保證順序,在需要順序的場景下不適用。

在Parse @Configuration class流程中有一個(gè)步驟是調(diào)用retrieveBeanMethodMetadata方法獲取所有@Bean標(biāo)注的方法并封裝MethodMetadata集,其中有一步就是使用SimpleAnnotationMetadataReadingVisitor讀取字節(jié)碼文件,讀取過程中將類的元數(shù)據(jù)封裝到SimpleAnnotationMetadata對(duì)象,從而確保了順序。

代碼片段之前記錄過,此處再介紹一下:

// Retrieve the metadata for all @Bean methods
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
    // 獲取注解元數(shù)據(jù)
	AnnotationMetadata original = sourceClass.getMetadata();
    // 獲取被@Bean標(biāo)注的Method元數(shù)據(jù)集
	Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
	if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
		// Try reading the class file via ASM for deterministic declaration order...
		// Unfortunately, the JVM's standard reflection returns methods in arbitrary
		// order, even between different runs of the same application on the same JVM.
        // 此處會(huì)將無序的beanMethods集轉(zhuǎn)為有序的beanMethods集,
        // 因?yàn)镾tandardAnnotationMetadata使用的是反射方式獲取meta信息,
        // 這個(gè)不保證順序,所以需要將其轉(zhuǎn)為SimpleAnnotationMetadata類型,
        // 他內(nèi)部使用ClassVisitor通過讀取字節(jié)碼文件,按順序解析獲取meta信息。
        // 后續(xù)會(huì)有專門的章節(jié)介紹StandardAnnotationMetadata和SimpleAnnotationMetadata類
		try {
            // 這里getMetadataReader得到的是一個(gè)SimpleMetadataReader對(duì)象
			AnnotationMetadata asm = this.metadataReaderFactory.getMetadataReader(
                original.getClassName()).getAnnotationMetadata();
			Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
			if (asmMethods.size() >= beanMethods.size()) {
				Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
				for (MethodMetadata asmMethod : asmMethods) {
					for (MethodMetadata beanMethod : beanMethods) {
						if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
							selectedMethods.add(beanMethod);
							break;
						}
					}
				}
				if (selectedMethods.size() == beanMethods.size()) {
					// All reflection-detected methods found in ASM method set -> proceed
					beanMethods = selectedMethods;
				}
			}
		} catch (IOException ex) {
			// No worries, let's continue with the reflection metadata we started with...
		}
	}
	return beanMethods;
}

SimpleMetadataReader類

SimpleMetadataReader(Resource resource, ClassLoader classLoader) throws IOException {
	SimpleAnnotationMetadataReadingVisitor visitor = 
        new SimpleAnnotationMetadataReadingVisitor(classLoader);
    // 這里使用SimpleAnnotationMetadataReadingVisitor讀取字節(jié)碼文件,封裝元數(shù)據(jù)
	getClassReader(resource).accept(visitor, PARSING_OPTIONS);
	this.resource = resource;
	this.annotationMetadata = visitor.getMetadata();
}
// 讀取字節(jié)碼文件完成之后,封裝SimpleAnnotationMetadata對(duì)象
public void visitEnd() {
	String[] memberClassNames = StringUtils.toStringArray(this.memberClassNames);
	MethodMetadata[] annotatedMethods = this.annotatedMethods.toArray(new MethodMetadata[0]);
	MergedAnnotations annotations = MergedAnnotations.of(this.annotations);
	this.metadata = new SimpleAnnotationMetadata(this.className, this.access,
			this.enclosingClassName, this.superClassName, this.independentInnerClass,
			this.interfaceNames, memberClassNames, annotatedMethods, annotations);
}

MethodMetadata接口

封裝方法的元數(shù)據(jù)。

實(shí)現(xiàn)類:

  • StandardMethodMetadata - MethodMetadata implementation that uses standard reflection to introspect a given Method.
  • SimpleMethodMetadata - ASM based.

StandardMethodMetadata

使用反射方式獲取方法元數(shù)據(jù)。

SimpleMethodMetadata

基于SimpleAnnotationMetadataReadingVisitor讀取的字節(jié)碼數(shù)據(jù),封裝方法元數(shù)據(jù)。

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

相關(guān)文章

  • 完美解決Java獲取文件路徑出現(xiàn)亂碼的問題

    完美解決Java獲取文件路徑出現(xiàn)亂碼的問題

    今天小編就為大家分享一篇完美解決Java獲取文件路徑出現(xiàn)亂碼的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Java中的TreeSet集合解析

    Java中的TreeSet集合解析

    這篇文章主要介紹了Java中的TreeSet集合解析,  TreeSet是一個(gè)有序的集合,基于TreeMap實(shí)現(xiàn),支持兩種排序方式:自然排序和定制排序,
    TreeSet是非同步的,線程不安全的,需要的朋友可以參考下
    2023-09-09
  • Spring中@RestControllerAdvice注解的使用詳解

    Spring中@RestControllerAdvice注解的使用詳解

    這篇文章主要介紹了Spring中@RestControllerAdvice注解的使用詳解,@RestControllerAdvice是一個(gè)組合注解,由@ControllerAdvice、@ResponseBody組成,而@ControllerAdvice繼承了@Component,需要的朋友可以參考下
    2024-01-01
  • JPA-JpaRepository方法命名語法說明

    JPA-JpaRepository方法命名語法說明

    這篇文章主要介紹了JPA-JpaRepository方法命名語法說明,具有很好的參考價(jià)值。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • BufferedWriter如何使用write方法實(shí)現(xiàn)換行

    BufferedWriter如何使用write方法實(shí)現(xiàn)換行

    這篇文章主要介紹了BufferedWriter如何使用write方法實(shí)現(xiàn)換行的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 基于springboot redirect重定向路徑問題總結(jié)

    基于springboot redirect重定向路徑問題總結(jié)

    這篇文章主要介紹了springboot redirect重定向路徑問題總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot使用Jwt處理跨域認(rèn)證問題的教程詳解

    SpringBoot使用Jwt處理跨域認(rèn)證問題的教程詳解

    這篇文章主要介紹了SpringBoot使用Jwt處理跨域認(rèn)證問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java設(shè)計(jì)模式之策略模式詳細(xì)解析

    Java設(shè)計(jì)模式之策略模式詳細(xì)解析

    這篇文章主要介紹了Java設(shè)計(jì)模式之策略模式詳細(xì)解析,策略模式中,定義算法族,分別封裝起來,讓他們之間可以相互轉(zhuǎn)化,此模式讓算法的變化獨(dú)立于使用算法的客戶,需要的朋友可以參考下
    2023-11-11
  • 使用springboot aop來實(shí)現(xiàn)讀寫分離和事物配置

    使用springboot aop來實(shí)現(xiàn)讀寫分離和事物配置

    這篇文章主要介紹了使用springboot aop來實(shí)現(xiàn)讀寫分離和事物配置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • Spring?AOP實(shí)現(xiàn)用戶登錄統(tǒng)一驗(yàn)證功能

    Spring?AOP實(shí)現(xiàn)用戶登錄統(tǒng)一驗(yàn)證功能

    這篇文章主要為大家詳細(xì)介紹了Spring?AOP如何實(shí)現(xiàn)用戶登錄統(tǒng)一驗(yàn)證功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)具有一定的借鑒價(jià)值,需要的可以參考一下
    2023-01-01

最新評(píng)論