type
status
date
slug
summary
tags
category
icon
password

1、概述

Ognl 是一个功能强大的表达式语言,用来获取和设置 Java 对象的属性 ,它旨在提供一个更高抽象度语法来对 Java 对象图进行导航。
Java 中很多可以做的事情,也可以使用 OGNL 来完成,并且 OGNL 可以用更简洁的语法来完成对 Java 对象的导航。通常来说:通过一个 “路径” 来完成对象信息的导航,这个 “路径” 可以是到 java bean 的某个属性,或者集合中的某个索引的对象,等等,而不是直接使用 get 或者 set 方法来完成。
例如同样是获取 Map 中某个对象的属性,用 Java 语言表示出来如下:
而使用 OGNL 表达式则为:
除了简单清晰以外,OGNL 有着更高的环境适应性。我们可以将 OGNL 表达式应用在配置文件、XML文件等处,而只要在解析这些文件时使用 OGNL 进行解析即可。例如,下面所示的一段 XML 配置中,test条件的判断就使用了 OGNL 表达式。
Java 中使用了 OGNL 的常见的框架/项目:

2、Ognl语法

OGNL 的三要素:
  • 表达式(Expression):表达式是整个 OGNL 的核心内容,所有的 OGNL 操作都是针对表达式解析后进行的。通过表达式来告诉 OGNL 操作到底要干些什么。因此,表达式其实是一个带有语法含义的字符串,整个字符串将规定操作的类型和内容。OGNL 表达式支持大量的表达式,如 “链式访问对象”、表达式计算、甚至还支持 Lambda 表达式。
  • Root 对象:OGNL 的 Root 对象可以理解为 OGNL 的操作对象。当我们指定了一个表达式的时候,我们需要指定这个表达式针对的是哪个具体的对象。而这个具体的对象就是 Root 对象,这就意味着,如果有一个 OGNL 表达式,那么我们需要针对 Root 对象来进行 OGNL 表达式的计算并且返回结果。
  • 上下文环境:有个 Root 对象和表达式,我们就可以使用 OGNL 进行简单的操作了,如对 Root 对象的赋值与取值操作。但是,实际上在 OGNL 的内部,所有的操作都会在一个特定的数据环境中运行。这个数据环境就是上下文环境(Context)。OGNL 的上下文环境是一个 Map 结构,称之为 OgnlContext。Root 对象也会被添加到上下文环境当中去。说白了上下文就是一个 MAP 结构,它实现了 java.utils.Map 的接口。
如下所示是一个 OGNL 的实例
OGNL语法:
  • .操作符:如上所示,可以调用对象的属性和方法, hacker.name,且上一个节点的结果作为下一个节点的上下文,如(#a=new java.lang.String("calc")).(@java.lang.Runtime@getRuntime().exec(#a)),也可以换成逗号(#a=new java.lang.String("calc")),(@java.lang.Runtime@getRuntime().exec(#a))
  • @操作符:用于调用静态对象、静态方法、静态变量,@java.lang.Math@abs(-10)
  • #操作符:
    • 用于调用非root对象
    • 创建Map
    • 定义变量
  • $操作符:一般用于配置文件,<param name="name">${name}</param>
  • %操作符:计算其中的OGNL表达式,%{hacker.name}
  • List:直接使用{"green", "red", "blue"}创建
  • 对象创建:new java.lang.String[]{"foobar"}

3、Ognl实战

3.1 对象定位

我们知道在 java 中,一切都是对象,所以我们的 ognl 表达式必然是着手于某一个对象的,通常在 ognl 中,可以将待执行目标对象划分为三类
  • 简单对象:(如基本数据类型,String)
  • 非简单对象:(非简单对象,实例访问)
  • 静态对象:(静态类)
在 gonl 的语法中,上面三种 case,根据不同的开头来标记

3.1.1 静态对象

简单来说就是我想访问静态类的某个方法(或者静态类的成员)
语法规则为根据@开始,后面接上完整的类名
一个实例 case 如下,相当于 java 代码中直接调用Math.max(10, 20)

3.1.2 非简单对象

访问一个普通对象的成员 or 方法
语法规则为根据#开头,后面为对象名(说明,这个对象需要在 Ognl 的上下文中,且可以根据对象名可以唯一定位)

3.1.3 简单对象

即基本类型的对象访问,不加任何前缀,直接使用即可,如下

3.2 方法调用

执行目标对象的某个方法,规则如下

3.3 成员访问

访问目标对象的成员,规则如下

3.4 集合

ognl 针对常用的集合进行了特殊的支持

3.4.1 List

通过 {} 创建列表,通过 [] 来访问对象下标的元素
下面表示创建一个列表,有三个元素: 1,2,3; 获取列表中下标为 2 的元素

3.4.2 Arrays

数组,可以结合 new 来使用

3.4.3 Map

#{k:v, k:v} 方式来创建 map
下面的语句,表示创建一个 map,并获取其中 key 为 name 的元素

3.5 表达式语句

前面是一些简单的,基本的成员访问,方法调用,除此之外还存在更牛逼的用法,支持表达式的执行

3.5.1 成员赋值

3.5.2 表达式计算

3.5.3 三目运算符

3.5.4 集合支持

针对集合做了一些简化,方便调用

3.5.5 对象创建

可以直接通过 new 来创建一个对象,当我们需要执行的目标方法的参数为非基本类型时,可能会非常好用

3.5.6 链式语句

什么是链式语句呢?
有点类似设计模式中的 Builder 模式,我要执行一串的操作,最后获取目标
定义规则如下,圆括号包裹起来,中间用逗号分隔,依次执行,最后一个为需要返回的目标
结合上面的对象创建,可以实现非常强大的功能
直接创建一个可用的 User 对象,下面执行完毕之后,直接获取一个属性被初始化后的 User 对象

3.5.7 lambda 表达式

这个有点高端了,首先是定义 lambda 表达式,然后借助前面的链式方式调用,下面是一个阶乘的 case
在Java中使用Ognl教程使用Arthas查看和修改Spring容器对象
mcbilla
mcbilla
一个普通的干饭人🍚
Announcement
type
status
date
slug
summary
tags
category
icon
password
🎉欢迎来到飙戈的博客🎉
-- 感谢您的支持 ---
👏欢迎学习交流👏