1. MEL的优势
在Mule ESB上有很多方法可以操作Mule Message,比如Java语言或者其他脚本语言(比如JavaScript等)。但是MEL表达式是Mule推荐使用,在Mule应用中的一个统一和标准的方法。
- MEL表达式为开发人员提供了一个一致的标准化语言,用来访问和计算Mule Message的Payload(负载),Property(属性)和Variable(变量)。
- MEL基于Mule特定的对象,Studio中提供auto-complete(自动完成,语法提示)的功能,帮助开发者快速编码。
- 更重要的是,Mule的绝大多数组件都支持MEL,比如路由组件,过滤组件等。
MEL的示例,这个示例在在Mule的Logger组件中使用MEL表达式获取FlowVars。
从下图可以看到,我们在Logger组件中使用MEL表达式,能够提供语法提示,该提示带出了上一步设定的customerNo变量。
XML配置如下:
<flow name="mel-flow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
<set-variable variableName="customerNo" value="#[1008]" doc:name="customerNo"/>
<logger message="The customerNo is #[flowVars.customerNo]" level="INFO" doc:name="Logger"/>
</flow>
注意:MEL是一种表达式,和脚本语言类似,但并不相同。表达式通常用于动态获取值或者设定值,或对数据进行简单的操作。表达式语言和脚本语言之间在功能上存在重叠,但如果您编写的内容非常复杂,需要的不仅仅是几行代码,或者您需要包含条件逻辑,那么脚本语言通常会更有用。如果简单的获取或设定值,调用方法或执行函数,则使用表达式则更方便。
2. MEL的使用场景
MEL表达式常用的使用场景大概可以分成三种。
- 获取值
#[payload]
- 表示获取message的负载
#[message.inboundProperties.'http.query.params'.customerNo]
- 表示获取查询参数customerNo
#[payload.callMethod(parameters)
- 表示调用payload对象的callMethod方法,并获取方法返回值
#[xpath('//root/element')]
- 表示使用xpath语法解析并获取相应节点内容。
- 条件比较,返回的结果就是布尔变量
#[payload.amount > 2000]
#[message.inboundProperties.'http.method' == 'GET']
- 表示判断HTTP请求是不是GET方法
- 设定值,通常用于Message Enricher组件。
#[flowVars.dbResult]
- 这里表示相应的值设定到dbResult变量中。
3. MEL的示例
-
使用表达式提取值,根据消息的内容,属性决定执行流程。在下面的示例中,payload是一个Java对象,我们根据购买类型,将订单分发路由到不同的JMS消息队列中。
<choice> <when expression="#[payload.getOrderType() == 'book']"> <jms:outbound-endpoint queue="bookQueue" /> </when> <when expression="#[payload.getOrderType() == 'music']"> <jms:outbound-endpoint queue="musicQueue" /> </when> </choice>
-
使用表达式提取值,并将值传递给Connector,如下示例就是使用MEL计算的值设定SMTP Connector的邮件标题,邮件接收人等。
<smtp:outbound-endpoint from="#[flowVars.mailFrom]" to="#[flowVars.mailTo]" subject="#[payload.mailSubject]" doc:name="SMTP"/>
-
如果payload是Java对象,可以调用payload方法,获取方法的返回值。示例就说调用calAmount方法,并打印计算出来的金额。
<logger message="#[payload.calAmount()]" />
4. MEL的上下文对象
我们在上述的MEL表达式示例中可以看到MEL有多个部分组成,第一部分就是上下文对象。MEL常见的上下文对象如下:
上下文对象 | 说明 |
---|---|
#[server] | 当前服务器,可以获取服务器的时间,JDK版本等,如#[server.dateTime],#[server.javaVersion] |
#[mule] | 当前Mule实例,可以获取Mule的版本,目录等。如#[mule.version] |
#[app] | 当前Mule应用的实例,可以获取应用的名称等。如#[app.name] |
#[message] | 这个是我们最经常使用的对象,就说Mule message。如#[message.payload],#[message.inboundProperties.'http.query.params'.customerNo]等 |
server上下文对象的常用属性:
Field | Field描述 |
---|---|
dateTime | 系统当前时间 |
host | 主机名 |
ip | 主机IP |
osName | 操作系统名称 |
userName | 当前用户 |
userDir | 当前用户工作目录 |
mule上下文对象的常用属性:
Field | Field描述 |
---|---|
home | Mule Runtime的安装目录 |
version | Mule Runtime的版本 |
nodeId | 集群下的本机ID |
clusterId | 集群ID |
app上下文对象的常用属性:
Field | Field描述 |
---|---|
name | Mule App应用名称 |
workdir | Mule App工作目录 |
message上下文对象的常用属性:
Field | Field描述 |
---|---|
id | message的唯一ID |
rootId | message的根ID |
payload | message的负载 |
inboundProperties | message的inbound头信息 |
inboundAttachments | message的inbound附件信息 |
outboundProperties | message的outbound头信息 |
outboundAttachments | message的outbound附件信息 |
5. MEL的Variable
不同于第4点提到的上下文对象,MEL中还可以使用变量,使用变量并不要求在表达式中使用上下文对象。变量是顶层的标识符。MEL中常见的变量如下:
- flowVars - flowVars的有效范围是在一个Flow中,定义flowVars之后,后续的Message Processor都可以使用。
- sessionVars - 在跨Flow通信时,可以使用sessionVars来传递变量。需要注意的是,sessionVars并不总是有效的,其实取决于Inboud Endpoint的类型。后续再出专题介绍flowVars和sessionVars等之间的区别。
#[flowVars.foo = sessionVars.bar]
上述的表达式的意思是,将session变量赋值给flow变量。
6. MEL访问属性
-
点语法。适用对象通常是Java Pojo。MEL中可以使用点语法来访问相关的对象属性,同样对象属性的属性也是可以用点号来访问的。
#[message.payload.item.name]
-
Null安全性访问。Java编程中经常遇到NullPointerException错误,也就是说对空对象进行访问操作会报错。而在MEL表达式,可以通过点语法.?来避免出错。如下示例,即使item为null,该表达式仍然不会报错,它会返回null值。
#[message.payload.?item.name]
-
属性名称的转义。如果属性名称有特殊字符,那么使用点语法会遇到问题,这个时候可以单引号进行转义。如下示例,http.query.params是一个整体。我们访问这个属性名,必须使用单引号进行转义。
#[message.inboundProperties.'http.query.params'.customerNo]
-
中括号语法。如果对象是数组,或者Map,那么可以使用中括号进行访问
#[payload[5]]
#[payload['userName']]
7. MEL操作符
常用的操作符如下,和普通的开发语言类似。还有更多的操作符可以查阅官方手册。
- 算术运算符 + - / * %
- 比较运算符 == != > < >= <=
- 逻辑运算符 && ||