SpEL

本文介绍Spring3.0引入的SpEL表达式语言,包括基本语法、运算符、集合操作等特性,并展示了如何利用SpEL进行Bean属性注入及方法调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring 3.0 创建了一种新的方式用以配置对象的注入(set注入或者构造参数注入)–SpEL

一、基本特性:
使用#{…}作为定界符,所有的大括号中的字符都将被认定为是SpELl
1、字面量的表示:

<property name="count" value="#{5}"/>

2、小数:

<property name="count" value="#{5.5}"/>

3、科学计数法:

<property name="capacity" value="#{1e4}"/>

4、String 可以使用单引号或者双引号作为字符串的定界符号:

<property name="name" value="#{'tom'}"/> 或者 
<property name="name" value='#{"tom"}'/>  视外部情况而定

5、Boolean:

<property name="enabled" value="#{false}"/>

二、引用Bean属性和方法

1、引用其他对象

<bean id="obj1" value="com.xxx.xxx.Xxx"/>
<bean id="obj2" value="com.xxx.xxx.Xxx2">
    <property name="instrument" value="#{obj1}"/>
</bean>

通过id:”obj1”将对象注入到instrument属性中,这与下面的配置是一样的:

<property name="instrument" ref="obj1"/>

2、引用其他对象的属性:

<bean id = "obj" class="com.xxx.xxx.Xxx">
    <property name="song" value="#{kenny.song}"/>
</bean>

kenny 是Bean id 而song是属性的名字,这样配置就如同我们写了如下代码

Xxx obj= new Xxx();
obj.setSong(kenny.getSong());

3、调用其他的方法

<property name ="song" voalue="songSelector.selectSong()"/>

调用了Beanld为”songSelector”的对象的selectSong()方法,并将返回值注入到song属性中,或者还可以脸是操作。如下:

<property name="song" value="songSelector.selectSong().toUpperCase()"/>

如果songSelector.selectSong()返回null的还会抛出异常,为了避免,我们要使用?.表达式。这样如果songSelector.selectSong()为null就不会再调用后面的方法了。如下:

<property name="song" value="songSelector.selectSong()?.toUpperCase()"/>

4、调用静态方法
我们已经知道如何通过一个对戏那个调用它的方法了,但是如何调用一个静态方法呢?用T()。
它将返回一个Class object
然后我们再调用相应的方法即可:

<property name="multiplier" value="T(java.lang.Math).PI"/>

SpEL支持的运算符号

1、算数运算符:+、-、*、/、%、^

<property name="adjustedAmount" value="#{counter.total+42}"/>
<property name="adjustedAmount" value="#{counter.total-20}"/>
<property name="circumference" value="#{2*T(java.lang.Math).PI*circle.redius}"/>
<property name="average" value="#{counter.total/counter.count}"/>
<property name="remainder" value="#{{counter.total%counter.count}"/>
<property name="area" value="#{T(java.lang.Math).PI*circle.radius^2}"/>

加号还可以用作字符串连接:

<property name="fullName" value="#{performer.firstName + ' '+performer.lastName}"/>

2、比较运算符:< , > ,== , <= , >= ,lt ,gt, eq, le ,ge

<property name="equal" value="#{counter.total==100}"/>

不可以使用< 和 > 号,应为在xml中它有特殊含义,我们使用lt和gt代替

<property name="hasCapacity" value="#{counter.total le 1000}"/>

3、逻辑运算符号 and , or , not, !

<property name="largeCircle" value="#{shape.kind=='circle' and shape.perimeter gt 1000}"/>
<property name="outOfStock" value="#{!product.available}"/>
<property name="outOfStock" value="#{not product.available}"/>

**4、if-else 运算符 : ?:(ternary), ?:(Elvis)
最基本的?:(如同使用EL表达式):**

<property name="instrument" value="#{songSelector.selecSong()=='Jingle Bells' ? piano : 'Jingle Bells '}"/>

变体的 ?:

<property name="song" value="#{ kenny.song!=null ? kenny.song : 'Greensleeves'}"/>
优化后:<property name="song" value="#{ kenny.song ? : 'Greensleeves'}"/>

