我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Spring@Bean注解深入分析源码执行过程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Spring@Bean注解深入分析源码执行过程

本文将通过阅读spring源码,分析@Bean注解导入Bean的原理。

从AnnotationConfigApplicationContext对象的创建讲起,因为在创建他的过程中,spring会先注入一系列的处理器,使用这些处理器解析@Configuration Class进而将@Bean标注的方法转为BeanDefinition注入到容器。

其他的ApplicationContext实现在原理上也是一致的,只是入口不同而已。

AnnotationConfigApplicationContext创建

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

做了以下事情:

  • 创建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
  • 注册Configuration Bean Class
  • refresh()加载、刷新容器:包含着@Configuration Class解析

创建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner

  • AnnotatedBeanDefinitionReader - 用于编程注册Bean类的方便适配器,ClassPathBeanDefinitionScanner的替代方案,支持使用注解方式显示的注册Bean类。有几个重载的registerBean方法,可以将给定的Bean类注册到spring容器,注册的是AnnotatedGenericBeanDefinition对象,他提供了获取Bean类meta信息的方法。
  • ClassPathBeanDefinitionScanner - 从类路径扫描组件并注册到容器

在创建AnnotatedBeanDefinitionReader时,会向容器注册几个注解驱动处理器:

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

org.springframework.context.annotation.internalConfigurationAnnotationProcessor: ConfigurationClassPostProcessor

  • BeanFactoryPostProcessor实现,用于解析@Configuration类。
  • 这个处理器是按优先级排序的,因为在@Configuration类中声明的任何Bean方法都必须在任何其他BeanFactoryPostProcessor执行之前注册其对应的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注解的逻辑。

注册Configuration Bean Class

register(componentClasses);

调用到AnnotatedBeanDefinitionReader的register方法:

this.reader.register(componentClasses);

AnnotatedBeanDefinitionReader类支持使用注解方式显示的注册Bean类。几个重载的registerBean方法,可以将给定的Bean类注册到spring容器,注册的是AnnotatedGenericBeanDefinition对象,他提供了获取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. 创建AnnotatedGenericBeanDefinition对象,封装StandardAnnotationMetadata用于获取Bean的注解元信息
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    // skip判断,暂时不做分析
	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注册到容器
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	definitionHolder = 
        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

创建AnnotatedGenericBeanDefinition需要稍微注意一下:

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// AnnotatedGenericBeanDefinition构造方法
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对象会保存一个StandardAnnotationMetadata对象,用于获取BeanMeta信息。

StandardAnnotationMetadata后文会有专门章节进行介绍。

至此,spring只是将@Configuration Class作为一个AnnotatedBeanDefinition注册到了容器中,@Configuration Class解析工作是在refresh时做的。

@Configuration Class解析

refresh方法

这段代码在AbstractApplicationContext类中,此处只截取了与本文相关部分:

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应用的实现类重写了这个方法,此处不展开分析
			postProcessBeanFactory(beanFactory);
			// Invoke factory processors registered as beans in the context.
            // 这里开始调用BeanFactory处理器
			invokeBeanFactoryPostProcessors(beanFactory);

invokeBeanFactoryPostProcessors

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

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法:

  • 先调用BeanDefinitionRegistryPostProcessor
  • 再调用BeanFactoryPostProcessor

调用BeanFactoryPostProcessor与本文分析的内容关系不大,暂时不展开分析,重点看调用BeanDefinitionRegistryPostProcessor的逻辑。

入口在这里:

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

进入到invokeBeanDefinitionRegistryPostProcessors方法:

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

此时,就会调用到ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法。

ConfigurationClassPostProcessor类

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	// 略
    // Derive further bean definitions from the configuration classes in the registry.
    // 从容器中已有的的@Configuration Class定义进一步解析BeanDefinition
    // 此处不只会解析@Bean注解,其他的比如@Import、@ComponentScan等注解他也会解析
	processConfigBeanDefinitions(registry);
}

processConfigBeanDefinitions方法代码比较多,此处只截取相关部分:

