Spring源码分析之Scope注解处理

Spring框架Ioc容器加载流程及Bean的生命周期源码分析 学习视频:《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-dWx4ae2h-1712113363460)][外链图片转存中…(img-xEEzxJr6-1712113363461)] 阅读详情

前言

本文旨在分析在Spring容器启动之时,@Scope注解的处理过程。

处理代码为:(该代码来自与register方法的底层实现doRegisterBean方法)

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());

//进入this.scopeMetadataResolver.resolveScopeMetadata方法
ScopeMetadata resolveScopeMetadata(BeanDefinition definition);

//找到resolveScopeMetadata(BeanDefinition definition)方法的实现如下:


@Override
	public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
		ScopeMetadata metadata = new ScopeMetadata();
//判断definition是AnnotatedBeanDefinition的实例,按照本人工程中写出的样例其中传入的definition参数的类型是AnnotatedGenericBeanDefinition,
//AnnotatedGenericBeanDefinition的继承关系图如下1.1中所示
//结论是true
		if (definition instanceof AnnotatedBeanDefinition) {
			AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;//强装
           //AnnotationConfigUtils.attributesFor方法分析如下1.2所示
           //其作用为:在待注入bean中寻找@Scope注解
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
					annDef.getMetadata(), this.scopeAnnotationType); //Scope.class就是this.scopeAnnotationType
            //如果存在@Scope注解
			if (attributes != null) {
                //attributes.getString("value")作用就是得出@Scope注解后的value值
                //就是将value中的值赋给scopeName属性
				metadata.setScopeName(attributes.getString("value"));
                //获取 proxyMode 属性值
				ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
                //如果代理模式是默认的,则proxyMode=ScopedProxyMode.NO,没代理
				if (proxyMode == ScopedProxyMode.DEFAULT) {
					proxyMode = this.defaultProxyMode;
				}
                //设置代理模式
				metadata.setScopedProxyMode(proxyMode);
			}
		}
		return metadata;
	}

1.1

AnnotatedGenericBeanDefinition的继承关系图如下所示:

显而易见,AnnotatedGenericBeanDefinition继承于BeanDifinition,故而前述的判断为true。

1.2 

AnnotationConfigUtils.attributesFor方法源码:

@Nullable
	static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, Class<?> annotationClass) {
		return attributesFor(metadata, annotationClass.getName());
	}


//上述方法的重载方法:attributesFor(metadata, annotationClass.getName())源码:


@Nullable
	static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, String annotationClassName) {
		return AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClassName, false));
	}

//继续追踪AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClassName, false))方法如下:
//1.参数中的方法:metadata.getAnnotationAttributes(annotationClassName, false)
//详细分析见1.3


//2.主方法:其中包装进入AnnotationAttributes这个Map类中的实例map是参数中方法提供的,所以所有的逻辑来自于该参数方法

/**
	 * Return an {@link AnnotationAttributes} instance based on the given map.
	 * <p>If the map is already an {@code AnnotationAttributes} instance, it
	 * will be cast and returned immediately without creating a new instance.
	 * Otherwise a new instance will be created by passing the supplied map
	 * to the {@link #AnnotationAttributes(Map)} constructor.
	 * @param map original source of annotation attribute <em>key-value</em> pairs
      翻译大概是:基于所给定的map返回一个AnnotationAttributes类的实例
      如果这个map已经是一个AnnotationAttributes类的实例,它将被强转,并在不创建一个新的实例的
      前提下立马返回,程序结束,否则呢,就将该map传递给AnnotationAttributes的构造器创建一个 
      AnnotationAttributes类的新实例。
	 */,
	@Nullable
	public static AnnotationAttributes fromMap(@Nullable Map<String, Object> map) {
       //下面的逻辑在翻译中已经体现,不再赘述
		if (map == null) {
			return null;
		}
		if (map instanceof AnnotationAttributes) {
			return (AnnotationAttributes) map;
		}
		return new AnnotationAttributes(map);
	}

1.3

metadata.getAnnotationAttributes(annotationClassName, false)源码