显然,优化后的书写更为简洁

5、正则表达式:matches

<property name="validEmail" value="#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}'}"/>

表达式返回逻辑值,如果匹配返回true,否则返回false

SpEL对集合的支持

有实体类如下:

package com.it.items;
public class Person{
    private String name;
    private int age;
}

xml中有如下定义

<util:list id = "persons">
    <bean class="com.it.items" p:name="zhangsan" p:age="20"/>
    <bean class="com.it.items" p:name="lisi" p:age="22"/>
    <bean class="com.it.items" p:name="wangwu" p:age="30"/>
    <bean class="com.it.items" p:name="laoda" p:age="28"/>
</util:list>

1、获取Collection中的某个对象
通过下标访问,如下:

<property name="person" value="#{persons[3]}"/>

这样就能得到name为laoda的person对象。(下标从0开始)

下标还可以通过变量来指定:

<property name="person" value="#{persons[T(java.lang.Math).reandom()*persons.size()]}"/>

如果是从Map中获取,可指定key值,

<property name="person" value="#{persons['key']}"/>

也可以通过key访问properties的值,

<util:properties id = "settings" location="classpath:settings.properties"/>
<property name="accessToken" value="#{settings['twitter.accessToken']}"/>

可以通过下标访问 systemEnvironment 和 SystemProperties 中的值,

<property name="homePath" value="#{systemEnvironment['HOME']}"/>

如果在 jre 运行时配置了-Dapplication.home=/etc/myapp,我们可以通过如下方式访问

<property name="homePath" value="#{systemProperties['application.home']}"/>

通过小标获取String 串种的某个字符

'This is a test'[8]

2、获取Collection中的子集,通过条件筛选(获取到的是一个新的Collection对象)

筛选子集:

<property name="bigCities" value="#{persons.?[age gt 20]}"/>

获取第一个(.^[]):

<property name="aBigCity" value="#{persons.^[age gt 20]}"/>

获取最后一个(.$[])

<property name="aBigCity" value="#{persons.$[age gt 20]}"/>

3、集合的投影(.![])
获取name组成的列表,

<property name="cityNames" value="#{persons.![name]}"/>

也可以获取多列

    <property name="cityNames" value="#{persons.![name + ', ' + age]}"/>

4、将投影和筛选结合,

<property name="cityNames" value="#{persons.?[age gt 20].![name +', ' + state]}"/>

本文只作为初学者笔记参考,勿喷

