关系分类及结构图.

  1. el表达式的解析接口,ExpressionParser.
    有其实现类,可注册配置选项(config),重点在于操作表达式.
  2. el表达式的配置类,SpelParserConfiguration.
    可配置el表达式的编译模式,指定类加载器,设置是否自动增长空元素(auto-grow)等等.
  3. el表达式的求值上下文,EvaluationContext.
    通过el的解析接口,获取表达式的接口,然后在此接口中可设置求值上下文的配置.
    求值上下文的接口,可设置rootObject,属性,构造器,方法,变量等等.

spring 切面注解 使用 el表达式 方法参数 spring el表达式注解获取参数值_操作符

基本的接口和类的列表.

接口或类

功能性说明

顶层接口(parser{configuration,context})

ExpressionParser  [i]

建议使用的实现类:SpelExpressionParser [c]

构造时可注册配置选项:SpelParserConfiguration [c]

调用解析方法时(`parse*`)可获取表达式接口:Expression [i]

SpelParserConfiguration [c]

可选的配置选项有编译模式的选择,类加载器的指定与否,是否自动初始化等等

其中编译模式,关联了枚举类:SpelCompilerMode [e]

Expression [i]

可对 el表达式 进行读写操作的接口,有其setter和getter方法实现.

另重写行为,可配置 el表达式 求值时的上下文:EvaluationContext [i]

EvaluationContext [i]

求值上下文的接口,spring 4.x中有两个实现类,即简易的和标准的实现.

可操作el表达式的属性,构造器,类型,rootObject等等.

SimpleEvaluationContext [c]

StandardEvaluationContext [c]

建议使用的实现类

SpelExpressionParser [c]

表达式解析的实现类

重写的构造器中,可注册解析的配置选项.(configuration)

在解析的方法中(parse*),可获取表达式的接口实例.(expression)

SpelParserConfiguration [c]

可组合选择自需的解析模式

1,设置编译模式,有三种候选项.  spelCompilerMode

2,设置解析式的类加载器.  classLoader

3,设置是否自动初始化空引用.  auto-grow

4,设置是否自动初始化集合中的空元素.  auto-grow

5,设置自动初始化集合长度的阈值.  limits

SpelCompilerMode [e]

内置了三种解析模式

off , 关闭,默认的选项

mixed , 混合模式

immediate , 即时模式

StandardEvaluationContext [c]

标准的求值上下文.也可根据不同场景,使用SimpleEvaluationContext [c].

此类中有大量的setter方法,可设置rootObject; property; constructor; method; var; type; 等等.

spel的语法

  • el表达式的语法格式为: ` #{ spel expression } `,也可以使用属性占位符的方式替代el的表达式.只需在配置文件中进行如下配置:
<!--属性占位符. -->                                                      
<!--只要配置了`property-placeholder`,就可使用占位符的形式,${属性} -->                
<!--可替代spel的形式#{spel expression} -->                                
<context:property-placeholder />
  • 属性占位符的格式是: ` ${  expression } `
  • spel在xml中的使用,只需使用el表达式,或者属性占位符即可.
    基于java的源码的使用,只需和注解@Value组合使用即可.
  • 注意,el表达式需要访问的rootObject的属性应当是public修饰的.
  • el表达式基础语法的图表.

语法

格式

使用

字面量(literal expression)

使用单引号,或者通过转义符使用双引号

支持字符串,算术运算,空值处理,进制转换等

" \"jack\" " ; " 2E-23-12 " ; " null "

容器(properties,lists,maps,arrays)

直接访问,可使用调用符访问其成员

" list.get(0) "

索引器(indexers)

使用符号`[]`,可直接访问其成员

" list[0] "

内部初始化(inner lists/maps)

使用格式:{value}或{key:value},成员以逗号分隔

" {0,1,2,3,4} "或" {0:name,1:age,3:gender} "

数组构造器(属于new操作符)

直接在表达式中,可初始化并分配数组

" new int[3] ";支持所有的数组初始化语法

操作符

1,在xml文档中,因符号解析冲突问题,部分操作符的替代方案,使用英文字符如下:

