`
jinnianshilongnian
  • 浏览: 21468724 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2411748
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3003019
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5635656
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:258906
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1595176
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:249651
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5852841
Group-logo
跟我学Nginx+Lua开...
浏览量:700210
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:782891
社区版块
存档分类
最新评论

【第五章】Spring表达式语言 之 5.1 概述 5.2 SpEL基础 ——跟我学spring3

 
阅读更多

5.1  概述

5.1.1  概述

       Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”,类似于Struts2x中使用的OGNL表达式语言,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等等,并且能与Spring功能完美整合,如能用来配置Bean定义。

       表达式语言给静态Java语言增加了动态功能。

       SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。

5.1.2  能干什么

       表达式语言一般是用最简单的形式完成最主要的工作,减少我们的工作量。

       SpEL支持如下表达式:

一、基本表达式:字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算及Elivis表达式、正则表达式、括号优先级表达式;

二、类相关表达式:类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用;

三、集合相关表达式:内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;

四、其他表达式:模板表达式。

注:SpEL表达式中的关键字是不区分大小写的。

5.2  SpEL基础

5.2.1  HelloWorld

       首先准备支持SpEL的Jar包:“org.springframework.expression-3.0.5.RELEASE.jar”将其添加到类路径中。

       SpEL在求表达式值时一般分为四步,其中第三步可选:首先构造一个解析器,其次解析器解析字符串表达式,在此构造上下文,最后根据上下文得到表达式运算后的值。

       让我们看下代码片段吧:

 

 

java代码:
package cn.javass.spring.chapter5;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class SpELTest {
    @Test
    public void helloWorld() {
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression =
parser.parseExpression("('Hello' + ' World').concat(#end)");
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("end", "!");
        Assert.assertEquals("Hello World!", expression.getValue(context));
    }
}

 

接下来让我们分析下代码:

1)创建解析器:SpEL使用ExpressionParser接口表示解析器,提供SpelExpressionParser默认实现;

2)解析表达式:使用ExpressionParser的parseExpression来解析相应的表达式为Expression对象。

3)构造上下文:准备比如变量定义等等表达式需要的上下文数据。

4)求值:通过Expression接口的getValue方法根据上下文获得表达式值。

 

是不是很简单,接下来让我们看下其具体实现及原理吧。

5.2.3  SpEL原理及接口

       SpEL提供简单的接口从而简化用户使用,在介绍原理前让我们学习下几个概念:

       一、表达式:表达式是表达式语言的核心,所以表达式语言都是围绕表达式进行的,从我们角度来看是“干什么”;

       二、解析器:用于将字符串表达式解析为表达式对象,从我们角度来看是“谁来干”;

       三、上下文:表达式对象执行的环境,该环境可能定义变量、定义自定义函数、提供类型转换等等,从我们角度看是“在哪干”;

       四、根对象及活动上下文对象:根对象是默认的活动上下文对象,活动上下文对象表示了当前表达式操作的对象,从我们角度看是“对谁干”。

       理解了这些概念后,让我们看下SpEL如何工作的呢,如图5-1所示:

 

图5-1 工作原理

       1)首先定义表达式:“1+2”;

       2)定义解析器ExpressionParser实现,SpEL提供默认实现SpelExpressionParser;

       2.1)SpelExpressionParser解析器内部使用Tokenizer类进行词法分析,即把字符串流分析为记号流,记号在SpEL使用Token类来表示;

       2.2)有了记号流后,解析器便可根据记号流生成内部抽象语法树;在SpEL中语法树节点由SpelNode接口实现代表:如OpPlus表示加操作节点、IntLiteral表示int型字面量节点;使用SpelNodel实现组成了抽象语法树;

       2.3)对外提供Expression接口来简化表示抽象语法树,从而隐藏内部实现细节,并提供getValue简单方法用于获取表达式值;SpEL提供默认实现为SpelExpression;

       3)定义表达式上下文对象(可选),SpEL使用EvaluationContext接口表示上下文对象,用于设置根对象、自定义变量、自定义函数、类型转换器等,SpEL提供默认实现StandardEvaluationContext;

4)使用表达式对象根据上下文对象(可选)求值(调用表达式对象的getValue方法)获得结果。

接下来让我们看下SpEL的主要接口吧:

1)ExpressionParser接口:表示解析器,默认实现是org.springframework.expression.spel.standard包中的SpelExpressionParser类,使用parseExpression方法将字符串表达式转换为Expression对象,对于ParserContext接口用于定义字符串表达式是不是模板,及模板开始与结束字符:

 

java代码:
public interface ExpressionParser {
       Expression parseExpression(String expressionString);
       Expression parseExpression(String expressionString, ParserContext context);
}

 

 

来看下示例:

 

java代码:
	
@Test
public void testParserContext() {
    ExpressionParser parser = new SpelExpressionParser();
    ParserContext parserContext = new ParserContext() {
        @Override
         public boolean isTemplate() {
            return true;
        }
        @Override
        public String getExpressionPrefix() {
            return "#{";
        }
        @Override
        public String getExpressionSuffix() {
            return "}";
        }
    };
    String template = "#{'Hello '}#{'World!'}";
    Expression expression = parser.parseExpression(template, parserContext);
    Assert.assertEquals("Hello World!", expression.getValue());
}

 

 

在此我们演示的是使用ParserContext的情况,此处定义了ParserContext实现:定义表达式是模块,表达式前缀为“#{”,后缀为“}”;使用parseExpression解析时传入的模板必须以“#{”开头,以“}”结尾,如"#{'Hello '}#{'World!'}"。

默认传入的字符串表达式不是模板形式,如之前演示的Hello World。

 

2)EvaluationContext接口:表示上下文环境,默认实现是org.springframework.expression.spel.support包中的StandardEvaluationContext类,使用setRootObject方法来设置根对象,使用setVariable方法来注册自定义变量,使用registerFunction来注册自定义函数等等。

 

3)Expression接口:表示表达式对象,默认实现是org.springframework.expression.spel.standard包中的SpelExpression,提供getValue方法用于获取表达式值,提供setValue方法用于设置对象值。

了解了SpEL原理及接口,接下来的事情就是SpEL语法了。

分享到:
评论
7 楼 c532876091 2017-04-11  
6 楼 thf913134326 2016-07-07  
5 楼 mapc我 2016-04-04  
楼主好厉害
4 楼 至尊宝_唯一 2014-03-22  
我用3.2的版本跑第一个实例:
java.lang.NullPointerException
at java.lang.String.concat(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:69)
at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:97)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:81)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:93)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:67)
at com.neil.TespSpEL.testSpELValue(TespSpEL.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:71)
at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

麻烦指导一下呢,谢谢
3 楼 307622798 2012-11-28  
jinnianshilongnian 写道
307622798 写道
楼主,他这个表达式的解析跟编译原理的自动机的原理是不是很像啊?去看他的解析感觉很难啊,呵呵

是的 就是那块知识

o(︶︿︶)o 唉,你说我当时怎么就不好好学一下编译原理呢,那时候不会还可以当面问老师,当时觉得难就不学,现在后悔了啊!呵呵
2 楼 jinnianshilongnian 2012-11-28  
307622798 写道
楼主,他这个表达式的解析跟编译原理的自动机的原理是不是很像啊?去看他的解析感觉很难啊,呵呵

是的 就是那块知识
1 楼 307622798 2012-11-28  
楼主,他这个表达式的解析跟编译原理的自动机的原理是不是很像啊?去看他的解析感觉很难啊,呵呵

相关推荐

    跟开涛学Spring

    1.15 【第五章】Spring表达式语言 之 5.1 概述 5.2 SpEL基础 ——跟我学spring3 . . . . . . . . . . . . . . .177 1.16 【第五章】Spring表达式语言 之 5.3 SpEL语法 ——跟我学spring3 . . . . . . . . . . . . ....

    Spring表达式语言中文参考手册.docx

    Spring Expression Language (SpEL)中文文档。基于Spring4.x。

    spring spEL 表达式详解

    Spring Expression Language,简称SpEL,是Spring框架中的一个强大表达式语言,用于在运行时查询和操作对象图。它提供了丰富的表达式语法,支持属性访问、方法调用、算术运算、逻辑判断以及控制流等操作,极大地简化...

    spring3.0.2api 文档spring表达式语言

    在本文中,我们将深入探讨Spring 3.0.2 API文档中的核心组件,特别是Spring表达式语言(SpEL),它是Spring框架中的一个强大工具,用于在运行时查询和操作对象图。 Spring表达式语言(Spring Expression Language,...

    Spring开发手册_表达式语言_API中文版

    **Spring 表达式语言(SpEL)API 中文版** Spring 表达式语言(Spring Expression Language,简称 SpEL)是 Spring 框架中一个强大的表达式系统,用于在运行时查询和操作对象图。它允许动态访问和修改对象属性、...

    Spring表达式语言.pdf

    ### Spring表达式语言(SpEL)详解 #### 引言 Spring框架自3.0版本引入了一种全新的配置对象依赖注入的方式—Spring表达式语言(SpEL),这为开发人员提供了一个灵活且强大的工具,使得在配置文件或注解中进行复杂的...

    Spring_SpEl表达式使用用例

    Spring Expression Language (SpEL)是Spring框架中的一种强大而灵活的表达式语言,主要用于在运行时查询和操作对象图。它提供了在配置元数据中进行表达式评估的能力,使得我们可以更加动态地控制Spring应用程序的...

    基于SpringBoot、Spring表达式语言 (SpEL)、annotation的操作日志框架+源代码+文档说明

    基于SpringBoot、Spring表达式语言 (SpEL)、annotation的操作日志 ### 简介 * 使用annotation来标注方法,标记操作内容 * 使用SpEL来动态生成操作日志内容,使操作日志记录更加详细(记录操作内容ID等关键信息) * ...

    跟我学spring3 .pdf

    《跟我学Spring3》这本书是针对Spring框架进行深入解析的一本教程,涵盖了Spring的核心特性,包括IoC(Inversion of Control,控制反转)、DI(Dependency Injection,依赖注入)、AOP(Aspect-Oriented Programming...

    Spring表达式语言SpEL用法详解

    Spring表达式语言SpEL用法详解 Spring表达式语言SpEL是一种强大的表达式语言,支持运行时查询和操作对象图。SpEL使用#{...}作为定界符,所有在大括号中的字符串均被认为是SpEL。SpEL为bean的属性进行动态赋值提供了...

    opt-log:基于SpringBoot、Spring表达式语言 (SpEL)、annotation的操作日志框架

    opt-log基于SpringBoot、Spring表达式语言 (SpEL)、annotation的操作日志简介使用annotation来标注方法,标记操作内容使用SpEL来动态生成操作日志内容,使操作日志记录更加详细(记录操作内容ID等关键信息)同一个...

    Spring-Framework-5.2.x Maven版本

    - **Spring Expression Language (SpEL)增强**:SpEL在5.2.x中进行了扩展,添加了更多表达式操作,如日期和时间操作、流控制以及更强大的类型安全访问。 **3. 调试Spring源码** 由于这个压缩包已经去除了`spring-...

    跟我学spring3(1-7)1

    《跟我学Spring3》是针对Spring框架的入门教程,主要涵盖了Spring的核心特性:IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入),以及AOP(Aspect-Oriented Programming,面向切面编程...

    跟我学spring3(1-7)

    《跟我学Spring3》系列教程涵盖了Spring框架的核心概念和技术,包括IoC(Inversion of Control,控制反转)、DI(Dependency Injection,依赖注入)、资源管理、Spring表达式语言(SpEL)以及面向切面编程(AOP)等...

    跟我学spring3(总共13章)13

    《跟我学Spring3》是针对初学者和有一定基础的开发者设计的一套全面、深入的教程,共计13个章节,涵盖了Spring3的核心概念和技术。Spring3作为Java开发中备受推崇的框架,它提供了丰富的功能,包括依赖注入、AOP...

    跟我学spring3

    《跟我学Spring3》这本书是针对初学者和中级开发者的一份宝贵资源,旨在深入浅出地介绍Spring框架的精髓和核心概念。Spring是Java企业级应用开发中的一个关键框架,它简化了应用程序的构建,提供了依赖注入、面向切...

    跟我学Spring3

    《跟我学Spring3》这本书是针对Java开发人员深入学习Spring框架第三版的一份教程。Spring作为Java企业级应用开发中的核心框架,它以其强大的功能、灵活性和模块化设计深受开发者喜爱。Spring3版本在前一版本基础上...

Global site tag (gtag.js) - Google Analytics