值表示式基礎知識
值表示式是 Spring Expression Language (SpEL) 和 Property Placeholder Resolution 的組合。它們結合了程式化表示式的強大評估功能,以及依賴屬性佔位符解析從 Environment
(例如組態屬性)取得值的簡便性。
表示式預期由受信任的輸入(例如註解值)定義,而不是從使用者輸入決定。
以下程式碼示範如何在註解的環境中使用表示式。
@Document("orders-#{tenantService.getOrderCollection()}-${tenant-config.suffix}")
class Order {
// …
}
值表示式可以從單獨的 SpEL 表示式、屬性佔位符或混合各種表示式(包括文字)的複合表示式定義。
#{tenantService.getOrderCollection()} (1)
#{(1+1) + '-hello-world'} (2)
${tenant-config.suffix} (3)
orders-${tenant-config.suffix} (4)
#{tenantService.getOrderCollection()}-${tenant-config.suffix} (5)
1 | 使用單一 SpEL 表示式的值表示式。 |
2 | 使用靜態 SpEL 表示式評估為 2-hello-world 的值表示式。 |
3 | 使用單一屬性佔位符的值表示式。 |
4 | 由文字 orders- 和屬性佔位符 ${tenant-config.suffix} 組成的複合表示式。 |
5 | 使用 SpEL、屬性佔位符和文字的複合表示式。 |
使用值表示式為您的程式碼引入了很大的彈性。這樣做需要在每次使用時評估表示式,因此,值表示式評估會對效能概況產生影響。 |
剖析與評估
值表示式由 ValueExpressionParser
API 剖析。ValueExpression
的實例是執行緒安全的,並且可以快取以供稍後使用,以避免重複剖析。
以下範例顯示值表示式 API 用法
-
Java
-
Kotlin
ValueParserConfiguration configuration = SpelExpressionParser::new;
ValueEvaluationContext context = ValueEvaluationContext.of(environment, evaluationContext);
ValueExpressionParser parser = ValueExpressionParser.create(configuration);
ValueExpression expression = parser.parse("Hello, World");
Object result = expression.evaluate(context);
val configuration = ValueParserConfiguration { SpelExpressionParser() }
val context = ValueEvaluationContext.of(environment, evaluationContext)
val parser = ValueExpressionParser.create(configuration)
val expression: ValueExpression = parser.parse("Hello, World")
val result: Any = expression.evaluate(context)
SpEL 表示式
SpEL 表示式 遵循範本樣式,其中表示式預期包含在 #{…}
格式中。表示式使用 EvaluationContext
進行評估,該內容由 EvaluationContextProvider
提供。內容本身是功能強大的 StandardEvaluationContext
,允許廣泛的操作、存取靜態類型和內容擴充功能。
請務必僅剖析和評估來自受信任來源(例如註解)的表示式。接受使用者提供的表示式可能會建立一個入口路徑,以利用應用程式環境和您的系統,從而導致潛在的安全性漏洞。 |
擴充評估內容
EvaluationContextProvider
及其反應式變體 ReactiveEvaluationContextProvider
提供對 EvaluationContext
的存取。ExtensionAwareEvaluationContextProvider
及其反應式變體 ReactiveExtensionAwareEvaluationContextProvider
是預設實作,可從應用程式環境(特別是 ListableBeanFactory
)判斷內容擴充功能。
擴充功能實作 EvaluationContextExtension
或 ReactiveEvaluationContextExtension
,以提供擴充功能支援以水合 EvaluationContext
。這些是根物件、屬性和函數(最上層方法)。
以下範例顯示內容擴充功能,該功能提供根物件、屬性、函數和別名函數。
EvaluationContextExtension
-
Java
-
Kotlin
@Component
public class MyExtension implements EvaluationContextExtension {
@Override
public String getExtensionId() {
return "my-extension";
}
@Override
public Object getRootObject() {
return new CustomExtensionRootObject();
}
@Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put("key", "Hello");
return properties;
}
@Override
public Map<String, Function> getFunctions() {
Map<String, Function> functions = new HashMap<>();
try {
functions.put("aliasedMethod", new Function(getClass().getMethod("extensionMethod")));
return functions;
} catch (Exception o_O) {
throw new RuntimeException(o_O);
}
}
public static String extensionMethod() {
return "Hello World";
}
public static int add(int i1, int i2) {
return i1 + i2;
}
}
public class CustomExtensionRootObject {
public boolean rootObjectInstanceMethod() {
return true;
}
}
@Component
class MyExtension : EvaluationContextExtension {
override fun getExtensionId(): String {
return "my-extension"
}
override fun getRootObject(): Any? {
return CustomExtensionRootObject()
}
override fun getProperties(): Map<String, Any> {
val properties: MutableMap<String, Any> = HashMap()
properties["key"] = "Hello"
return properties
}
override fun getFunctions(): Map<String, Function> {
val functions: MutableMap<String, Function> = HashMap()
try {
functions["aliasedMethod"] = Function(javaClass.getMethod("extensionMethod"))
return functions
} catch (o_O: Exception) {
throw RuntimeException(o_O)
}
}
companion object {
fun extensionMethod(): String {
return "Hello World"
}
fun add(i1: Int, i2: Int): Int {
return i1 + i2
}
}
}
class CustomExtensionRootObject {
fun rootObjectInstanceMethod(): Boolean {
return true
}
}
註冊上述顯示的擴充功能後,您可以使用其匯出的方法、屬性和根物件來評估 SpEL 表示式
#{add(1, 2)} (1)
#{extensionMethod()} (2)
#{aliasedMethod()} (3)
#{key} (4)
#{rootObjectInstanceMethod()} (5)
1 | 調用 MyExtension 宣告的 add 方法,結果為 3 ,因為該方法會新增兩個數值參數並傳回總和。 |
2 | 調用 MyExtension 宣告的 extensionMethod 方法,結果為 Hello World 。 |
3 | 調用 aliasedMethod 方法。該方法作為函數公開,並重新導向到 MyExtension 宣告的 extensionMethod 方法,結果為 Hello World 。 |
4 | 評估 key 屬性,結果為 Hello 。 |
5 | 在根物件實例 CustomExtensionRootObject 上調用 rootObjectInstanceMethod 方法。 |
您可以在 SecurityEvaluationContextExtension
找到真實世界的內容擴充功能。
屬性佔位符
遵循 ${…}
形式的屬性佔位符通常指的是由 PropertySource
透過 Environment
提供的屬性。屬性可用於解析系統屬性、應用程式組態檔、環境組態或由秘密管理系統貢獻的屬性來源。您可以在 Spring Framework 關於 @Value
用法的說明文件中找到有關屬性佔位符的更多詳細資訊。