lt (<), gt (>), le (#), ge(>=), eq (==), ne (!=), div (/), mod (%), not (!)

2,可在parse*的重构方法中,使用#{},涉及的操作类是TemplateParserContext.

比较操作符

可使用比如>,<,=等等的比较运算符

\

逻辑操作符

表达式中的逻辑操作符,使用and,or和not

\

算术操作符

表达式支持的有+,-,*,/,%,^(平方)等等

\

instanceof操作符

可直接在表达式内使用,使用空格区分

" obj instanceof Type ",返回Boolean类型

matches操作符

正则匹配,支持大部分的匹配符

" str matches 'regex expression' "

类型引用操作符---T()

使用符号: T(),可查看TypeLocator接口,
java.lang包中的引用不需全类名,反之使用.

" T(Math).random() "

new操作符

使用new操作符可实例化对象,但应使用全类名

" new java.util.ArrayLis<?>() "

变量引用操作符---#

与求值上下文有关,内置的有#this和#root,

也可设置方法引用,设置求值上下文实例

" #var "

bean引用操作符---@

可引用容器中注册的bean,依据beanName

" @beanName "

三元操作符---` ? : `

表达式支持三元操作符

\

Elvis操作符

Groovy语言中替代三元操作符的方案.
<var> ?: <value>;var若是null,则取候选值value

" attr?:\"unknown\" "

安全导航操作符---?

来自Groovy语言

考虑空值异常的情况,若使用?操作符,

遇到此异常时,不抛出,而是返回null.

" list?.get(12) "

集合选择操作符---.?

集合中选择满足条件的元素,可结合变量引用

操作符使用

" list.?[#this>0] "

集合转换操作符---.!

将集合中的取出的元素,转换则条件返回的结果

" list.![#this<0] "


使用的jar包依赖

<dependency>                                
	<groupId>org.springframework</groupId>  
	<artifactId>spring-context</artifactId> 
	<version>4.3.20.RELEASE</version>       
</dependency>                               
<dependency>                                
	<groupId>org.springframework</groupId>  
	<artifactId>spring-test</artifactId>    
	<version>4.3.20.RELEASE</version>       
</dependency>                               
                                            
<dependency>                                
	<groupId>junit</groupId>                
	<artifactId>junit</artifactId>          
	<version>4.12</version>                 
</dependency>

xml配置文件,注册解析器,解析配置,求值上下文,以及测试所使用的bean

<!--配置spel解析器,SpelExpressionParser -->                                                              
<bean class="org.springframework.expression.spel.standard.SpelExpressionParser">                    
	<constructor-arg name="configuration">                                                          
		<!--设置解析配置选项,SpelParserConfiguration -->                                                    
		<!--注:不启用spel的编译模式. -->                                                                     
		<bean class="org.springframework.expression.spel.SpelParserConfiguration">                  
			<constructor-arg name="compilerMode">                                                   
				<null />                                                                            
			</constructor-arg>                                                                      
			<constructor-arg name="compilerClassLoader">                                            
				<null />                                                                            
			</constructor-arg>                                                                      
			<constructor-arg name="autoGrowNullReferences" value="true" />                          
			<constructor-arg name="autoGrowCollections" value="true" />                             
			<constructor-arg name="maximumAutoGrowSize" value="120" />                              
		</bean>                                                                                     
	</constructor-arg>                                                                              
</bean>                                                                                             
                                                                                                    
<!--配置求值上下文,EvaluationContext -->                                                                   
<!--spring4.3新增SimpleEvaluationContext实现类,配置需要使用@Configuration和@Bean的组合形式. -->                      
<bean class="org.springframework.expression.spel.support.StandardEvaluationContext" />              
                                                                                                    
                                                                                                    
<!--配置测试使用的rootObject -->                                                                           
<bean id="user" class="siye.el.User" scope="prototype">                                             
	<property name="props">                                                                         
		<props>                                                                                     
			<prop key="name">jack</prop>                                                            
			<prop key="age">43</prop>                                                               
			<prop key="sex">0</prop>                                                                
		</props>                                                                                    
	</property>                                                                                     
	<property name="intarr">                                                                        
		<list>                                                                                      
			<array value-type="int">                                                                
				<value>43</value>                                                                   
			</array>                                                                                
			<array value-type="int">                                                                
				<value>54</value>                                                                   
			</array>                                                                                
			<array value-type="int">                                                                
				<value>98</value>                                                                   
			</array>                                                                                
		</list>                                                                                     
	</property>                                                                                     
	<property name="list">                                                                          
		<list>                                                                                      
			<value>3</value>                                                                        
			<value>2</value>                                                                        
			<value>1</value>                                                                        
		</list>                                                                                     
	</property>                                                                                     
	<property name="map">                                                                           
		<map>                                                                                       
			<entry key="0" value="head" />                                                          
			<entry key="1" value="body" />                                                          
			<entry key="2" value="foot" />                                                          
		</map>                                                                                      
	</property>                                                                                     
</bean>                                                                                             
                                                                                                    
<!--属性占位符. -->                                                                                      
<!--只要配置了`property-placeholder`,就可使用占位符的形式,${属性} -->                                                
<!--可替代spel的形式#{spel expression} -->                                                                
<!--<context:property-placeholder />  -->

基于java的配置类

package siye.el;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ComponentScan("siye.el")
@ImportResource(locations = "classpath:/config.xml")
public class ConfigClass
{
}

辅助测试el表达式的注册bean类

package siye.el;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component("userInner")
@Scope("prototype")
public class User
{
	public Properties props;
	public int[] intarr;
	public List<Integer> list;
	public Map<Integer, String> map;


	public String name;

	public User getInstance()
	{
		return new User();
	}


	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public Properties getProps()
	{
		return props;
	}
	public void setProps(Properties props)
	{
		this.props = props;
	}
	public int[] getIntarr()
	{
		return intarr;
	}
	public void setIntarr(int[] intarr)
	{
		this.intarr = intarr;
	}
	public List<Integer> getList()
	{
		return list;
	}
	public void setList(List<Integer> list)
	{
		this.list = list;
	}
	public Map<Integer, String> getMap()
	{
		return map;
	}
	public void setMap(Map<Integer, String> map)
	{
		this.map = map;
	}

}

测试类;basic,测试字面量解析;collections,测试集合容器的操作;operator,测试el表达式的操作符等

package siye.el;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = ConfigClass.class)
public class UnitTestBasic
{