// 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());
// 此处是一个do while循环
// 因为解析一遍之后,容器里面可能会有新的被注入的@Configuration Class定义,需要进一步解析
// 比如@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集注册BeanDefinition

Parse @Configuration class

这个步骤是将容器里面的@Configuration Class Bean定义解析成ConfigurationClass集,ConfigurationClass封装着@Configuration Class的元信息,包括:

  • AnnotationMetadata metadata - 注解元信息
  • beanName - bean名字
  • Set<BeanMethod> beanMethods - 这个就是这个配置类里面使用@Bean导出的Bean集合
  • 以及Import相关信息

入口在这里:

parser.parse(candidates);

parse方法:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			if (bd instanceof AnnotatedBeanDefinition) {
                // 进入这个分支
				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();
}

之后进入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方法,该方法负责解析@Configuration Class,包括以下内容:

  • 递归处理内部类
  • 处理@PropertySource注解
  • 处理@ComponentScan注解
  • 处理@Import注解
  • 处理@ImportResource注解
  • 处理@Bean注解
  • 最后获取以下当前@Configuration Class的父类,如果有,则需要继续解析该父类

此处只截取与@Bean解析相关的代码片段:

// 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) {
    // 获取注解元数据
	AnnotationMetadata original = sourceClass.getMetadata();
    // 获取被@Bean标注的Method元数据集
	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.
        // 此处会将无序的beanMethods集转为有序的beanMethods集,
        // 因为StandardAnnotationMetadata使用的是反射方式获取meta信息,
        // 这个不保证顺序,所以需要将其转为SimpleAnnotationMetadata类型,
        // 他内部使用ClassVisitor通过读取字节码文件,按顺序解析获取meta信息。
        // 后续会有专门的章节介绍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的流程就结束了,后续的逻辑就是封装 BeanDefinition并将其注册到容器。

解析ConfigurationClass集注册BeanDefinition

将ConfigurationClass集进一步解析,将导出、扫描出的组件封装成BeanDefinition注册到容器:

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相关
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

loadBeanDefinitionsForBeanMethod方法,读取指定的BeanMethod对象,将其封装成BeanDefinition注册到容器:

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注解的核心原理就分析完成了。后续将简单介绍一下AnnotationMetadata和MethodMetadata这两个接口。

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.

用于获取类的注解元数据。

他继承了ClassMetadata接口,所以也可以获取类的相关信息:比如类名、实现的接口、继承的父类等信息。另外,他还支持获取类的MethodMetadata集,即把类的所有方法解析之后封装成MethodMetadata集。

实现类:

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

StandardAnnotationMetadata类

这个类使用反射方式获取类的注解元数据。

我们在上文介绍创建AnnotatedGenericBeanDefinition的过程中,看到过这个类对象的创建方式:

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

实际上只是把类封装到里面,实现方法里面使用反射获取对应元数据。

SimpleAnnotationMetadata类

StandardAnnotationMetadata类获取出来的元数据不保证顺序,在需要顺序的场景下不适用。

在Parse @Configuration class流程中有一个步骤是调用retrieveBeanMethodMetadata方法获取所有@Bean标注的方法并封装MethodMetadata集,其中有一步就是使用SimpleAnnotationMetadataReadingVisitor读取字节码文件,读取过程中将类的元数据封装到SimpleAnnotationMetadata对象,从而确保了顺序。

代码片段之前记录过,此处再介绍一下:

// Retrieve the metadata for all @Bean methods
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
    // 获取注解元数据
	AnnotationMetadata original = sourceClass.getMetadata();
    // 获取被@Bean标注的Method元数据集
	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.
        // 此处会将无序的beanMethods集转为有序的beanMethods集,
        // 因为StandardAnnotationMetadata使用的是反射方式获取meta信息,
        // 这个不保证顺序,所以需要将其转为SimpleAnnotationMetadata类型,
        // 他内部使用ClassVisitor通过读取字节码文件,按顺序解析获取meta信息。
        // 后续会有专门的章节介绍StandardAnnotationMetadata和SimpleAnnotationMetadata类
		try {
            // 这里getMetadataReader得到的是一个SimpleMetadataReader对象
			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读取字节码文件,封装元数据
	getClassReader(resource).accept(visitor, PARSING_OPTIONS);
	this.resource = resource;
	this.annotationMetadata = visitor.getMetadata();
}
// 读取字节码文件完成之后,封装SimpleAnnotationMetadata对象
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接口

