【深入浅出Spring原理及实战】「夯实基础系列」360全方位渗透和探究SpringEL的开发实战指南(解析上下文—EvaluationContext)

EvaluationContext接口

EvaluationContext是一个用于评估表达式的接口,它能解析属性、方法和字段,并且帮助执行类型转换。它在表达式的解析和执行过程中扮演着重要的角色,是一个非常有用的工具。

当使用StandardEvaluationContext时,我们可以直接调用相关方法来解析属性、调用方法和访问字段。此外,它还提供了类型转换的功能,可以帮助我们处理不同类型之间的转换。

StandardEvaluationContext

在具体的实现中,标准实现StandardEvaluationContext使用反射来操作对象,并且它缓存了java.lang.reflect的方法、字段和构造函数实例,以提升性能。这种实现方式充分利用了Java的反射机制,使得对象操作过程更加高效。

EvaluationContext和其标准实现StandardEvaluationContext是进行表达式评估和执行的重要工具,通过反射机制和缓存功能来提升性能,并简化对象操作和类型转换的过程。

StandardEvaluationContext的实现机制

在StandardEvaluationContext中,您可以使用setRootObject()方法或在构造函数中传入根对象来指定要评估的对象。此外,您还可以使用setVariable()和registerFunction()方法来指定在表达式中使用的变量和函数。

StandardEvaluationContext的扩展机制

如果需要扩展SpEL评估表达式的功能,您还可以在StandardEvaluationContext中注册自定义的ConstructorResolvers、MethodResolvers和PropertyAccessors。

ConversionService类型转换

SpEL默认使用Spring Core中的ConversionService进行类型转换。该转换服务内置了许多常用的转换器,并且还支持完全的可扩展性,因此您可以添加自定义的类型转换器。此外,该转换服务还具有泛型感知的重要功能。这意味着当在表达式中使用泛型类型时,SpEL会自动尝试进行转换,以保持对象的类型正确性。

操作案例分析

在实践中,这意味着当使用SpEL的setValue()方法进行赋值时,如果要设置的属性是一个List类型,而实际上该属性的具体类型是List,SpEL会自动识别出在将元素放入列表之前需要将其转换为布尔值。下面是一个简单的例子:

java 复制代码
class Simple {
    public List<Boolean> booleanList = new ArrayList<Boolean>();
}
Simple simple = new Simple();
simple.booleanList.add(true);
StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);
// false is passed in here as a string. SpEL and the conversion service will
// correctly recognize that it needs to be a Boolean and convert it
parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");
// b will be false
Boolean b = simple.booleanList.get(0);

bean定义提供表达式支持

SpEL表达式可以与基于XML或注解的配置元数据一起使用,用于定义BeanDefinition。无论是在XML配置还是注解配置中,定义表达式的语法形式都是#{<表达式字符串>}

XML操作配置

在XML配置中,可以使用SpEL表达式来定义bean的属性值、方法参数值甚至构造函数参数值。例如:

xml 复制代码
<bean id="myBean" class="com.example.MyBean">
  <property name="name" value="#{user.name}" />
  <property name="age" value="#{user.age + 1}" />
  <constructor-arg value="#{user.address}" />
  <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/> 
</bean>

在上面的示例中,我们使用SpEL表达式来引用另一个bean中的属性值,并进行一些计算。user.name表示引用名为user的bean中的name属性值,user.age + 1表示引用userage属性值并在其基础上加1,user.address表示引用useraddress属性值作为构造函数参数值。

systemProperties

在Spring表达式语言(SpEL)中,systemProperties是一个预定义的对象,用于访问系统属性。系统属性是指Java虚拟机(JVM)运行时设置的属性,可以通过System.getProperty(String key)方法来获取。

使用systemProperties对象,可以在SpEL表达式中获取和操作系统属性。例如,可以使用systemProperties['java.version']来获取Java版本的系统属性,或者使用systemProperties['user.dir']来获取当前工作目录的系统属性。

以下是一个示例,展示了如何在SpEL表达式中使用systemProperties对象:

xml 复制代码
<bean id="testBean" class="xxxx.TestBean">
    <property name="userRegion" value="#{ systemProperties['user.region'] }"/>
</bean>

注解操作配置

在注解配置中,可以使用SpEL表达式来定义注解中的属性值。例如:

java 复制代码
@Component
public class TestBean{
  @Value("#{user.region}")
  private String region;
  // ...
}

在上面的示例中,我们使用SpEL表达式作为@Value注解的属性值,来引用另一个bean中的属性值并进行一些计算。#{user.region}表示引用名为user的bean中的region属性值。

通过使用SpEL表达式,我们可以灵活地在配置中引用和计算属性值,使配置更加动态和可配置化。

systemProperties

java 复制代码
@Value("#{systemProperties['user.name']}")
private String username;

@Value("#{systemProperties['os.name']}")
private String osName;

在上述示例中,我们使用@Value注解将系统属性赋值给Java类中的两个变量:usernameosNamesystemProperties['user.name']将获取当前用户的用户名,而systemProperties['os.name']将获取当前操作系统的名称。

需要注意的是,systemProperties对象只能访问系统属性,而不能访问环境变量。如果需要访问环境变量,可以使用systemEnvironment对象。

获取其他bean对象的数据

例如,还可以通过名称来引用其他bean的属性。

xml 复制代码
<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
</bean>
<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
    <property name="initialShapeSeed" value="#{numberGuess.randomNumber}"/>
</bean>

自动装配(Autowiring)方法和构造函数

java 复制代码
@Autowired
  public TestBean( @Value("#{systemProperties['user.region']}"} String defaultLocale) {
      this.defaultLocale = defaultLocale;
}

$#符号有不同的用途和含义:

  • $符号:$符号用于引用直接访问的变量或属性。它表示直接获取当前上下文中的值,例如 ${name} 表示获取名为 name 的变量的值。$符号通常在XML属性配置中使用。

  • #符号:#符号用于引用通过Spring容器管理的bean。它表示获取由Spring容器创建和管理的bean的引用,可以调用bean的方法和访问bean的属性。例如 #{person.getName()} 表示获取名为 person 的bean的getName()方法的返回值。#符号通常在注解或SpEL表达式中使用。

总的来说,$符号用于引用直接访问的变量或属性,而#符号用于引用通过Spring容器管理的bean。它们在不同的上下文中使用,具有不同的含义和作用。

相关推荐
一只特立独行的猪6111 小时前
Java面试——集合篇
java·开发语言·面试
吃面不喝汤661 小时前
Flask + Swagger 完整指南:从安装到配置和注释
后端·python·flask
讓丄帝愛伱2 小时前
spring boot启动报错:so that it conforms to the canonical names requirements
java·spring boot·后端
weixin_586062022 小时前
Spring Boot 入门指南
java·spring boot·后端
一颗知足的心2 小时前
SpringCloud Alibaba五大组件之——Sentinel
spring·spring cloud·sentinel
Dola_Pan5 小时前
Linux文件IO(二)-文件操作使用详解
java·linux·服务器
wang_book5 小时前
Gitlab学习(007 gitlab项目操作)
java·运维·git·学习·spring·gitlab
蜗牛^^O^6 小时前
Docker和K8S
java·docker·kubernetes
从心归零6 小时前
sshj使用代理连接服务器
java·服务器·sshj
一个诺诺前行的后端程序员7 小时前
springcloud微服务实战<1>
spring·spring cloud·微服务