	@Autowired
	private SpelExpressionParser parser;


	@Test
	public void test()
	{
		// 解析字符串
		String stringValue =
				parser.parseExpression("\"jack\"").getValue(String.class);
		System.out.println(stringValue);

		// 解析浮点数
		// 支持指数表示法,符号和小数点.
		Double doubleValue =
				parser.parseExpression("3.4232365E+23").getValue(Double.class);
		System.out.println(doubleValue.toString());


		// 解析整数
		// 支持进制的表达方式.
		Integer intValue =
				parser.parseExpression("0xfffff").getValue(Integer.class);
		System.out.println(intValue);


		// 解析布尔值
		Boolean booleanValue =
				parser.parseExpression("false").getValue(Boolean.class);
		System.out.println(booleanValue);


		// 解析空值.
		// 注意null没有类类型.
		Object nullValue =
				parser.parseExpression("null").getValue(Object.class);
		System.out.println(nullValue);

	}


}
package siye.el;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

/*
 * 1,spel的语法,properties,lists,arrays,maps,indexers(索引器)
 * 	其中索引器的格式是使用符号`[]`直接访问其元素.
 * 2,spel中的inner lists 和 inner maps.
 * 	使用符号{value}和{key:value},多元素以符号`,`间隔.
 * 3,spel中,可直接使用数组的构造器创建数组.
 */
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = ConfigClass.class)
public class UnitTestCollections
{

	@Autowired
	private ApplicationContext context;
	@Autowired
	@Qualifier("user")
	private User user;
	@Autowired
	SpelExpressionParser parser;
	@Autowired
	StandardEvaluationContext evaluationContext;

	@Test
	public void test()
	{
		System.out.println(context);
		System.out.println(user);
		System.out.println(parser);
		System.out.println(evaluationContext);
	}



	// 解析properties
	@Test
	public void test1()
	{
		Expression expression =
		// parser.parseExpression("props.getProperty(\"name\")");
				parser.parseExpression("props[name]");
		String value = expression.getValue(user, String.class);
		System.out.println(value);
	}

	// 解析arrays
	@Test
	public void test2()
	{
		Expression expression = parser.parseExpression("intarr[1]");
		Integer intvalue = expression.getValue(user, int.class);
		System.out.println(intvalue);
	}


	// 解析lists和indexers(索引器)
	@Test
	public void test3()
	{
		// 测试lists
		Expression expression = parser.parseExpression("list.get(0)");
		Integer intvalue = expression.getValue(user, Integer.class);
		System.out.println(intvalue);
		// 测试indexers(索引器)
		Expression expression2 = parser.parseExpression("list[2]");
		expression2.setValue(evaluationContext, user, 23);
		System.out.println(user.list);
	}