/**
	 * Retrieve the attributes of the annotation of the given type, if any (i.e. if
	 * defined on the underlying element, as direct annotation or meta-annotation),
	 * also taking attribute overrides on composed annotations into account.
	 * @param annotationName the fully qualified class name of the annotation
	 * type to look for
	 * @param classValuesAsString whether to convert class references to String
	 * class names for exposure as values in the returned Map, instead of Class
	 * references which might potentially have to be loaded first
	 * @return a Map of attributes, with the attribute name as key (e.g. "value")
	 * and the defined attribute value as Map value. This return value will be
	 * {@code null} if no matching annotation is defined.
     * 主要的意思是,检索出所给定注释的属性
	 */
	@Nullable
	Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);


//查看其实现方法,鼠标指针放在方法上,快捷键Ctrl+Alt+B,出现所有的实现方法,最后点击你所需要的

###StandardAnnotationMetadata类
@Override
	@Nullable
	public Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) { //classValuesAsString=false
		return (this.annotations.length > 0 ? AnnotatedElementUtils.getMergedAnnotationAttributes(
				getIntrospectedClass(), annotationName, classValuesAsString, this.nestedAnnotationsAsMap) : null); 
 //1.annotations为final类型的数组,并且在StandardAnnotationMetadata类的构造器中赋值为:
 //this.annotations = introspectedClass.getAnnotations();
 //追踪introspectedClass.getAnnotations底层如下(****)处
	}
 //2.getAnnotationAttributes(String annotationName, boolean classValuesAsString)的逻辑是:
(1)annotations数组长度大于0,则执行AnnotatedElementUtils.getMergedAnnotationAttributes(
				getIntrospectedClass(), annotationName, classValuesAsString, this.nestedAnnotationsAsMap)方法,
分析如下1.4所示。
(2)否则,返回null,也就是说待处理的bean中没有注释


(****)introspectedClass.getAnnotations底层实现:
public Annotation[] getAnnotations() {
        return AnnotationParser.toArray(annotationData().annotations); //得到一个Annotation[]实例,其底层待探索(反射实现)
    }

1.4

AnnotatedElementUtils.getMergedAnnotationAttributes(
                getIntrospectedClass(), annotationName, classValuesAsString, this.nestedAnnotationsAsMap)源码:

/**
	 * Get the first annotation of the specified {@code annotationName} within
	 * the annotation hierarchy <em>above</em> the supplied {@code element} and
	 * merge that annotation's attributes with <em>matching</em> attributes from
	 * annotations in lower levels of the annotation hierarchy.
	 * <p>Attributes from lower levels in the annotation hierarchy override attributes
	 * of the same name from higher levels, and {@link AliasFor @AliasFor} semantics are
	 * fully supported, both within a single annotation and within the annotation hierarchy.
	 * <p>In contrast to {@link #getAllAnnotationAttributes}, the search algorithm used by
	 * this method will stop searching the annotation hierarchy once the first annotation
	 * of the specified {@code annotationName} has been found. As a consequence,
	 * additional annotations of the specified {@code annotationName} will be ignored.
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level javadoc}.
	 * @param element the annotated element
	 * @param annotationName the fully qualified class name of the annotation type to find
	 * @param classValuesAsString whether to convert Class references into Strings or to
	 * preserve them as Class references
	 * @param nestedAnnotationsAsMap whether to convert nested Annotation instances
	 * into {@code AnnotationAttributes} maps or to preserve them as Annotation instances
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if not found
	 * @since 4.2
	 * @see #findMergedAnnotation(AnnotatedElement, Class)
	 * @see #findMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
	 * @see #getAllAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
	 */
      //上述翻译的核心意思是:在提供的element之上的注释层次结构中,获取指定annotationName的第一个注释,
      //并将该注释的属性与来自注释层次结构较低级别的注释的匹配属性合并。
      //在本案例中传递的参数可知:就是获取@Scope注释的属性等信息。
	@Nullable
	public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
			String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
		AnnotationAttributes attributes = searchWithGetSemantics(element, null, annotationName,
				new MergedAnnotationAttributesProcessor(classValuesAsString, nestedAnnotationsAsMap)); 
       //核心方法,获取attribute属性,可以看下searchWithGetSemantics方法的底层描述,详见1.5
		AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap);
		return attributes;
	}

