# Spring 表达式语言 ## Spring 表达式语言 你可以通过使用[Spring Expression Language](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#expressions)中编写的表达式来配置许多 Spring 集成组件。 在大多数情况下,`#root`对象是`Message`,它有两个属性(`headers`和`payload`),允许这样的表达式,如`payload`,`payload.thing`,`headers['my.header']`,以此类推。 在某些情况下,提供了额外的变量。例如,``提供`#requestParams`(来自 HTTP 请求的参数)和`#pathVariables`(来自 URI 中的路径占位符的值)。 对于所有 SPEL 表达式,可以使用`BeanResolver`来启用对应用程序上下文中的任何 Bean 的引用(例如,`@myBean.foo(payload)`)。此外,还有两个`PropertyAccessors`可用。`MapAccessor`允许通过使用一个键和`ReflectivePropertyAccessor`访问`Map`中的值,这允许访问字段和 JavaBean 兼容的属性(通过使用 getter 和 setter)。这就是访问`Message`标头和有效负载属性的方法。 ### spel 评估上下文定制 从 Spring Integration3.0 开始,你可以向框架使用的 SPEL 评估上下文添加额外的`PropertyAccessor`实例。该框架提供(只读)`JsonPropertyAccessor`,你可以使用它从`JsonNode`或`String`中的 JSON 访问字段。如果你有特定的需求,也可以创建自己的`PropertyAccessor`。 此外,你还可以添加自定义功能。自定义函数是在类上声明的`static`方法。函数和属性访问器在整个框架中使用的任何 SPEL 表达式中都是可用的。 下面的配置显示了如何使用自定义属性访问器和函数直接配置`IntegrationEvaluationContextFactoryBean`: ``` ``` Spring 为了方便起见,集成为属性访问器和函数提供了名称空间支持,如下文所述。该框架自动为你配置工厂 Bean。 这个工厂 Bean 定义覆盖了默认的`integrationEvaluationContext` Bean 定义。它将自定义访问器和一个自定义函数添加到列表中(其中还包括标准访问器[前面提到过](#spel))。 请注意,自定义函数是静态方法。在前面的示例中,自定义函数是在一个名为`MyFunctions`的类上的一个名为`calc`的静态方法,并接受类型为`MyThing`的单个参数。 假设你有一个`Message`,其有效负载的类型为`MyThing`。进一步假设你需要执行一些操作来从`MyThing`创建一个名为`MyObject`的对象,然后在该对象上调用一个名为`calc`的自定义函数。 标准属性访问器不知道如何从`MyThing`获取`MyObject`,因此你可以编写并配置一个自定义属性访问器来执行此操作。因此,你的最终表达式可能是`"#barcalc(payload.myObject)"`。 工厂 Bean 有另一个属性(`typeLocator`),它允许你自定义在 SPEL 求值期间使用的`TypeLocator`。你可能需要在某些使用非标准`ClassLoader`的环境中运行这样做。在下面的示例中,SPEL 表达式总是使用 Bean 工厂的类装入器: ``` ``` ### spel 函数 Spring 集成提供了名称空间支持,以允许你创建 SPEL 自定义函数。你可以指定``组件来为整个框架中使用的[自定义 SPEL 函数](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#expressions-ref-functions)提供`EvaluationContext`。你可以添加一个或多个这些组件,而不是配置前面所示的工厂 Bean,并且框架会自动将它们添加到默认的`integrationEvaluationContext`工厂 Bean 中。 例如,假设你有一个有用的静态方法来计算 XPath。下面的示例展示了如何创建一个自定义函数来使用该方法: ``` ``` 给出了前面的例子: * ID 为`integrationEvaluationContext`的默认`IntegrationEvaluationContextFactoryBean` Bean 已在应用程序上下文中注册。 * 将``解析并添加到`functions`的`Map`中,作为一个映射条目,其`id`作为键,而静态`Method`作为值。 * `integrationEvaluationContext`工厂 Bean 创建了一个新的`StandardEvaluationContext`实例,并配置了默认的`PropertyAccessor`实例、`BeanResolver`实例和自定义函数。 * 将`EvaluationContext`实例注入到`ExpressionEvaluatingTransformer` Bean 中。 要通过使用 Java 配置提供一个 SPEL 函数,你可以为每个函数声明一个`SpelFunctionFactoryBean` Bean。下面的示例展示了如何创建自定义函数: ``` @Bean public SpelFunctionFactoryBean xpath() { return new SpelFunctionFactoryBean(XPathUtils.class, "evaluate"); } ``` | |在父上下文中声明的 SPEL 函数也可以在任意子上下文中使用,
每个上下文都有自己的`integrationEvaluationContext`工厂 Bean 实例,因为每个上下文都需要一个不同的`BeanResolver`,但是函数声明是继承的,可以通过声明同名的 SPEL 函数来重写。| |---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| #### 内置 spel 函数 Spring 集成提供了 FolloiWNG 标准功能,这些功能在启动时自动注册到应用程序上下文中: * `#jsonPath`:在指定的对象上计算“jsonpath”。这个函数调用`JsonPathUtils.evaluate(…​)`,将其委托给[Jayway JsonPath 库](https://github.com/json-path/JsonPath)。下面的清单展示了一些使用示例: ``` ``` `#jsonPath`还支持第三个(可选的)参数:[`com.jayway.jsonpath.Filter`](https://github.com/json-path/jsonpath#filter-predicates)的数组,它可以通过引用 Bean 或 Bean 方法(例如)来提供。 | |使用此函数需要 Jayway JsonPath 库(`json-path.jar`)位于 Classpath 上。
否则将不注册`#jsonPath`spel 函数。| |---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| 有关 JSON 的更多信息,请参见[变压器](./transformer.html#transformer)中的“JSON Transformers”。 * `#xpath`:在某些提供的对象上计算“XPath”。有关 XML 和 XPath 的更多信息,请参见[XML 支持-处理 XML 有效负载](./xml.html#xml)。 ### 属性访问器 Spring 集成提供了名称空间支持,以允许你创建 SPEL 自定义[`PropertyAccessor`](https://DOCS. Spring.io/ Spring/DOCS/current/javadoc-api/org/springframework/expression/propertyaccessor.html)实现。你可以使用``组件为整个框架中使用的`PropertyAccessor`实例提供自定义`PropertyAccessor`实例的列表。你可以添加一个或多个这些组件,而不是配置前面所示的工厂 Bean,并且框架会自动将访问器添加到默认的`integrationEvaluationContext`工厂 Bean。下面的示例展示了如何做到这一点: ``` ``` 在前面的示例中,两个自定义`PropertyAccessor`实例被注入到`EvaluationContext`中(以它们被声明的顺序)。 要通过使用 Java 配置提供`PropertyAccessor`实例,你应该声明一个名为`SpelPropertyAccessorRegistrar` Bean 的`spelPropertyAccessorRegistrar`(由`IntegrationContextUtils.SPEL_PROPERTY_ACCESSOR_REGISTRAR_BEAN_NAME`常量指定)。下面的示例展示了如何使用 Java 配置两个自定义`PropertyAccessor`实例: ``` @Bean public SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() { return new SpelPropertyAccessorRegistrar(new JsonPropertyAccessor()) .add(fooPropertyAccessor()); } ``` | |在父上下文中声明的自定义`PropertyAccessor`实例也可用于任意子上下文。
它们被放置在结果列表的末尾(但在默认`org.springframework.context.expression.MapAccessor`之前)并且`o.s.expression.spel.support.ReflectivePropertyAccessor`)。
如果在子上下文中声明一个具有相同 Bean ID 的`PropertyAccessor`,则它将覆盖父访问器。
在``中声明的 bean 必须具有一个“id”属性。
使用的最终顺序如下:

当前上下文中的访问者,按照它们被声明为

* 来自父上下文的任何访问器的顺序,按照

*`MapAccessor`
* 的顺序| |---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|