	// 测试maps
	@Test
	public void test4()
	{
		// 采用indexers(索引器)的方式访问.
		Expression expression = parser.parseExpression("map[0]");
		String value = expression.getValue(user, String.class);
		System.out.println(value);
	}


	// spel的内部初始化,inner lists和inner maps
	// 使用符号{value}和{key:value},多元素以符号`,`间隔.
	@Test
	public void test5()
	{
		// inner lists
		Expression expression =
				parser.parseExpression("{'jack','rose','lili'}");
		List<?> list = expression.getValue(evaluationContext, List.class);
		System.out.println(list);
		// inner maps
		Expression expression2 =
				parser.parseExpression("{0:'jack',1:'rose',2:'lili'}");
		Map<?, ?> map = expression2.getValue(evaluationContext, Map.class);
		System.out.println(map);
	}

	// 使用数组的构造器
	@Test
	public void test6()
	{
		// 还可以使用其他创建形式
		// new int[num]
		// new int[num0][num1]
		Expression expression = parser.parseExpression("new int[]{1,2,3,4,5}");
		int[] intarr = expression.getValue(evaluationContext, int[].class);
		System.out.println(Arrays.toString(intarr));
	}


}
package siye.el;

import java.util.ArrayList;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@ContextConfiguration(classes = ConfigClass.class)
public class UnitTestOperator
{
	@Autowired
	ApplicationContext context;
	@Autowired
	SpelExpressionParser parser;
	@Autowired
	StandardEvaluationContext evaluationContext;
	@Autowired
	@Qualifier("userInner")
	private User user;
	@Autowired
	@Qualifier("user")
	private User userxml;


	@Test
	public void test()
	{
		System.out.println(user);
		System.out.println(parser);
		System.out.println(evaluationContext);
	}

	/*
	 * spel中常使用的操作符有,
	 * 比较操作符,比如>,<,=,e.g.
	 * 逻辑操作符,and,or,not,
	 * 算术操作符,+,-,%,^,e.g.
	 * instanceof操作符,
	 * matches操作符,
	 * T()类型引用操作符,
	 * new操作符,可以使用new操作符实例化对象,但必须是全类名!
	 * `#`,变量操作符,是用来操作变量的,内置的变量有#this和#root
	 * `.`,属性操作符
	 * `?`,搜寻操作符
	 * `@\&`,操作bean
	 * 
	 * 补充说明:
	 * xml文档中的literal-operator替代形式
	 * lt (<), gt (>), le (#), ge(>=), eq (==),
	 * ne (!=), div (/), mod (%), not (!)
	 */

	// 使用比较操作符.
	@Test
	public void test1()
	{
		Expression expression = parser.parseExpression("2>3");
		Boolean value = expression.getValue(boolean.class);
		System.out.println(value);
	}


	// 使用逻辑操作符.
	@Test
	public void test2()
	{
		Expression expression = parser.parseExpression("true and false");
		Boolean value = expression.getValue(boolean.class);
		System.out.println(value);
	}

	// 使用算术操作符.
	@Test
	public void test3()
	{
		Expression expression = parser.parseExpression("1.22 + 3.44");
		Double value = expression.getValue(double.class);
		System.out.println(value);
	}


	// 使用instanceof操作符
	@Test
	public void test4()
	{
		Expression expression =
				parser.parseExpression("'jack' instanceof T(java.lang.String)");
		Boolean value = expression.getValue(boolean.class);
		System.out.println(value);
	}


	// 使用matches操作符
	@Test
	public void test5()
	{
		Expression expression =
				parser.parseExpression("'5.001' matches '^\\d+(\\.\\d{2})$'");
		Boolean value = expression.getValue(boolean.class);
		System.out.println(value);
	}


	// 使用T()操作符
	// 说明,
	// 标准的求值上下文,StandardEvaluationContext.
	// 其借用的是typeLocator属性来查询类型的,而TypeLocator接口有默认的实现
	// StandardTypeLocator类.可查看其构造器,默认把`java.lang`包注册进去了.
	// 故,
	// 使用T()操作符的时候,若引用的是java.lang包的类,就不需要前缀类,
	// 但若是其他类型,必须使用全类名.
	@Test
	public void test6()
	{
		Expression expression =
				parser.parseExpression("T(java.lang.Math).random()");
		Double value = expression.getValue(double.class);
		System.out.println(value);
	}