1.5

searchWithGetSemantics方法的底层描述

	/**
	 * Search for annotations of the specified {@code annotationName} or
	 * {@code annotationType} on the specified {@code element}, following
	 * <em>get semantics</em>.
	 * @param element the annotated element
	 * @param annotationType the annotation type to find
	 * @param annotationName the fully qualified class name of the annotation
	 * type to find (as an alternative to {@code annotationType})
	 * @param processor the processor to delegate to
	 * @return the result of the processor (potentially {@code null})

     * 大致意思是:在遵循get语义的前提下,在指定element实例上寻找指定的annotationName或者
     * annotationType的注释,由上面传递的参数可知,我们的目的就是寻找@Scope注释
	 */
	@Nullable
	private static <T> T searchWithGetSemantics(AnnotatedElement element,
			@Nullable Class<? extends Annotation> annotationType,
			@Nullable String annotationName, Processor<T> processor) {

		return searchWithGetSemantics(element,
				(annotationType != null ? Collections.singleton(annotationType) : Collections.emptySet()),
				annotationName, null, processor);
	}

//在往下的searchWithGetSemantics方法(org.springframework.core.annotation.AnnotatedElementUtils#searchWithGetSemantics(java.lang.reflect.AnnotatedElement, java.util.Set<java.lang.Class<? extends java.lang.annotation.Annotation>>, 
java.lang.String, java.lang.Class<? extends java.lang.annotation.Annotation>, org.springframework.core.annotation.AnnotatedElementUtils.Processor<T>, java.util.Set<java.lang.reflect.AnnotatedElement>, int))
大概是用递归实现的,有待进一步探究

1.6 参考文献

【1】https://segmentfault.com/a/1190000017413393?utm_source=tag-newest

【2】https://www.bilibili.com/video/BV1tx411o77Z?p=5

【3】《Spring源码解析》

SpringIOC之ScopeMetadata 然后,可以将 MyScopeMetadata 配置到 Spring 容器中,以应用于特定的 Bean 或 BeanDefinition。 阅读详情

相关推荐

spring核心源码分析第五篇 refresh流程之postProcessBeanFactory

postProcessBeanFactory作用 AbstractApplicationContext并没有任何实现,但其允许在上下文子类中重写 其方法的注释翻译如下: 在beanfactory加载完毕后,尚未构建BeanDefinition和实例化之前,允许子类覆写ApplicationContext来实现相关功能,例如: 修改BeanFactory 或者注册BeanPostProcessor等等 spring并没有约束子类重写后具体的实现,只是告知当前的被执行时机是beanFactory加载完成,Be

小麒麟的博客 1730

设计模式—结构型—代理模式

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 角色: 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。 真实角色:实现抽象角色,定义真实角色所要实现的业

路漫漫其修远兮,吾将上下而求索。 444

手把手教你用TL431设计反激电源补偿器(附波特图调试技巧)

本文详细介绍了如何使用TL431设计反激电源补偿器,并提供了波特图调试技巧。通过实战经验分享,帮助工程师快速掌握补偿网络设计、分压电阻计算和稳定性判据,避免常见设计误区,提升电源稳定性与效率。

weixin_29201859的博客 377

AnnotationConfigUtils 处理注解Bean 定义类中的通用注解

AnnotationConfigUtils 类的processCommonDefinitionAnnotations()在向容器注册Bean 之前,首先对注解Bean 定义类中的通用Spring 注解进行处理,源码如下: //处理Bean定义中通用注解 static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { AnnotationAttrib

Leon_Jinhai_Sun的博客 468

MTK metadata中AF模块的移除与配置调整

本文详细介绍了在MTK平台Camera开发中如何移除metadata中的AF(自动对焦)模块。通过系统清理MTK_CONTROL_AF_REGIONS、MTK_CONTROL_MAX_REGIONS等关键配置项,并调整对焦模式及硬件特性声明,确保定制化设备在禁用自动对焦功能后的稳定运行。

q1w3e5r7t9y的博客 570

【QGIS、OSM】利用python开源工具实现指定区域的交通分配

