
示例工程文档【免费下载链接】spring-reading涵盖了 Spring 框架的核心概念和关键功能包括控制反转IOC容器的使用面向切面编程AOP的原理与实践事务管理的方式与实现Spring MVC 的流程与控制器工作机制以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程以及对 Spring 源码的编程风格与设计模式的深入探讨。项目地址https://gitcode.com/GitHub_Trending/sp/spring-reading点击查看免费下载PropertyAccessor是 Spring 表达式语言SpEL中定义统一属性访问规范的核心接口它让 Spring 各模块SpEL、数据绑定、AOP、IoC 容器等能够以一致的方式读取和写入对象的属性并通过自定义实现适配 JavaBean、Map、数组等不同对象结构。本文以 spring-reading 仓库中的 spring-spel-propertyAccessor 模块为例深入剖析该接口的四个方法、八类典型实现并给出可直接运行的读写实战示例帮助读者掌握自定义属性访问逻辑的方法。一、知识储备理解本接口需要的基础在深入PropertyAccessor之前建议先具备以下三方面的知识Spring 表达式语言SpEL了解 SpEL 的基本语法与功能包括表达式的解析流程、运算符、变量与函数的用法。表达式只有被评估Evaluate才会产生值而评估过程离不开EvaluationContext提供的运行时环境。对象属性访问与反射机制了解如何使用 Java 反射访问与操作对象属性包括获取类字段、调用 getter/setter 方法、设置字段值等。PropertyAccessor的典型实现如ReflectivePropertyAccessor正是基于反射完成属性读写。设计模式理解适配器模式、策略模式等常见设计模式。PropertyAccessor接口在设计中扮演了策略角色——SpEL 引擎把不同的对象类型分派给对应的访问器策略自定义实现类通常也需要遵循这些模式思想。如果对 SpEL 的评估上下文还不熟悉可以先阅读仓库中的 spring-spel-evaluationContext/README.md其中展示了StandardEvaluationContext如何持有属性访问器列表——这正是PropertyAccessor被挂载和调用的位置。二、基本描述PropertyAccessor 是什么PropertyAccessor接口的作用在于定义一套统一的属性访问规范。通过该接口可以实现对对象属性的读取与写入操作使得 Spring 框架中的各个模块能够统一地访问对象的属性从而实现更加灵活、可扩展的应用开发。通过实现这个接口开发者可以定制对象属性的访问逻辑以满足不同场景下的需求典型场景包括Spring 表达式语言SpEL表达式#myBean.name求值时引擎需要借助PropertyAccessor读取name属性数据绑定Data Binding将用户输入如 HTTP 请求参数绑定到后端数据模型AOP 编程对被增强对象的属性进行拦截与修改IoC 容器访问注册在容器中的 Bean 对象属性。三、主要功能读写能力与可扩展性PropertyAccessor接口围绕读与写两条主线提供四个核心能力属性读取ReadcanRead()判断当前访问器是否可以读取指定属性read()读取属性值。只有canRead()返回true时read()才能成功。属性写入WritecanWrite()判断当前访问器是否可以写入指定属性write()设置属性值。只有canWrite()返回true时write()才能成功。自定义属性访问逻辑允许开发者根据实际需求实现自定义访问逻辑通过自定义PropertyAccessor实现类来访问对象属性从而承载特定业务逻辑或行为。适配不同的对象结构可以针对不同对象结构实现不同的PropertyAccessor实现类以适应 JavaBean、Map、数组等不同类型的对象。四、接口源码四个方法 一个目标类声明PropertyAccessor接口源码如下Spring Framework 3.0 引入作者 Andy Clement/** * 属性访问器能够读取可能写入对象的属性。 * * p这个接口没有限制因此实现者可以自由地直接访问属性作为字段或通过getter方法或其他方式访问属性。 * * p解析器可以选择指定一个目标类的数组用于调用它。然而如果从{link #getSpecificTargetClasses()}返回{code null}它将被调用 * 以尝试解析所有属性引用并有机会确定它是否可以读取或写入它们。 * * p属性解析器被认为是有序的并且每个都将依次被调用。影响调用顺序的唯一规则是在{link #getSpecificTargetClasses()}中直接命名目标类的任何解析器 * 将在通用解析器之前首先被调用。 * * author Andy Clement * since 3.0 */ public interface PropertyAccessor { /** * 返回此解析器应该被调用的类数组。 * p返回{code null}表示这是一个通用解析器可以在任何类型上尝试解析属性。 * return 适用于此解析器的类数组或{code null}如果是通用解析器 */ Nullable Class?[] getSpecificTargetClasses(); /** * 用于确定解析器实例是否能够访问指定目标对象上的指定属性。 * param context 尝试进行访问的评估上下文 * param target 要访问属性的目标对象 * param name 要访问的属性的名称 * return 如果此解析器能够读取属性则为true * throws AccessException 如果有任何问题确定是否可以读取属性 */ boolean canRead(EvaluationContext context, Nullable Object target, String name) throws AccessException; /** * 用于从指定的目标对象中读取属性。 * 只有当{link #canRead}也返回{code true}时才能成功。 * param context 尝试进行访问的评估上下文 * param target 要访问属性的目标对象 * param name 要访问的属性的名称 * return 包装读取的属性值和其类型描述符的TypedValue对象 * throws AccessException 如果有任何问题访问属性值 */ TypedValue read(EvaluationContext context, Nullable Object target, String name) throws AccessException; /** * 用于确定解析器实例是否能够向指定目标对象上的指定属性写入。 * param context 尝试进行访问的评估上下文 * param target 要访问属性的目标对象 * param name 要访问的属性的名称 * return 如果此解析器能够写入属性则为true * throws AccessException 如果有任何问题确定是否可以写入属性 */ boolean canWrite(EvaluationContext context, Nullable Object target, String name) throws AccessException; /** * 用于向指定目标对象的属性写入。 * 只有当{link #canWrite}也返回{code true}时才能成功。 * param context 尝试进行访问的评估上下文 * param target 要访问属性的目标对象 * param name 要访问的属性的名称 * param newValue 属性的新值 * throws AccessException 如果有任何问题写入属性值 */ void write(EvaluationContext context, Nullable Object target, String name, Nullable Object newValue) throws AccessException; }源码要点解读1getSpecificTargetClasses()决定调用优先级返回null表示这是一个通用解析器可以对任意类型尝试解析属性返回具体类数组则表示该解析器专精于某些目标类型。SpEL 引擎按顺序依次询问访问器唯一确定的排序规则是直接命名了目标类的解析器一定先于通用解析器被调用。这一机制保证了MapAccessor专精Map类型可以优先于通用反射访问器处理Map对象。2canRead/read与canWrite/write成对出现读取和写入都遵循先询问、后操作的两段式协议先调用canXxx判断能力再调用对应的read/write执行实际操作。read返回的是TypedValue——同时包装属性值与其类型描述符方便表达式引擎做后续的类型转换与比较。所有方法都声明抛出AccessException用于表达访问过程中的异常情况。3与EvaluationContext的挂载关系EvaluationContext接口中定义了getPropertyAccessors()方法返回一个按顺序询问的访问器列表参见 spring-spel-evaluationContext/README.md。表达式求值过程中一旦遇到属性引用引擎便遍历该列表找到第一个canRead返回true的访问器来执行读取。五、主要实现八类典型访问器Spring 围绕PropertyAccessor提供了丰富的实现各司其职BeanExpressionContextAccessor允许在表达式中访问特定的对象和属性可直接访问上下文中的对象属性。典型场景在 Spring 的Value注解中使用 SpEL 表达式读取配置属性。BeanFactoryAccessor允许在 SpEL 表达式中访问 SpringBeanFactory中注册的 Bean 对象的属性。BeanFactory是 Spring IoC 容器的核心接口用于管理和创建 Bean。通过BeanFactoryAccessor可以在表达式中通过beanName语法访问容器中的 Bean读取和设置其属性值。CompilablePropertyAccessor允许对属性访问进行编译优化以提高性能。通过编译能力在运行时对属性访问逻辑进行优化减少不必要的计算、提高执行效率适用于性能要求较高的场景。DataBindingPropertyAccessor允许在 Spring 应用程序中读取和写入属性专门服务数据绑定过程。数据绑定是将用户输入绑定到后端数据模型的过程在 Web 应用程序中广泛应用该访问器为绑定过程提供便捷的属性读写能力。EnvironmentAccessor用于从 Spring环境Environment中访问属性例如读取配置文件中的属性值。Spring 的环境抽象统一了系统属性、环境变量、配置文件等属性来源通过EnvironmentAccessor可以在 SpEL 表达式中直接访问环境属性实现动态配置与属性注入。JspPropertyAccessor允许在 JSP 页面中使用 SpEL 表达式并在 JSP 标签如eval标签中访问对象的属性。JSP 与 SpEL 结合可实现更灵活、动态的页面渲染。MapAccessor用于在 SpEL 表达式中直接访问Map对象中的键值对。通过MapAccessor可以像访问普通属性一样读取、设置 Map 的键值极大方便了在表达式中操作 Map 结构。OptimalPropertyAccessor提供属性访问的优化实现通常在ReflectivePropertyAccessor内部使用用于提高属性访问性能。通过对属性访问逻辑的优化减少不必要的计算从而更高效地访问属性值。此外ReflectivePropertyAccessor是 SpEL 的默认属性访问器在StandardEvaluationContext中getPropertyAccessors()默认返回的就是ReflectivePropertyAccessor这一点可以在 EvaluationContextDemo.java 的运行结果中直接看到。它基于 Java 反射机制读取 JavaBean 时优先查找getXxx()方法写入时优先查找setXxx()方法并在内部使用OptimalPropertyAccessor做热点访问优化。六、最佳实践从零写一个可运行的属性访问 Demo仓库中 PropertyAccessorDemo.java 给出了一个最小可运行的示例完整演示了创建解析器 → 构建上下文 → 设置变量 → 解析并读取属性的完整链路。6.1 目标 JavaBeanMyBeanMyBean定义了一个简单的 Java Bean包含私有字段name及对应的 getter / setter完整代码见 MyBean.javapackage com.xcs.spring; public class MyBean { public MyBean(String name) { this.name name; } private String name; // Getters and setters public String getName() { return name; } public void setName(String name) { this.name name; } }6.2 主程序解析表达式并读取属性package com.xcs.spring; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; public class PropertyAccessorDemo { public static void main(String[] args) { // 创建一个SpEL表达式解析器 ExpressionParser parser new SpelExpressionParser(); StandardEvaluationContext context new StandardEvaluationContext(); context.setVariable(myBean, new MyBean(spring-reading)); // 解析SpEL表达式读取 myBean 对象的 name 属性 String name parser.parseExpression(#myBean.name).getValue(context, String.class); System.out.println(name name); } }6.3 代码逐步拆解步骤代码作用1SpelExpressionParser创建 SpEL 表达式解析器负责把字符串表达式编译为Expression对象2StandardEvaluationContext创建评估上下文它是EvaluationContext的默认实现内部持有ReflectivePropertyAccessor等组件见 spring-spel-evaluationContext 模块3context.setVariable(myBean, ...)在上下文中注册名为myBean的变量供表达式以#myBean形式引用4parseExpression(#myBean.name)解析表达式#myBean解析为上下文变量.name触发属性访问5getValue(context, String.class)在给定上下文中求值ReflectivePropertyAccessor通过getName()反射读取属性并转换为String返回6.4 运行结果运行后控制台输出name spring-reading6.5 运行前提模块的 Maven 坐标见 pom.xml它继承自聚合模块 spring-spel/pom.xml后者又是仓库根 pom.xml 的子模块仓库根 POM 声明了 Spring Boot 2.3.12.RELEASE对应 Spring Framework 5.2.x使用 Java 11 编译spring-boot-starter-web等依赖中已包含 SpEL 相关的spring-expression模块因此无需额外引入依赖即可运行将PropertyAccessorDemo作为普通 Java 应用运行包含 main 方法即可得到上述输出。6.6 进阶自定义一个 PropertyAccessor理解了协议之后自定义访问器只需实现四个方法即可。核心思路是在getSpecificTargetClasses()中返回要专精的类型或返回null表示通用在canRead/canWrite中判断目标对象与属性名是否匹配自己的处理范围在read/write中执行真正的读写逻辑read需要返回TypedValue可用new TypedValue(value)包装。随后通过context.setPropertyAccessors(List.of(myAccessor))或继承StandardEvaluationContext覆写getPropertyAccessors()即可把自定义访问器接入 SpEL 求值链路。七、与其他组件的关系Spring 表达式语言SpEL在 SpEL 中PropertyAccessor接口用于访问对象的属性。SpEL 提供运行时动态求值表达式的机制通过PropertyAccessor接口实现对对象属性的读写操作。Spring 数据绑定数据绑定用于将用户提交的数据绑定到后端数据模型PropertyAccessor提供统一方式来访问对象属性可在数据绑定过程中使用典型实现为DataBindingPropertyAccessor。Spring AOP 编程在面向切面编程中PropertyAccessor可用于访问被增强对象的属性配合 AOP 实现对属性的拦截、修改等操作。Spring IoC 容器在控制反转容器中PropertyAccessor可用于访问注册在容器中的 Bean 对象的属性典型实现为BeanFactoryAccessor方便地管理和访问对象属性。其他自定义组件自定义框架或库中同样可以使用PropertyAccessor实现对对象属性的访问操作以实现特定功能或逻辑。八、常见问题与规避建议属性访问权限问题访问对象的属性时可能因访问控制如private字段、模块化限制导致无法读取或写入。建议优先依赖公共 getter/setter 或调整访问权限必要时借助ReflectivePropertyAccessor的setAllowWrite/ 反射设置进行控制。属性命名问题大小写不匹配、拼写错误会导致属性无法被正确解析。建议严格遵循 JavaBean 命名规范字段name对应方法getName/setName表达式中的属性名与 getter 名称保持一致。属性类型转换问题将字符串值赋给整数类型属性等场景可能抛出转换异常。建议利用EvaluationContext提供的TypeConverter完成显式转换或在写入前做好类型校验。上下文环境配置问题需要提供合适的上下文环境如EvaluationContext配置错误或环境设置不当会导致属性访问失败。建议使用StandardEvaluationContext作为默认上下文按需通过setPropertyAccessors等 API 定制组件列表。异常处理问题属性访问过程中可能出现空指针异常、访问权限异常等。建议对AccessException及求值异常进行适当的捕获与处理保证程序稳定性与健壮性。九、小结PropertyAccessor以极简的五个方法定义了 SpEL 乃至整个 Spring 生态统一的属性读写协议getSpecificTargetClasses()决定优先级canRead/read、canWrite/write组成先询问、后操作的两段式访问。围绕它Spring 提供了面向反射、Map、BeanFactory、Environment、数据绑定等场景的丰富实现同时留给开发者完全的自定义空间。想进一步深入可以结合以下仓库资源继续阅读实战入口PropertyAccessorDemo.java 与 MyBean.java上下文与访问器挂载关系spring-spel-evaluationContext/README.md表达式解析入口spring-spel-expressionParser/README.md模块构建配置spring-spel-propertyAccessor/pom.xml赞分享示例工程文档【免费下载链接】spring-reading涵盖了 Spring 框架的核心概念和关键功能包括控制反转IOC容器的使用面向切面编程AOP的原理与实践事务管理的方式与实现Spring MVC 的流程与控制器工作机制以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程以及对 Spring 源码的编程风格与设计模式的深入探讨。项目地址https://gitcode.com/GitHub_Trending/sp/spring-reading点击查看免费下载相关推荐Symfony属性访问对象属性操作的统一接口Symfony属性访问对象属性操作的统一接口 你是否还在为PHP对象属性的复杂操作而困扰在日常开发中我们经常需要处理各种对象的属性访问比如获取私有属性、后端Web框架MyBatis ObjectWrapper 源码解析统一 JavaBean、Map 与集合的属性访问抽象MyBatis ObjectWrapper 源码解析统一 JavaBean、Map 与集合的属性访问抽象 本文基于 doocs/source code hun文档教程知识库Spring 源码阅读深入解析 Environment 环境抽象 —— Profiles 与属性解析的统一入口Spring 源码阅读深入解析 Environment 环境抽象 —— Profiles 与属性解析的统一入口 Environment 是 Spring 框架示例工程文档上一篇RocketRide 运行方式选型指南Cloud、自托管与 VS Code 本地引擎下一篇终极指南如何用nRF Connect桌面版加速Nordic物联网设备开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考