	// 使用new操作符,必须使全类名.
	@Test
	public void test7()
	{
		Expression expression = parser.parseExpression("new siye.el.User()");
		User value = expression.getValue(User.class);
		System.out.println(value);
	}


	// spel内部使用变量.借用符号`#`
	@Test
	public void test8()
	{
		// 在环境中新建一个变量.
		evaluationContext.setVariable("newname", "jack");
		// 使用该变量,#newname
		Expression expression = parser.parseExpression("name = #newname");
		expression.getValue(evaluationContext, user);
		System.out.println(user.name);
	}

	// function language
	// 变量引用,也可以引用操作方法.
	// 使用操作麻烦,不推荐使用,有符号`.`的替代方案.
	@Test
	public void test9()
	{
		try
		{
			evaluationContext.setVariable("test",
					Arrays.class.getMethod("toString", int[].class));
			Object value =
					parser.parseExpression("#test(intarr)").getValue(
							evaluationContext, userxml);
			System.out.println(value);
		} catch (Exception e)
		{
		}
	}


	// 测试#this和#root
	// this,表示当前求值环境中处理的对象.
	// root,表示求值环境中设置的rootObject.
	@SuppressWarnings("serial")
	@Test
	public void test10()
	{
		// 测试#this
		evaluationContext.setVariable("list", new ArrayList<Integer>()
		{
			{
				add(0);
				add(1);
				add(2);
				add(3);
				add(4);
			}
		});
		Object thisvalue =
				parser.parseExpression("#list.?[#this>3]").getValue(
						evaluationContext);
		System.out.println(thisvalue);
		// 测试#root
		evaluationContext.setRootObject(userxml);
		Object rootvalue =
				parser.parseExpression("#root").getValue(evaluationContext);
		System.out.println(rootvalue);
	}


	// bean reference
	// @操作符,用来引用容器中配置的bean
	@Test
	public void test11()
	{
		// 获取bean工厂的解析对象.
		BeanFactoryResolver factoryResolver = new BeanFactoryResolver(context);
		// 设置bean的解析对象.
		evaluationContext.setBeanResolver(factoryResolver);
		Expression expression = parser.parseExpression("@user");
		Object value = expression.getValue(evaluationContext);
		System.out.println(value);
	}


	// 三元操作符
	// `?:`
	@Test
	public void test12()
	{
		Expression expression = parser.parseExpression("2<5?0:1");
		Integer value = expression.getValue(evaluationContext, int.class);
		System.out.println(value);
	}


	// Elvis操作符
	// <var>?:<value>,表示如果var取值为null,则取value值.
	// Elvis操作符实际上是三元操作符的简写形式.
	//
	// 常识补充,其是Groovy语言中的三元操作符.
	@Test
	public void test13()
	{
		user.list = null;
		Expression expression = parser.parseExpression("list?:'Unknown'");
		Object value = expression.getValue(evaluationContext, user);
		System.out.println(value);
	}


	// 安全导航操作符
	// 使用符号?
	// 来自Groovy的语法.
	// 主要是用来防止抛出空指针异常的,若是无法求值,就返回null.
	@Test
	public void test14()
	{
		Expression expression = parser.parseExpression("list?.get(10)");
		Object value = expression.getValue(evaluationContext, user);
		System.out.println(value);
	}



	// 集合选择器
	// .?[ selection expression ]
	//
	@Test
	public void test15()
	{
		Expression expression = parser.parseExpression("list.?[#this>1]");
		Object value = expression.getValue(evaluationContext, userxml);
		System.out.println(value);
	}

	// 集合转换器
	// .![ projection expression ]
	//
	@Test
	public void test16()
	{
		Expression expression = parser.parseExpression("list.![#this>2]");
		Object value = expression.getValue(evaluationContext, userxml);
		System.out.println(value);
	}


	// 使用spel的模板环境.
	// #{ spel expression }
	// 可查看接口ParserContext,及其实现类TemplateParserContext.
	@Test
	public void test17()
	{
		Expression expression =
				parser.parseExpression("随机求取的值是:#{T(Math).random()}",
						new TemplateParserContext());
		Object value = expression.getValue();
		System.out.println(value);
	}

}