如果从osmgnms和grid2demand得到的node.csv,我们要修改path4gnms代码中的utils.py的四处设置。利用QGIS实现可视化,得到的link_performance.csv,参数有volume和VOC。改完这四处代码,就可以运行path4gnms中的tutorial.ipynb了。

weixin_40594084的博客 1275

AnnotationScopeMetadataResolver 解析作用域元数据

AnnotationScopeMetadataResolver 通过resolveScopeMetadata()方法解析注解Bean 定义类的作用域元信息,即判断注册的Bean 是原生类型(prototype)还是单态(singleton)类型,其源码如下: //解析注解Bean定义类中的作用域元信息 @Override public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { ScopeMetadata metada

Leon_Jinhai_Sun的博客 683

中文实体关系抽取数据集大盘点:从百度Duie2.0到医疗CBLUE,哪个更适合你的NLP项目?

本文全面分析了中文实体关系抽取领域的主流数据集,包括百度DuIE 2.0、医疗CBLUE等,帮助开发者根据项目需求选择最适合的数据集。文章详细对比了各数据集的特点、适用场景及优化策略,为自然语言处理项目提供实用指南。

weixin_29284657的博客 121

spring5.2.x源码阅读笔记-AnnotationConfigApplicationContext构建(二)register(componentClasses)

接上一篇,使用同样的测试用例 代码块1:register(Class<?>... componentClasses) public void register(Class<?>... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); this.reader.register(componentClasses);

weixin_43836063的博客 1398

光伏发电系统模拟及其发电预测开源python工具pvlib

本文介绍光伏发电系统模拟及其发电预测开源python工具pvlib,以及举例介绍获取辐照度方法、光伏发电预测思路。

肖永威的专栏 1万+

鸿蒙手机卸载内置应用 adb连接

**傻瓜式删除鸿蒙系统内置应用,自己亲测有效。**

JJDXBT的博客 3万+

spring应用手册-IOC(XML配置实现)-(36)-context:component-scan的scope-resolver属性

戴着假发的程序员出品 context:component-scan的scope-resolver属性 spring应用手册(第一部分) 注意这个属性scope-resolver和scoped-proxy是互斥的。 这个属性跟name-generator有点类似,它是基于接口ScopeMetadataResolver的,实现resolveScopeMetadata方法,目的是为了将@Sco

344

YOLOv11 改进策略 | HWD:引入 Haar 小波变换,减少信息丢失

在卷积神经网络(CNN)中,下采样(Downsampling)是降低特征图分辨率、扩大感受野的关键操作,通常通过最大池化(MaxPool)或步长为 2 的卷积(Strided Convolution)实现。然而,这些方法在降低分辨率的同时,往往会丢失图像中的高频细节信息(如边缘、纹理)和精确的空间位置信息,这可能对后续特征提取和目标检测精度产生不利影响,尤其是对于小目标和需要精细定位的任务。

走向CTO的路上... 1789

@RefreshScope注解底层源码分析

最近在研究Spring Cloud和Spring Cloud Alibaba源码,在看到Nacos的配置中心的时候,有注意到自动刷新配置的玩法,底层实现依靠@RefreshScope注解。那么为什么要写这篇文章呢?笔者认为@RefreshScope注解源码实现跨度特别大,从Spring Cloud Alibaba 到Spring Cloud 到 Spring Boot 再到Spring,笔者认为能够理解它的源码实现的话对Spring全家桶的理解又能上升一个档次~版本如果下: 先会用,再深入源码,所以我们

李哈zzz的博客 1476

Xiaojie雷达之路---手把手教你从串口获取雷达原始数据(一)---新建工程(开始)

Hello,大家好,我是Xiaojie,欢迎大家能够和Xiaojie来一起学习毫米波雷达知识,Xiaojie准备连载一个系列的文章---利用串口获取毫米波雷达中的原始数据,本系列文章将从新建工程到最后原始数据显示到PC上进行逐步介绍,这个系列的文章大约是一个4-5篇左右。本篇文章呢,主要讲的是如何新建一个毫米波雷达的工程。

XiaoJie的博客 5810

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【Spring源码分析】扫描并注册BeanDefinition逻辑

