Beginning Spring学习笔记——第9章 SpEL
来源:互联网 发布:淘宝滥发信息怎么申诉 编辑:程序博客网 时间:2024/06/14 13:55
使用SpEL配置应用程序
本章使用的依赖基本被下文件包括:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.springframework.samples.service.service</groupId> <artifactId>SpringAOPTest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <!-- Generic properties --> <java.version>1.6</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- Web --> <jsp.version>2.3.1</jsp.version> <jstl.version>1.2</jstl.version> <servlet.version>3.1.0</servlet.version> <!-- Spring --> <spring-framework.version>4.3.10.RELEASE</spring-framework.version> <!-- Hibernate / JPA --> <hibernate.version>5.2.10.Final</hibernate.version> <!-- Logging --> <logback.version>1.2.3</logback.version> <slf4j.version>1.7.25</slf4j.version> <!-- Test --> <junit.version>4.12</junit.version> <!-- AspectJ --> <aspectj.version>1.8.10</aspectj.version> </properties> <dependencies> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring-framework.version}</version> </dependency> <!-- Other Web dependencies --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>${jsp.version}</version> <scope>provided</scope> </dependency> <!-- Spring and Transactions --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring-framework.version}</version> </dependency> <!-- Logging with SLF4J & LogBack --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> <scope>runtime</scope> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <!-- Test Artifacts --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring-framework.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- AspectJ --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </project>
首先在src/main/resource文件夹下创建上下文配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="show1" class="com.wiley.beginningspring.ch9.MyBean"> <property name="message" value="#{systemProperties['user.language']}" /> </bean></beans>
此处将类MyBean定义成了名为show1的类,并向其中的message属性通过SpEL注入了系统属性中的用户语言。
接下来创建MyBean类。
public class MyBean { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; }}
然后就可以在Main类中测试配置了。
public class Main { public static void main(String... args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); MyBean myBean = context.getBean(MyBean.class); System.out.println(myBean.getMessage()); }}
输出结果为zh,用户语言为中文。项目目录结构很简单:
事实上,也可以用注解完成配置,此时的配置类为:
@Configuration@ComponentScan(basePackages = {"com.wiley.beginningspring.ch9"})public class ApplicationConfig {}
而MyBean类需要在类定义时被定义为一个Spring Bean:
@Componentpublic class MyBean { @Value("#{systemProperties['user.language']}") private String message; public String getMessage() { return message; }}
其中message属性上通过@Value注解使用相同的SpEL语句注入了用户语言的值。
创建一个分析器
SpEL上下文中定义的表达式都应该首先被ExpressionParser解析然后被评估,该分析器对象是线程安全的。默认情况下,表达式模板以‘#’开头,‘}’结尾。分析器对象创建如下: ExpressionParser parser = new SpELExpressionParser();
创建完分析器实例后就可以用它的parseExpression方法解析一个表达式创建一个表达式实例: Expression expression = parser.parseExpression("'Hello World'");
然后就可以通过它的getValue方法获得表达式评估的值: String value = expression.getValue(String.class)
下用 SpEL 解析一个 Hello World:
public class HelloWorldTest { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void helloWorldParsedOK() { Expression expression = parser.parseExpression("'Hello World!'"); String value = expression.getValue(String.class); assertThat(value, is("Hello World!")); }}
测试通过。
通过SpEL调用方法
xml配置中调用方法
项目目录结构为:
首先在src/main/resource文件夹中创建applicationContext.xml文件。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="show1" class="com.wiley.beginningspring.ch9.Show"> <property name="instrument" value="Piano" /> <property name="song" value="Turning Tables" /> </bean> <bean id="show2" class="com.wiley.beginningspring.ch9.Show"> <property name="instrument" value="Guitar" /> <property name="song" value="#{show2.guitarSong()}" /> </bean></beans>
该上下文文件中定义了两个类为Show的Bean。分别用字符串常量和SpEL表达式调用方法注入了值。
然后创建Show类:
public class Show { private String instrument; private String song; public void setInstrument(String instrument) { this.instrument = instrument; } public void setSong(String song) { this.song = song; } public String guitarSong() { return "More Than Words"; } public void present() { System.out.println("Playing " + song + " with instrument " + instrument); }}
然后创建Main方法执行程序:
public class Main { public static void main(String... args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Show show1 = (Show) context.getBean("show1"); show1.present(); Show show2 = (Show) context.getBean("show2"); show2.present(); }}
运行输出结果:
在字符串上调用方法及链接调用
public class NestedMethodInvocationStringConcatTest { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void helloParsedAndConcatenatedWithWorldAndThenLengthMethodInvoked() { Expression exp = parser.parseExpression("'Hello'.concat(' World!').length()"); Integer value = exp.getValue(Integer.class); assertThat(value, is(12)); }}
调用构造函数
public class ConstructorInvocationTest { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void constructorInvocationWorksOK() { Expression exp = parser.parseExpression("new Double(3.141592653589793)"); Double value = exp.getValue(Double.class); assertThat(value, is(3.141592653589793)); }}
调用静态方法
public class StaticConstantFieldAccessTest { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void staticConstantFieldAccessWorksOK() { Expression exp = parser.parseExpression("T(java.lang.Math).PI"); Double value = exp.getValue(Double.class); assertThat(value, is(3.141592653589793)); }}
使用变量和函数
可以通过context.setVariable("name",...)
注册一个变量到评估上下文StandardEvaluationContext对象中,之后就可以在变量名前加#引用已经注册的变量了。
#root
可以在评估上下文中设置一个根对象,当表达式中遇到未知方法和属性时使用该对象进行查找。
public class RootVariablesTests { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void rootVariableRegisteredOK() { StandardEvaluationContext context = new StandardEvaluationContext(); context.setRootObject(new MyBean()); assertTrue(parser.parseExpression("#root").getValue(context) instanceof MyBean); }}
其中MyBean为任意类。
public class MyBean {}
#this
提供对当前评估过程的引用。
访问一同属性和环境变量
使用前缀@来访问:
String value = parser.parseExpression("@systemEnvironment[JAVA_HOME]").getValue(context, String.class);String value = parser.parseExpression("@systemProperties['java.version']").getValue(context, String.class);
内联列表
public class InlineListTests { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void inlineListCreatedOK() { List<Integer> value = parser.parseExpression("{1,2,3}").getValue(List.class); assertThat(value, hasItems(1, 2, 3)); } @Test public void inlineListOfListsCreatedOK() { List<List<Integer>> value = parser.parseExpression("{{1,2},{3,4},{5,6}}").getValue(List.class); assertThat(value, hasItems(Arrays.asList(1,2), Arrays.asList(3,4), Arrays.asList(5,6))); }}
注册函数
除了注册变量外还可以注册函数,并在之后调用。注册方法为context.registerFunction("name",method)
public class FunctionRegistrationTests { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void functionRegisteredOK() throws NoSuchMethodException { StandardEvaluationContext context = new StandardEvaluationContext(); context.registerFunction("capitalize", StringUtils.class.getDeclaredMethod("capitalize", new Class[] { String.class })); String value = parser.parseExpression("#capitalize('hello')").getValue(context, String.class); assertThat(value, is("Hello")); }}
SpEL运算符
- 关系:
<, >, <=, >=, ==, !=, lt, gt, le, ge, eq, ne
- 算数:
+, -, *, /, %, ^
- 逻辑:
&&, ||, !, and, or, not, between, instanceof
- 条件:
? : (ternary), ? : (elvis)
- 其他类型:
?.(safe navigation), ?[...](selection), ![...](projection), ^[...](first element), $[...](last element)
其中 instantceof 可以用来判定表达式是否为某个类的实例,如"'Hello' instanceof T(String)"
返回一个true值的Boolean变量。
安全导航运算符用于在嵌套属性上进行导航,使未初始化的属性返回null值而不是抛出SpelEvaluationException。如
public class SafeNavigationOperatorsTest { ExpressionParser p; @Before public void setup() { p = new SpelExpressionParser(); } @Test public void safeNavigationOperatorsWorkOK() { Employee employee = new Employee("Mert"); StandardEvaluationContext context = new StandardEvaluationContext(employee); assertThat(p.parseExpression("Address?.Name").getValue(context, String.class), is(nullValue())); }}
利用之前提到的#this还可以进行集合选择与投影将其转换为另一个集合。
@Test public void collectionSelectedOK() { StandardEvaluationContext context = new StandardEvaluationContext(); context.setRootObject(Arrays.asList(1,2,3,4,5,6,7,8,9)); List<Integer> evenNumbers = parser.parseExpression("#root.?[#this%2 == 0 ?: false]").getValue(context, List.class); assertThat(evenNumbers, hasItems(2, 4, 6, 8)); }
其中#this用来遍历集合中元素。
还可以通过![…]将一个集合投影到另一个集合,如下:
public class Worker { private String name; private Country birthPlace; public Worker(String name, Country birthPlace) { this.name = name; this.birthPlace = birthPlace; } public String getName() { return name; } public Country getBirthPlace() { return birthPlace; }}public enum Country { TR, USA, DE}
投影Worker到Country:
@Test public void collectionProjectedOK() { StandardEvaluationContext context = new StandardEvaluationContext(); context.setRootObject(Arrays.asList( new Worker("Mert", Country.DE), new Worker("Funda", Country.TR), new Worker("Tugce", Country.USA))); List<Country> birthPlaces = parser.parseExpression("#root.![#this.birthPlace]").getValue(context, List.class); assertThat(birthPlaces, hasItems(Country.TR, Country.USA, Country.DE)); }
使用SpEL中的实用工具
访问Spring Bean
在Bean名称前添加@来访问
public class SpringBeanAccessTests { ExpressionParser parser; @Before public void setup() { parser = new SpelExpressionParser(); } @Test public void springBeanAccessWorksOK() { StandardEvaluationContext context = new StandardEvaluationContext(); context.setBeanResolver(new BeanFactoryResolver(new AnnotationConfigApplicationContext(ApplicationConfig.class))); Expression exp = parser.parseExpression("@myBean.sayHello()"); String value = exp.getValue(context, String.class); assertThat(value, is("Hello!")); }}@Componentpublic class MyBean { public String sayHello() { return "Hello!"; }}@Configuration@ComponentScan(basePackages = {"com.wiley.beginningspring.ch9"})public class ApplicationConfig {}
<spring:eval>
使用spring.tld中的该标签可以将评估值显示到JSP页面或为变量分配值。
<body> <spring:eval expression = "@MyBean.sayHi()"/></body>
- Beginning Spring学习笔记——第9章 SpEL
- Beginning Spring学习笔记——第1章
- Beginning Spring学习笔记——第10章 缓存
- Beginning Spring学习笔记——第2章(一)Spring IoC容器
- Beginning Spring学习笔记——第2章(三)Spring的Bean管理
- Beginning Spring学习笔记——第3章(一)Spring MVC基础
- Beginning Spring学习笔记——第4章(一)Spring JDBC连接的配置
- Beginning Spring学习笔记——第5章(二)Spring的JPA支持
- Beginning Spring学习笔记——第6章(一)Spring事务管理基础
- Beginning Spring学习笔记——第7章 使用Spring进行测试驱动开发
- Beginning Spring学习笔记——第8章 Spring AOP
- Beginning Spring学习笔记——第2章(二)依赖注入
- Beginning Spring学习笔记——第3章(二)表单处理
- Beginning Spring学习笔记——第5章(一)ORM和JPA基础
- Beginning Spring学习笔记——第4章(二)使用Spring执行数据访问操作
- Beginning Spring学习笔记——第6章(二)使用Spring进行声明式事务管理
- Beginning Spring学习笔记——第6章(三)使用Spring进行编程式事务管理
- Beginning Spring学习笔记——第11章 使用Spring开发REST风格的Web服务
- CentOS安装php加速软件Zend Optimizer 3.3.9
- QT graphics
- 数据结构编程笔记十八:第七章 图 图的邻接矩阵存储表示及各基本操作的实现
- 【PAT甲级】1004. Counting Leaves (30)——JAVA实现
- 自定义QGraphicsItem选中样式
- Beginning Spring学习笔记——第9章 SpEL
- 内存管理
- Redis学习笔记--Redis持久化
- VC6.0 Release 版本下调试运行设置
- java mac系统下寻找 java 和jdk的安装路径
- zTree -- jQuery 树插件 使用方法与例子
- env: node: No such file or directory的解决办法
- java 图形用户界面设计 之 改变主题 示例代码
- 2.分而治之