03-25
<think>好的,我现在需要处理用户关于Spring Expression Language(SpEL)的查询。用户要求提供一个使用指南,并按照特定的格式要求来回答,包括使用中文、正确的LaTeX格式、生成相关问题等。首先,我得确保自己充分理解SpEL的核心概念和功能,这样才能准确回答。 首先,我应该回顾用户提供的引用内容。引用1提到SpEL类似于JSP的EL表达式,而引用2和3则详细说明了SpEL的特性,比如支持运算符、方法调用、属性访问,以及在Spring中的应用场景,比如@Value注解、条件注解等。这些信息是构建答案的基础。 接下来,我需要组织答案的结构。用户希望有一个结构清晰的指南,分步骤说明。按照系统级指令,需要包括基本概念、语法元素、应用场景、示例代码以及性能优化等内容。同时,要确保所有数学表达式和代码块格式正确。比如,行内表达式用$...$,独立公式用$$...$$,并单独成段。 在语法元素部分,用户提到的运算符如算术、比较、逻辑、三元、正则等需要详细列出,并且每个运算符可能需要用LaTeX格式呈现。例如,比较运算符中的等于可以用$==$,不等于用$!=$,而正则匹配需要用$matches$。同时,需要注意避免使用Markdown,所以用编号列表来呈现这些运算符。 应用场景部分,用户提供的引用提到了@Value注解、条件注解、缓存注解等,这些都需要详细解释,并给出示例代码。例如,在@Value中使用SpEL注入值,或者用@ConditionalOnExpression控制Bean的创建。代码块需要用三个反引号包裹,并指定语言为java,同时确保代码的正确性,比如正确的注解和表达式写法。 在示例代码部分,需要展示不同场景下的SpEL用法,比如属性注入、条件判断、缓存键生成等。每个示例要简洁明了,突出SpEL的应用方式。例如,使用@Value("#{systemProperties['user.dir']}")来注入系统属性,或者@Cacheable(key = "#id")来定义缓存键。 性能优化部分,需要提醒用户注意SpEL表达式的复杂度,避免在频繁调用的方法中使用复杂表达式,以及缓存解析结果提高性能。这部分需要结合实践经验,给出实用的建议,帮助用户避免常见陷阱。 最后,生成相关问题需要考虑用户可能进一步想知道的内容,比如与JSP EL的区别、安全性、调试方法、性能优化、动态配置等。这些问题应覆盖基础对比、高级用法和实际问题解决,有助于用户深入学习和应用SpEL。 整个过程中,需要确保语言口语化,避免使用专业术语堆砌,而是用易于理解的方式解释概念。同时,检查LaTeX格式是否正确,比如行内表达式是否正确使用$符号,独立公式是否单独成段。例如,在提到正则匹配时,表达式应该写成$'192.168.1.1' matches '\\d+\\.\\d+\\.\\d+\\.\\d+'$,确保转义字符正确。 另外,需要注意引用标识的正确添加,每个引用在回答中自然出现的地方末尾添加,如引用1、2、3对应的内容。例如,在介绍SpEL基本概念时,末尾添加[^1],在提到运算符时引用[^3],应用场景引用[^2]等。 可能遇到的困难是如何将技术细节以简洁明了的方式呈现,同时符合用户的格式要求。需要反复检查各部分是否符合系统指令,特别是LaTeX和代码块的格式,避免错误。同时,确保生成的问题与用户查询相关,能够引导用户进一步学习。 总结来说,回答的结构需要包括简介、语法、应用、示例、优化和问题,每个部分紧扣用户提供的引用内容,并补充必要的细节和示例,确保全面且易于理解。最后,通过相关问题引导用户深入探索SpEL的不同方面,提升他们的知识和应用能力。</think>### Spring Expression Language (SpEL) 使用指南 #### 1. 基本概念 SpELSpring 框架内置的表达式语言,支持在运行时查询和操作对象图。其核心特性包括: - 字面量(数值、字符串、布尔值) - 运算符(算术、逻辑、关系等) - 方法调用与属性访问 - 集合操作(过滤、投影) #### 2. 语法元素 SpEL 表达式语法类似 Java,但更简洁。例如: - **变量引用**:`#variableName` - **类型操作符**:`T(java.lang.Math).PI` - **集合选择**:`list.?[#this > 10]` 常用运算符示例: $$ \text{算术运算符: } +, -, *, /, \% $$ $$ \text{逻辑运算符: } and, or, not $$ $$ \text{正则匹配: } '192.168.1.1' matches '\\d+\\.\\d+\\.\\d+\\.\\d+' $$ #### 3. 核心应用场景 - **属性注入**:通过 `@Value` 注解动态注入值 ```java @Value("#{systemProperties['user.dir']}") private String userDir; ``` - **条件化 Bean 创建**:结合 `@ConditionalOnExpression` 控制 Bean 加载[^2] ```java @ConditionalOnExpression("#{environment.getProperty('mode') == 'prod'}") ``` - **缓存配置**:在 `@Cacheable` 中定义动态键 ```java @Cacheable(key = "#id + '-' + #type") public Object getData(int id, String type) { ... } ``` #### 4. 安全与性能优化 - **表达式缓存**:Spring 默认缓存解析后的表达式,减少重复解析开销 - **限制复杂度**:避免在循环或高频调用场景中使用复杂表达式 - **沙箱机制**:通过 `EvaluationContext` 限制可访问的类和方法 #### 5. 示例:动态权限校验 ```java @PreAuthorize("@securityService.checkAccess(#userId, T(com.example.Role).ADMIN)") public void adminOperation(String userId) { ... } ``` 此例通过 SpEL 调用自定义安全服务方法,并引用枚举类型实现动态权限控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值