封装方法的元数据。

实现类:

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

StandardMethodMetadata

使用反射方式获取方法元数据。

SimpleMethodMetadata

基于SimpleAnnotationMetadataReadingVisitor读取的字节码数据,封装方法元数据。

到此这篇关于Spring @Bean注解深入分析源码执行过程的文章就介绍到这了,更多相关Spring @Bean注解内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Spring@Bean注解深入分析源码执行过程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Spring@Bean注解深入分析源码执行过程

随着SpringBoot的流行,我们现在更多采用基于注解式的配置从而替换掉了基于XML的配置,所以本篇文章我们主要探讨基于注解的@Bean以及和其他注解的使用
2023-01-10

Spring中Bean注入源码示例解析

这篇文章主要为大家介绍了Spring中Bean注入源码示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-15

深入分析GolangServer源码实现过程

这篇文章深入介绍了GolangServer源码实现过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2023-02-02

SpringCloud@RefreshScope注解源码层面深入分析

@RefreshScope注解能帮助我们做局部的参数刷新,但侵入性较强,需要开发阶段提前预知可能的刷新点,并且该注解底层是依赖于cglib进行代理的,所以不要掉入cglib的坑,出现刷了也不更新情况
2023-05-15

spring是如何注入对象的和bean创建过程分析

首先需要知道一个大致实现● 这个注入过程肯定是在 BeanPostProcessor 中实现的●spring 是在 beanFactory.getBean 进行 bean 实例化的,即懒加载● 根据第二条,也就是说在 getBean 的时候才会去调用所有 Be
spring是如何注入对象的和bean创建过程分析
2019-05-21
2023-06-02

深入解析golang编译器的编译过程:从源码到可执行文件

从源码到可执行文件:解析golang编译器的编译过程概述:Golang是一种快速、简单和可靠的编程语言,而其编译器是将Golang代码转换为可执行文件的关键工具。在这篇文章中,我们将深入探究Golang编译器的编译过程,从源码到最终生成的可
深入解析golang编译器的编译过程:从源码到可执行文件
2023-12-29

Tomcat源码分析 | 启动过程深度解析

在启动过程中,LifecycleBase 首先发出 STARTING_PREP 事件,StandardServer 额外还会发出 CONFIGURE_START_EVENT 和 STARTING 事件,通知 LifecycleListene

useEffect 返回函数执行过程源码解析

这篇文章主要为大家介绍了useEffect 返回函数执行过程源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-16

【Mybatis源码解析】mapper实例化及执行流程源码分析

文章目录 简介 环境搭建 源码解析 附 基础环境:JDK17、SpringBoot3.0、mysql5.7 储备知识:《【Spring6源码・AOP】AOP源码解析》、《JDBC详细
2023-08-20

深入浅出Sqoop之迁移过程源码分析

【摘要】 Sqoop是一种用于在 Apache Hadoop 和结构化数据存储(如关系数据库)之间高效传输批量数据的工具 。本文将简单介绍Sqoop作业执行时相关的类及方法,并将该过程与MapReduce的执行结合,分析数据如何从源端迁移到目
深入浅出Sqoop之迁移过程源码分析
2016-04-28

SpringBoot整合SpringSecurity过滤器链加载执行流程源码分析(最新推荐)

SpringBoot对于SpringSecurity提供了自动化配置方案,可以使用更少的配置来使用SpringSecurity,这篇文章主要介绍了SpringBoot整合SpringSecurity过滤器链加载执行流程源码分析,需要的朋友可以参考下
2023-02-23

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录