扫描源码一般是接触Spring源码时大家首先去接触的,因为它是去扫描且过滤出符合的条件的Bean的元数据的(注意这里说的是Bean的元数据,并非全是类的元数据,在此过程中用了ASM技术去提取类的元数据进行操作),比如满足includefilter,不是接口,抽象类等等才会被加入候选…

qq_63691275的博客 1322

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

spring源码分析

spring源码深究

野心与梦 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Spring 其它注解和杂项

使用 @Lazy 注解的典型场景就是解决循环依赖问题。特别是构造注入,@Lazy 是弥补构造注入的『缺点』的关键。当你对注入的 JavaBean 使用 @Lazy 注解时,Spring 注入的并非是这个单例对象,而是它的一个代理。当你(在未来)第一次使用这个 Bean 时,这个代理对象才会去 IoC 容器中找这个真正的 Bean。

xiaotu的博客 1023

【Spring源码分析】BeanDefinition

Spring源码分析(BeanDefinition)BeanDefinition的加载与注册

scj1022的博客 1332

@ComponentScan注解各属性作用源码分析

的

xyjy11的博客 743

Spring源码分析

1、核心基础 1(常规),2(部分内部原理),3(专业训练) 1(spring.xml) 2(注解) 1、核心注解 注解 作用 备注 @Bean 容器中注册组件 @Primary 同类组件如果有多个,标注主组件 @DependsOn 组件之间声明依赖关系 @Lazy 组件懒加载(最后使用的时候才创建) @Scope 声明组件的作用范围(SCOPE_PROTOTYPE,SCOPE_SINGLETON,) @Primary 同类组件如果有多个,标注主组件 @

Jerry的博客 180

Spring IoC 源码分析 (基于注解) 之 Bean的解析与注册

在上一篇文章Spring IoC 源码分析 (基于注解) 之 包扫描中,我们介绍了Spring基于注解扫描包获取bean的过程。本文我们将一起探讨spring对bean解析,并注册到IOC容器的过程。 我们先接着看下面这段代码: ClassPathBeanDefinitionScanner类 ...

chengwei0708的博客 353

细节满满!Spring IOC容器源码分析最优解

前言 许多文章都是分析的 xml 配置,但是现在 Spring Boot 开发多基于注解。本文从注解的角度分析 Spring IOC 容器源码。 版本: Spring Boot:2.1.6.RELEASE Spring FrameWork:5.1.8.RELEASE Java 8 BeanDefinition BeanDefinition 接口定义了一个包含属性、构造器参数、其他具体信息的 bean 实例。 public interface BeanDefinition extends ..

Java圈全能架构师的博客 365

spring--AnnotationConfigApplicationContext扫描bean过程源码分析

AnnotationConfigApplicationContext 前言 AnnotationConfigApplicationContext 和 ClassPathXmlApplicationContext 与 FileSystemXmlApplicationContext 类似都是抽象类 AbstractApplicationContext 的子类,最终都调用父类的 refresh 方法开始 bean工厂的初始化等一系列操作,不同的是 AnnotationConfigApplicationConte

安魂 1498

dubbo service注解用法_dubbo系列之spring boot核心配置读取(三)

欢迎关注公众号【sharedCode】致力于主流中间件的源码分析, 可以直接与我联系版本说明springboot starter : 0.1.1dubbo版本: 2.6.2自动配置类@Configuration @ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true, havingV...

weixin_39634898的博客 847

最简 Spring IOC 容器源码分析

前言 BeanDefinition BeanFactory 简介 Web 容器启动过程 bean 的加载 FactoryBean 循环依赖 bean 生命周期 公众号 前言 许多文章都是分析的 xml 配置,但是现在 Spring Boot 开发多基于注解。本文从注解的角度分析 Spring IOC 容器源码。 版本: Spring Boot:2.1.6.RELEASE Spring FrameWork:5.1.8.RELEASE Java 8 文章部分内容参考自:https://www.javado...

231
上一篇: Spring容器启动之org.springframework.context.annotation.ConditionEvaluator#shouldSkip方法详解
下一篇: Spring启动之CommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) 解析
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值