This is an automated email from the ASF dual-hosted git repository.

zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 065fe17c51f Refactor `shardingsphere-infra-expr` to expose the use of 
Row Value Expressions SPI (#28340)
065fe17c51f is described below

commit 065fe17c51f39614ccba11383fed772f381a2d78
Author: Ling Hengqian <[email protected]>
AuthorDate: Sat Sep 23 21:03:29 2023 +0800

    Refactor `shardingsphere-infra-expr` to expose the use of Row Value 
Expressions SPI (#28340)
    
    * Refactor `shardingsphere-infra-expr` to expose the use of SPI
    
    * Add doc for Row Value Expressions SPI
---
 docs/document/content/dev-manual/sharding.cn.md    |  17 +++
 docs/document/content/dev-manual/sharding.en.md    |  17 +++
 docs/document/content/faq/_index.cn.md             |   2 +-
 docs/document/content/faq/_index.en.md             |   3 +-
 .../content/features/sharding/concept.cn.md        |   7 ++
 .../content/features/sharding/concept.en.md        |   9 ++
 .../common-config/builtin-algorithm/expr.cn.md     |  64 ++++++++++
 .../common-config/builtin-algorithm/expr.en.md     |  66 ++++++++++
 .../common-config/builtin-algorithm/sharding.cn.md |   2 +-
 .../common-config/builtin-algorithm/sharding.en.md |   3 +-
 .../startup/graalvm-native-image.cn.md             |   7 +-
 .../startup/graalvm-native-image.en.md             |  12 +-
 ...ReadwriteSplittingRuleConfigurationChecker.java |   4 +-
 .../rule/ReadwriteSplittingRule.java               |   6 +-
 .../sharding/hint/HintInlineShardingAlgorithm.java |   4 +-
 .../inline/ComplexInlineShardingAlgorithm.java     |   4 +-
 .../sharding/inline/InlineShardingAlgorithm.java   |   4 +-
 .../shardingsphere/sharding/rule/ShardingRule.java |   4 +-
 .../shardingsphere/sharding/rule/TableRule.java    |   4 +-
 .../checker/ShardingTableRuleStatementChecker.java |  10 +-
 .../sharding/CoreHintShardingAlgorithmFixture.java |   4 +-
 infra/expr/core/pom.xml                            |   7 +-
 .../expr/core/InlineExpressionParserFactory.java   |  36 +++++-
 .../core/InlineExpressionParserFactoryTest.java    |  49 +++++---
 .../CustomInlineExpressionParserFixture.java       |  63 ++++++++++
 ...ingsphere.infra.expr.spi.InlineExpressionParser |   2 +-
 infra/expr/espresso/pom.xml                        |  12 ++
 .../espresso/EspressoInlineExpressionParser.java   |  42 +++++--
 .../EspressoInlineExpressionParserTest.java        |  43 +++++--
 infra/expr/{hotsopt => groovy}/pom.xml             |   8 +-
 .../expr/groovy/GroovyInlineExpressionParser.java} |  54 ++++++--
 ...ingsphere.infra.expr.spi.InlineExpressionParser |   2 +-
 .../groovy/GroovyInlineExpressionParserTest.java   | 139 +++++++++++++++++++++
 .../hotsopt/HotspotInlineExpressionParserTest.java | 120 ------------------
 infra/expr/pom.xml                                 |   4 +-
 infra/expr/purelist/pom.xml                        |   6 +-
 .../purelist/PureListInlineExpressionParser.java   |  22 ++--
 .../PureListInlineExpressionParserTest.java        |  28 ++++-
 .../infra/expr/spi/InlineExpressionParser.java     |  24 ++--
 pom.xml                                            |   8 --
 .../ShardingRuleConfigurationImportChecker.java    |   4 +-
 .../test/e2e/cases/dataset/DataSet.java            |   2 +-
 .../engine/composer/BatchE2EContainerComposer.java |   2 +-
 .../test/e2e/engine/type/DDLE2EIT.java             |   2 +-
 .../test/e2e/engine/type/dml/BaseDMLE2EIT.java     |   2 +-
 .../test/e2e/env/DataSetEnvironmentManager.java    |   2 +-
 46 files changed, 679 insertions(+), 257 deletions(-)

diff --git a/docs/document/content/dev-manual/sharding.cn.md 
b/docs/document/content/dev-manual/sharding.cn.md
index dfac191b287..e419ccafd2b 100644
--- a/docs/document/content/dev-manual/sharding.cn.md
+++ b/docs/document/content/dev-manual/sharding.cn.md
@@ -79,3 +79,20 @@ chapter = true
 
|--------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 | DatabaseTimestampService | 从数据库中获取当前时间进行路由    | 
[`org.apache.shardingsphere.timeservice.type.database.DatabaseTimestampService`](https://github.com/apache/shardingsphere/blob/master/kernel/time-service/type/database/src/main/java/org/apache/shardingsphere/timeservice/type/database/DatabaseTimestampService.java)
 |
 | SystemTimestampService   | 从应用系统时间中获取当前时间进行路由 | 
[`org.apache.shardingsphere.timeservice.type.system.SystemTimestampService`](https://github.com/apache/shardingsphere/blob/master/kernel/time-service/type/system/src/main/java/org/apache/shardingsphere/timeservice/type/system/SystemTimestampService.java)
           |
+
+## InlineExpressionParser
+
+### 全限定类名
+
+`org.apache.shardingsphere.infra.expr.core.InlineExpressionParser`
+
+### 定义
+
+解析行表达式
+
+### 已知实现
+
+| *配置标识*   | *详细说明*            | *全限定类名*                                       
                                 |
+|----------|-------------------|--------------------------------------------------------------------------------|
+| GROOVY   | 使用 Groovy 语法的行表达式 | 
`org.apache.shardingsphere.infra.expr.groovy.GroovyInlineExpressionParser`     |
+| PURELIST | 使用标准列表的行表达式       | 
`org.apache.shardingsphere.infra.expr.purelist.PureListInlineExpressionParser` |
diff --git a/docs/document/content/dev-manual/sharding.en.md 
b/docs/document/content/dev-manual/sharding.en.md
index aeadbfae502..0463e27c40c 100644
--- a/docs/document/content/dev-manual/sharding.en.md
+++ b/docs/document/content/dev-manual/sharding.en.md
@@ -79,3 +79,20 @@ Obtain the current date for routing definition
 
|--------------------------|--------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 | DatabaseTimestampService | Get the current time from the database for 
routing           | 
[`org.apache.shardingsphere.timeservice.type.database.DatabaseTimestampService`](https://github.com/apache/shardingsphere/blob/master/kernel/time-service/type/database/src/main/java/org/apache/shardingsphere/timeservice/type/database/DatabaseTimestampService.java)
 |
 | SystemTimestampService   | Get the current time from the application system 
for routing | 
[`org.apache.shardingsphere.timeservice.type.system.SystemTimestampService`](https://github.com/apache/shardingsphere/blob/master/kernel/time-service/type/system/src/main/java/org/apache/shardingsphere/timeservice/type/system/SystemTimestampService.java)
           |
+
+## InlineExpressionParser
+
+### Fully-qualified class name
+
+`org.apache.shardingsphere.infra.expr.core.InlineExpressionParser`
+
+### Definition
+
+Row Value Expressions definition
+
+### Implementation classes
+
+| *Configuration Type* | *Description*                                     | 
*Fully-qualified class name*                                                   |
+|----------------------|---------------------------------------------------|--------------------------------------------------------------------------------|
+| GROOVY               | Row Value Expressions that uses the Groovy syntax | 
`org.apache.shardingsphere.infra.expr.groovy.GroovyInlineExpressionParser`     |
+| PURELIST             | Row Value Expressions that uses a standard list   | 
`org.apache.shardingsphere.infra.expr.purelist.PureListInlineExpressionParser` |
diff --git a/docs/document/content/faq/_index.cn.md 
b/docs/document/content/faq/_index.cn.md
index d5e3865a03a..3797a58860e 100644
--- a/docs/document/content/faq/_index.cn.md
+++ b/docs/document/content/faq/_index.cn.md
@@ -122,7 +122,7 @@ DROP DATABASE sharding_db;
 
 回答:
 
-行表达式标识符可以使用 `${...}` 或 `$->{...}`,但前者与 Spring 本身的属性文件占位符冲突,因此在 Spring 
环境中使用行表达式标识符建议使用 `$->{...}`。
+使用 `InlineExpressionParser` SPI 的默认实现的行表达式标识符可以使用 `${...}` 或 `$->{...}`,但前者与 
Spring 本身的属性文件占位符冲突,因此在 Spring 环境中使用行表达式标识符建议使用 `$->{...}`。
 
 ### [分片] inline 表达式返回结果为何出现浮点数?
 
diff --git a/docs/document/content/faq/_index.en.md 
b/docs/document/content/faq/_index.en.md
index f6e7d01b238..1bcf0ffbbf3 100644
--- a/docs/document/content/faq/_index.en.md
+++ b/docs/document/content/faq/_index.en.md
@@ -130,7 +130,8 @@ Answer:
 
 Answer:
 
-`${...}` or `$->{...}` can be used in inline expression identifiers, but the 
former one clashes with place holders in Spring property files, so `$->{...}` 
is recommended to be used in Spring as inline expression identifiers.
+`${...}` or `$->{...}` can be used in inline expression identifiers using the 
default implementation of the 
+`InlineExpressionParser` SPI, but the former one clashes with place holders in 
Spring property files, so `$->{...}` is recommended to be used in Spring as 
inline expression identifiers.
 
 ### [Sharding] Why does float number appear in the return result of inline 
expression?
 
diff --git a/docs/document/content/features/sharding/concept.cn.md 
b/docs/document/content/features/sharding/concept.cn.md
index 66cc22c6a80..194dd2ab7bb 100644
--- a/docs/document/content/features/sharding/concept.cn.md
+++ b/docs/document/content/features/sharding/concept.cn.md
@@ -159,6 +159,13 @@ db0.t_order0, db0.t_order1, db1.t_order2, db1.t_order3, 
db1.t_order4
 
 对于常见的分片算法,使用 Java 代码实现并不有助于配置的统一管理。 通过行表达式书写分片算法,可以有效地将规则配置一同存放,更加易于浏览与存储。
 
+行表达式作为字符串由两部分组成,分别是字符串开头的对应 SPI 实现的 Type Name 部分和表达式部分。 以 
`<GROOVY>t_order_${1..3}` 为例,字符
+串`<GROOVY>` 部分的子字符串 `GROOVY` 为此行表达式使用的对应 SPI 实现的 Type Name,其被  `<>` 
符号包裹来识别。而字符串 `t_order_${1..3}`
+为此行表达式的表达式部分。当行表达式不指定 Type Name 时,例如 `t_order_${1..3}`,行表示式默认将使用 
`InlineExpressionParser` SPI 的 
+`GROOVY` 实现来解析表达式。
+
+以下部分介绍 `GROOVY` 实现的语法规则。
+
 行表达式的使用非常直观,只需要在配置中使用 `${ expression }` 或 `$->{ expression }` 标识行表达式即可。 
目前支持数据节点和分片算法这两个部分的配置。 行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。 例如:
 
 `${begin..end}` 表示范围区间
diff --git a/docs/document/content/features/sharding/concept.en.md 
b/docs/document/content/features/sharding/concept.en.md
index e5da2668f3d..b72ad2219bb 100644
--- a/docs/document/content/features/sharding/concept.en.md
+++ b/docs/document/content/features/sharding/concept.en.md
@@ -159,6 +159,15 @@ Row expressions are designed to address the two main 
issues of configuration sim
 
 For the common sharding algorithm, using Java code implementation does not 
help to manage the configuration uniformly. But by writing the sharding 
algorithm through line expressions, the rule configuration can be effectively 
stored together, which is easier to browse and store.
 
+A Row Value Expressions consists of two parts as a string, the Type Name part 
of the corresponding SPI implementation at the beginning of the string and the 
expression part.
+
+Take `<GROOVY>t_order_${1..3}` as sample, the `GROOVY` substring in the part 
of the `<GROOVY>` string is the Type Name used by the corresponding SPI 
implementation for this Row Value Expressions, which is identified by the `<>` 
symbol.
+And the `t_order_${1..3}` string is the expression part of this Row Value 
Expressions. When a Row Value Expressions does
+not specify a Type Name, such as `t_order_${1..3}`, the Row Value Expressions 
defaults to parse expressions by `GROOVY` implementation for 
`InlineExpressionParser` SPI.
+
+The following sections describe the syntax rules for the `GROOVY` 
implementation.
+
+
 Row expressions are very intuitive, just use `${ expression }` or `$->{ 
expression }` in the configuration to identify the row expressions. Data nodes 
and sharding algorithms are currently supported. The content of row expressions 
uses Groovy syntax, and all operations supported by Groovy are supported by row 
expressions. For example:
 
 `${begin..end}` denotes the range interval
diff --git 
a/docs/document/content/user-manual/common-config/builtin-algorithm/expr.cn.md 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.cn.md
new file mode 100644
index 00000000000..c55718e6b57
--- /dev/null
+++ 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.cn.md
@@ -0,0 +1,64 @@
++++
+title = "行表达式"
+weight = 7
++++
+
+## 使用 Groovy 语法的行表达式
+
+类型:GROOVY
+
+可配置属性:
+
+无
+
+## 使用标准列表的行表达式
+
+类型:PURELIST
+
+可配置属性:
+
+无
+
+## 操作步骤
+
+使用需要使用 `行表达式` 的属性时, 如在 `数据分片` 功能中, 在 `actualDataNodes` 属性下指明特定的 SPI 实现的 Type 
Name 即可。
+
+若 `行表达式` 不指明 SPI 的 Type Name,默认将使用 `GROOVY` 的 SPI 实现。
+
+## 配置示例
+
+```yaml
+rules:
+- !SHARDING
+  tables:
+    t_order: 
+      actualDataNodes: <PURELIST>ds_0.t_order_0, ds_0.t_order_1, 
ds_1.t_order_0, ds_1.t_order_1
+      tableStrategy: 
+        standard:
+          shardingColumn: order_id
+          shardingAlgorithmName: t_order_inline
+      keyGenerateStrategy:
+        column: order_id
+        keyGeneratorName: snowflake
+  defaultDatabaseStrategy:
+    standard:
+      shardingColumn: user_id
+      shardingAlgorithmName: database_inline
+  shardingAlgorithms:
+    database_inline:
+      type: INLINE
+      props:
+        algorithm-expression: <GROOVY>ds_${user_id % 2}
+    t_order_inline:
+      type: INLINE
+      props:
+        algorithm-expression: <GROOVY>t_order_${order_id % 2}
+  keyGenerators:
+    snowflake:
+      type: SNOWFLAKE
+```
+
+## 相关参考
+
+- [核心概念](/docs/document/content/features/sharding/concept.cn.md)
+- [数据分片](/docs/document/content/dev-manual/sharding.cn.md)
diff --git 
a/docs/document/content/user-manual/common-config/builtin-algorithm/expr.en.md 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.en.md
new file mode 100644
index 00000000000..216ce754d39
--- /dev/null
+++ 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.en.md
@@ -0,0 +1,66 @@
++++
+title = "Row Value Expressions"
+weight = 7
++++
+
+## Row Value Expressions that uses the Groovy syntax
+
+Type: GROOVY
+
+Attributes:
+
+None
+
+## Row Value Expressions that uses a standard list
+
+Type: PURELIST
+
+Attributes:
+
+None
+
+## Procedure
+
+When using attributes that require the use of `Row Value Expressions`, such as 
in the `data sharding` feature, it is 
+sufficient to indicate the Type Name of the specific SPI implementation under 
the `actualDataNodes` attribute.
+
+If the `Row Value Expressions` does not indicate the Type Name of the SPI, the 
SPI implementation of `GROOVY` will be 
+used by default.
+
+## Sample
+
+```yaml
+rules:
+- !SHARDING
+  tables:
+    t_order: 
+      actualDataNodes: <PURELIST>ds_0.t_order_0, ds_0.t_order_1, 
ds_1.t_order_0, ds_1.t_order_1
+      tableStrategy: 
+        standard:
+          shardingColumn: order_id
+          shardingAlgorithmName: t_order_inline
+      keyGenerateStrategy:
+        column: order_id
+        keyGeneratorName: snowflake
+  defaultDatabaseStrategy:
+    standard:
+      shardingColumn: user_id
+      shardingAlgorithmName: database_inline
+  shardingAlgorithms:
+    database_inline:
+      type: INLINE
+      props:
+        algorithm-expression: <GROOVY>ds_${user_id % 2}
+    t_order_inline:
+      type: INLINE
+      props:
+        algorithm-expression: <GROOVY>t_order_${order_id % 2}
+  keyGenerators:
+    snowflake:
+      type: SNOWFLAKE
+```
+
+## Related References
+
+- [Core Concept](/docs/document/content/features/sharding/concept.en.md)
+- [Data Sharding](/docs/document/content/dev-manual/sharding.en.md)
diff --git 
a/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.cn.md
 
b/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.cn.md
index ba4a751c8ad..0cd29976d13 100644
--- 
a/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.cn.md
+++ 
b/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.cn.md
@@ -73,7 +73,7 @@ Apache ShardingSphere 内置的标准分片算法实现类包括:
 
 #### 行表达式分片算法
 
-使用 Groovy 的表达式,提供对 SQL 语句中的 `=` 和 `IN` 的分片操作支持,只支持单分片键。
+使用 `InlineExpressionParser` SPI 的默认实现的 Groovy 的表达式,提供对 SQL 语句中的 `=` 和 `IN` 
的分片操作支持,只支持单分片键。
 对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的 Java 代码开发,如: `t_user_$->{u_id % 8}` 表示 `t_user` 
表根据 `u_id` 模 8,而分成 8 张表,表名称为 `t_user_0` 到 `t_user_7`。
 详情请参见[行表达式](/cn/dev-manual/sharding/#implementation-classes)。
 
diff --git 
a/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.en.md
 
b/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.en.md
index 7ba7d66d793..4c1e7bae245 100644
--- 
a/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.en.md
+++ 
b/docs/document/content/user-manual/common-config/builtin-algorithm/sharding.en.md
@@ -75,7 +75,8 @@ Apache ShardingSphere built-in standard sharding algorithm 
are:
 
 #### Inline Sharding Algorithm
 
-With Groovy expressions, `InlineShardingStrategy` provides single-key support 
for the sharding operation of `=` and `IN` in SQL.
+With Groovy expressions that uses the default implementation of the 
`InlineExpressionParser` SPI, 
+`InlineShardingStrategy` provides single-key support for the sharding 
operation of `=` and `IN` in SQL.
 Simple sharding algorithms can be used through a simple configuration to avoid 
laborious Java code developments.
 For example, `t_user_$->{u_id % 8}` means table t_user is divided into 8 
tables according to u_id, with table names from `t_user_0` to `t_user_7`.
 Please refer to [Inline 
Expression](/en/dev-manual/sharding/#implementation-classes) for more details.
diff --git 
a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md
 
b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md
index 973e550be69..501f9f99d00 100644
--- 
a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md
+++ 
b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.cn.md
@@ -37,9 +37,10 @@ services:
     - 
`org.apache.shardingsphere.sharding.algorithm.sharding.inline.ComplexInlineShardingAlgorithm`
     - 
`org.apache.shardingsphere.sharding.algorithm.sharding.hint.HintInlineShardingAlgorithm`
 
-- 当前阶段,GraalVM Native Image 形态的 ShardingSphere Proxy 不支持使用带 Groovy
-  语法的 `行表达式`, 这首先导致 `数据分片` 功能的`actualDataNodes`属性只能使用纯列表来配置, 例如 
`ds_0.t_order_0, ds_0.t_order_1`
-  或 `ds_0.t_user_0, ds_15.t_user_1023`。此问题在 
https://github.com/oracle/graal/issues/5522 追踪。
+- 当前阶段,GraalVM Native Image 形态的 ShardingSphere Proxy 不支持使用 
`InlineExpressionParser` SPI 的默认实现的 `行表达式`, 
+  这首先导致 `数据分片` 功能的`actualDataNodes` 属性只能使用其他 `InlineExpressionParser` SPI 
的实现来配置, 例如使用
+ `InlineExpressionParser` SPI 实现为 `PURELIST` 的 `行表达式`, 即 
`<PURELIST>ds_0.t_order_0, ds_0.t_order_1`
+  或 `<PURELIST>ds_0.t_user_0, ds_15.t_user_1023`。
 
 - 本节假定处于 Linux(amd64,aarch64), MacOS(amd64)或 Windows(amd64)环境。
   如果你位于 MacOS(aarch64/M1) 环境,你需要关注尚未关闭的 
https://github.com/oracle/graal/issues/2666 。
diff --git 
a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md
 
b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md
index 993d9dcd482..fe0d38acfa8 100644
--- 
a/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md
+++ 
b/docs/document/content/user-manual/shardingsphere-proxy/startup/graalvm-native-image.en.md
@@ -42,16 +42,18 @@ services:
     - 
`org.apache.shardingsphere.sharding.algorithm.sharding.inline.ComplexInlineShardingAlgorithm`
     - 
`org.apache.shardingsphere.sharding.algorithm.sharding.hint.HintInlineShardingAlgorithm`
 
-- At this stage, ShardingSphere Proxy in the form of GraalVM Native Image does 
not support the use
-  of `Row Value Expressions` with Groovy syntax, which first results in the 
`actualDataNodes` property of the `Sharding`
-  feature being only configurable using a pure list, such as `ds_0.t_order_0, 
ds_0.t_order_1`
-  or `ds_0.t_user_0, ds_15.t_user_1023`. This issue is tracked in 
https://github.com/oracle/graal/issues/5522 .
+- At this stage, ShardingSphere Proxy in the form of GraalVM Native Image does 
not support `row expressions` using the 
+  default implementation of the `InlineExpressionParser` SPI.
+  This first results in the `actualDataNodes` property of the `data sharding` 
feature that can only be configured using 
+  other implementations of the `InlineExpressionParser` SPI, for example using 
`PURELIST` implemented 
+  `InlineExpressionParser` SPI for `row expression`, i.e. 
`<PURELIST>ds_0.t_order_0, ds_0.t_order_1`
+  or `<PURELIST>ds_0.t_user_0, ds_15.t_user_1023`.
 
 - This section assumes a Linux (amd64, aarch64), MacOS (amd64) or Windows 
(amd64) environment.
   If you are on MacOS (aarch64/M1) environment, you need to follow 
https://github.com/oracle/graal/issues/2666 which is
   not closed yet.
 
-- 'org.apache.shardingsphere:shardingsphere-cluster-mode-repository-etcd' is 
affected by
+- `org.apache.shardingsphere:shardingsphere-cluster-mode-repository-etcd` is 
affected by
   https://github.com/micronaut-projects/micronaut-gcp/issues/532 and cannot be 
used.
 
 ## Premise
diff --git 
a/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/checker/ReadwriteSplittingRuleConfigurationChecker.java
 
b/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/checker/ReadwriteSplittingRuleConfigurationChecker.java
index ed9fb2a2a9b..984a472bb09 100644
--- 
a/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/checker/ReadwriteSplittingRuleConfigurationChecker.java
+++ 
b/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/checker/ReadwriteSplittingRuleConfigurationChecker.java
@@ -79,7 +79,7 @@ public final class ReadwriteSplittingRuleConfigurationChecker 
implements RuleCon
     
     private void checkWriteDataSourceNames(final String databaseName, final 
Map<String, DataSource> dataSourceMap, final Collection<String> 
addedWriteDataSourceNames,
                                            final 
ReadwriteSplittingDataSourceRuleConfiguration config, final 
Collection<ShardingSphereRule> rules) {
-        for (String each : 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(config.getWriteDataSourceName()))
 {
+        for (String each : 
InlineExpressionParserFactory.newInstance(config.getWriteDataSourceName()).splitAndEvaluate())
 {
             
ShardingSpherePreconditions.checkState(dataSourceMap.containsKey(each) || 
containsInOtherRules(each, rules),
                     () -> new 
DataSourceNameExistedException(String.format("Write data source name `%s` not 
in database `%s`.", each, databaseName)));
             
ShardingSpherePreconditions.checkState(addedWriteDataSourceNames.add(each),
@@ -97,7 +97,7 @@ public final class ReadwriteSplittingRuleConfigurationChecker 
implements RuleCon
     }
     
     private void checkReadeDataSourceNames(final String databaseName, final 
Map<String, DataSource> dataSourceMap, final Collection<String> 
addedReadDataSourceNames, final String readDataSourceName) {
-        for (String each : 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(readDataSourceName))
 {
+        for (String each : 
InlineExpressionParserFactory.newInstance(readDataSourceName).splitAndEvaluate())
 {
             
ShardingSpherePreconditions.checkState(dataSourceMap.containsKey(each),
                     () -> new 
DataSourceNameExistedException(String.format("Read data source name `%s` not in 
database `%s`.", each, databaseName)));
             
ShardingSpherePreconditions.checkState(addedReadDataSourceNames.add(each),
diff --git 
a/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/rule/ReadwriteSplittingRule.java
 
b/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/rule/ReadwriteSplittingRule.java
index db9bad0d737..68ec5cb4267 100644
--- 
a/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/rule/ReadwriteSplittingRule.java
+++ 
b/features/readwrite-splitting/core/src/main/java/org/apache/shardingsphere/readwritesplitting/rule/ReadwriteSplittingRule.java
@@ -103,10 +103,10 @@ public final class ReadwriteSplittingRule implements 
DatabaseRule, DataSourceCon
     
     private Map<String, ReadwriteSplittingDataSourceRule> 
createStaticDataSourceRules(final ReadwriteSplittingDataSourceRuleConfiguration 
config,
                                                                                
       final ReadQueryLoadBalanceAlgorithm loadBalanceAlgorithm) {
-        List<String> inlineReadwriteDataSourceNames = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(config.getName());
-        List<String> inlineWriteDatasourceNames = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(config.getWriteDataSourceName());
+        List<String> inlineReadwriteDataSourceNames = 
InlineExpressionParserFactory.newInstance(config.getName()).splitAndEvaluate();
+        List<String> inlineWriteDatasourceNames = 
InlineExpressionParserFactory.newInstance(config.getWriteDataSourceName()).splitAndEvaluate();
         List<List<String>> inlineReadDatasourceNames = 
config.getReadDataSourceNames().stream()
-                .map(each -> 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(each)).collect(Collectors.toList());
+                .map(each -> 
InlineExpressionParserFactory.newInstance(each).splitAndEvaluate()).collect(Collectors.toList());
         
ShardingSpherePreconditions.checkState(inlineWriteDatasourceNames.size() == 
inlineReadwriteDataSourceNames.size(),
                 () -> new 
InvalidInlineExpressionDataSourceNameException("Inline expression write data 
source names size error."));
         inlineReadDatasourceNames.forEach(each -> 
ShardingSpherePreconditions.checkState(each.size() == 
inlineReadwriteDataSourceNames.size(),
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/hint/HintInlineShardingAlgorithm.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/hint/HintInlineShardingAlgorithm.java
index 1d0ba06f067..1f52b6980fa 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/hint/HintInlineShardingAlgorithm.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/hint/HintInlineShardingAlgorithm.java
@@ -51,7 +51,7 @@ public final class HintInlineShardingAlgorithm implements 
HintShardingAlgorithm<
     private String getAlgorithmExpression(final Properties props) {
         String algorithmExpression = 
props.getProperty(ALGORITHM_EXPRESSION_KEY, DEFAULT_ALGORITHM_EXPRESSION);
         ShardingSpherePreconditions.checkNotNull(algorithmExpression, () -> 
new ShardingAlgorithmInitializationException(getType(), "Inline sharding 
algorithm expression can not be null."));
-        return 
InlineExpressionParserFactory.newInstance().handlePlaceHolder(algorithmExpression.trim());
+        return 
InlineExpressionParserFactory.newInstance(algorithmExpression.trim()).handlePlaceHolder();
     }
     
     @Override
@@ -67,7 +67,7 @@ public final class HintInlineShardingAlgorithm implements 
HintShardingAlgorithm<
     }
     
     private Closure<?> createClosure() {
-        Closure<?> result = 
InlineExpressionParserFactory.newInstance().evaluateClosure(algorithmExpression).rehydrate(new
 Expando(), null, null);
+        Closure<?> result = 
InlineExpressionParserFactory.newInstance(algorithmExpression).evaluateClosure().rehydrate(new
 Expando(), null, null);
         result.setResolveStrategy(Closure.DELEGATE_ONLY);
         return result;
     }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/ComplexInlineShardingAlgorithm.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/ComplexInlineShardingAlgorithm.java
index e9d81087cc6..22042132704 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/ComplexInlineShardingAlgorithm.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/ComplexInlineShardingAlgorithm.java
@@ -67,7 +67,7 @@ public final class ComplexInlineShardingAlgorithm implements 
ComplexKeysSharding
         String algorithmExpression = 
props.getProperty(ALGORITHM_EXPRESSION_KEY);
         
ShardingSpherePreconditions.checkState(!Strings.isNullOrEmpty(algorithmExpression),
                 () -> new ShardingAlgorithmInitializationException(getType(), 
"Inline sharding algorithm expression can not be null."));
-        return 
InlineExpressionParserFactory.newInstance().handlePlaceHolder(algorithmExpression.trim());
+        return 
InlineExpressionParserFactory.newInstance(algorithmExpression.trim()).handlePlaceHolder();
     }
     
     private Collection<String> getShardingColumns(final Properties props) {
@@ -132,7 +132,7 @@ public final class ComplexInlineShardingAlgorithm 
implements ComplexKeysSharding
     }
     
     private Closure<?> createClosure() {
-        Closure<?> result = 
InlineExpressionParserFactory.newInstance().evaluateClosure(algorithmExpression).rehydrate(new
 Expando(), null, null);
+        Closure<?> result = 
InlineExpressionParserFactory.newInstance(algorithmExpression).evaluateClosure().rehydrate(new
 Expando(), null, null);
         result.setResolveStrategy(Closure.DELEGATE_ONLY);
         return result;
     }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/InlineShardingAlgorithm.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/InlineShardingAlgorithm.java
index 593b1a02663..84c1ba83c87 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/InlineShardingAlgorithm.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/inline/InlineShardingAlgorithm.java
@@ -58,7 +58,7 @@ public final class InlineShardingAlgorithm implements 
StandardShardingAlgorithm<
         String expression = props.getProperty(ALGORITHM_EXPRESSION_KEY);
         
ShardingSpherePreconditions.checkState(!Strings.isNullOrEmpty(expression),
                 () -> new ShardingAlgorithmInitializationException(getType(), 
"Inline sharding algorithm expression cannot be null or empty"));
-        return 
InlineExpressionParserFactory.newInstance().handlePlaceHolder(expression.trim());
+        return 
InlineExpressionParserFactory.newInstance(expression.trim()).handlePlaceHolder();
     }
     
     private boolean isAllowRangeQuery(final Properties props) {
@@ -83,7 +83,7 @@ public final class InlineShardingAlgorithm implements 
StandardShardingAlgorithm<
     }
     
     private Closure<?> createClosure() {
-        Closure<?> result = 
InlineExpressionParserFactory.newInstance().evaluateClosure(algorithmExpression).rehydrate(new
 Expando(), null, null);
+        Closure<?> result = 
InlineExpressionParserFactory.newInstance(algorithmExpression).evaluateClosure().rehydrate(new
 Expando(), null, null);
         result.setResolveStrategy(Closure.DELEGATE_ONLY);
         return result;
     }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
index 17d9d126e79..cd35c79d082 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
@@ -197,12 +197,12 @@ public final class ShardingRule implements DatabaseRule, 
DataNodeContainedRule,
     }
     
     private Collection<String> getDataSourceNames(final 
ShardingAutoTableRuleConfiguration shardingAutoTableRuleConfig) {
-        List<String> actualDataSources = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(shardingAutoTableRuleConfig.getActualDataSources());
+        List<String> actualDataSources = 
InlineExpressionParserFactory.newInstance(shardingAutoTableRuleConfig.getActualDataSources()).splitAndEvaluate();
         return new HashSet<>(actualDataSources);
     }
     
     private Collection<String> getDataSourceNames(final 
ShardingTableRuleConfiguration shardingTableRuleConfig) {
-        List<String> actualDataNodes = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(shardingTableRuleConfig.getActualDataNodes());
+        List<String> actualDataNodes = 
InlineExpressionParserFactory.newInstance(shardingTableRuleConfig.getActualDataNodes()).splitAndEvaluate();
         return actualDataNodes.stream().map(each -> new 
DataNode(each).getDataSourceName()).collect(Collectors.toList());
     }
     
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/TableRule.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/TableRule.java
index ea7c5af15c8..429ad42d83e 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/TableRule.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/TableRule.java
@@ -106,7 +106,7 @@ public final class TableRule {
     
     public TableRule(final ShardingTableRuleConfiguration tableRuleConfig, 
final Collection<String> dataSourceNames, final String 
defaultGenerateKeyColumn) {
         logicTable = tableRuleConfig.getLogicTable();
-        List<String> dataNodes = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(tableRuleConfig.getActualDataNodes());
+        List<String> dataNodes = 
InlineExpressionParserFactory.newInstance(tableRuleConfig.getActualDataNodes()).splitAndEvaluate();
         dataNodeIndexMap = new HashMap<>(dataNodes.size(), 1F);
         actualDataNodes = isEmptyDataNodes(dataNodes) ? 
generateDataNodes(tableRuleConfig.getLogicTable(), dataSourceNames) : 
generateDataNodes(dataNodes, dataSourceNames);
         actualTables = getActualTables();
@@ -158,7 +158,7 @@ public final class TableRule {
             return new LinkedList<>();
         }
         List<String> dataSources = 
Strings.isNullOrEmpty(tableRuleConfig.getActualDataSources()) ? new 
LinkedList<>(dataSourceNames)
-                : 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(tableRuleConfig.getActualDataSources());
+                : 
InlineExpressionParserFactory.newInstance(tableRuleConfig.getActualDataSources()).splitAndEvaluate();
         return 
DataNodeUtils.getFormatDataNodes(shardingAlgorithm.getAutoTablesAmount(), 
logicTable, dataSources);
     }
     
diff --git 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
index cfefac1e9c4..70abf9cdee3 100644
--- 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
+++ 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
@@ -179,13 +179,13 @@ public final class ShardingTableRuleStatementChecker {
         }
         Collection<String> result = new LinkedHashSet<>();
         tableRuleConfigs.forEach(each -> 
result.addAll(getDataSourceNames(each)));
-        autoTableRuleConfigs.forEach(each -> 
result.addAll(InlineExpressionParserFactory.newInstance().splitAndEvaluate(each.getActualDataSources())));
+        autoTableRuleConfigs.forEach(each -> 
result.addAll(InlineExpressionParserFactory.newInstance(each.getActualDataSources()).splitAndEvaluate()));
         return result;
     }
     
     private static Collection<String> getDataSourceNames(final 
ShardingTableRuleConfiguration shardingTableRuleConfig) {
-        return InlineExpressionParserFactory.newInstance()
-                
.splitAndEvaluate(shardingTableRuleConfig.getActualDataNodes()).stream().map(each
 -> new DataNode(each).getDataSourceName()).collect(Collectors.toList());
+        return 
InlineExpressionParserFactory.newInstance(shardingTableRuleConfig.getActualDataNodes())
+                .splitAndEvaluate().stream().map(each -> new 
DataNode(each).getDataSourceName()).collect(Collectors.toList());
     }
     
     private static Collection<String> getDataSourceNames(final 
Collection<String> actualDataNodes) {
@@ -316,7 +316,7 @@ public final class ShardingTableRuleStatementChecker {
         Collection<String> result = new LinkedHashSet<>();
         
result.addAll(config.getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getActualDataSources)
                 .map(each -> 
Splitter.on(",").trimResults().splitToList(each)).flatMap(Collection::stream).collect(Collectors.toSet()));
-        result.addAll(config.getTables().stream().map(each -> 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(each.getActualDataNodes()))
+        result.addAll(config.getTables().stream().map(each -> 
InlineExpressionParserFactory.newInstance(each.getActualDataNodes()).splitAndEvaluate())
                 .flatMap(Collection::stream).distinct().map(each -> new 
DataNode(each).getDataSourceName()).collect(Collectors.toSet()));
         return result;
     }
@@ -327,7 +327,7 @@ public final class ShardingTableRuleStatementChecker {
     }
     
     private static Collection<String> parseDateSource(final String dateSource) 
{
-        return 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(dateSource);
+        return 
InlineExpressionParserFactory.newInstance(dateSource).splitAndEvaluate();
     }
     
     private static Collection<String> getLogicDataSources(final 
ShardingSphereDatabase database) {
diff --git 
a/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/fixture/sharding/CoreHintShardingAlgorithmFixture.java
 
b/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/fixture/sharding/CoreHintShardingAlgorithmFixture.java
index 40c8865786d..671a4b1d946 100644
--- 
a/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/fixture/sharding/CoreHintShardingAlgorithmFixture.java
+++ 
b/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/fixture/sharding/CoreHintShardingAlgorithmFixture.java
@@ -46,7 +46,7 @@ public final class CoreHintShardingAlgorithmFixture 
implements HintShardingAlgor
     private String getAlgorithmExpression(final Properties props) {
         String algorithmExpression = 
props.getProperty(ALGORITHM_EXPRESSION_KEY, DEFAULT_ALGORITHM_EXPRESSION);
         Preconditions.checkNotNull(algorithmExpression, "Inline sharding 
algorithm expression can not be null.");
-        return 
InlineExpressionParserFactory.newInstance().handlePlaceHolder(algorithmExpression.trim());
+        return 
InlineExpressionParserFactory.newInstance(algorithmExpression.trim()).handlePlaceHolder();
     }
     
     @Override
@@ -61,7 +61,7 @@ public final class CoreHintShardingAlgorithmFixture 
implements HintShardingAlgor
     }
     
     private Closure<?> createClosure() {
-        Closure<?> result = 
InlineExpressionParserFactory.newInstance().evaluateClosure(algorithmExpression).rehydrate(new
 Expando(), null, null);
+        Closure<?> result = 
InlineExpressionParserFactory.newInstance(algorithmExpression).evaluateClosure().rehydrate(new
 Expando(), null, null);
         result.setResolveStrategy(Closure.DELEGATE_ONLY);
         return result;
     }
diff --git a/infra/expr/core/pom.xml b/infra/expr/core/pom.xml
index 84f274b57cf..a5fafdeba9e 100644
--- a/infra/expr/core/pom.xml
+++ b/infra/expr/core/pom.xml
@@ -34,7 +34,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
-            <artifactId>shardingsphere-infra-expr-hotsopt</artifactId>
+            <artifactId>shardingsphere-infra-expr-groovy</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
@@ -49,10 +49,5 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
-        
-        <dependency>
-            <groupId>org.apache.groovy</groupId>
-            <artifactId>groovy</artifactId>
-        </dependency>
     </dependencies>
 </project>
diff --git 
a/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java
 
b/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java
index 11a03cd4948..97dd60b3c76 100644
--- 
a/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java
+++ 
b/infra/expr/core/src/main/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactory.java
@@ -22,21 +22,45 @@ import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 
+import java.util.Properties;
+
 /**
  * Inline expression parser factory.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class InlineExpressionParserFactory {
     
-    // workaround for 
https://junit.org/junit5/docs/5.10.0/api/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledInNativeImage.html
-    private static final boolean IS_SUBSTRATE_VM = 
"runtime".equals(System.getProperty("org.graalvm.nativeimage.imagecode"));
+    private static final String TYPE_NAME_BEGIN_SYMBOL = "<";
+    
+    private static final String TYPE_NAME_END_SYMBOL = ">";
     
     /**
-     * Create new instance of inline expression parser.
-     * 
+     * Create new instance of inline expression parser by inlineExpression.
+     * And for compatibility reasons, inlineExpression allows to be null.
+     *
+     * @param inlineExpression inline expression
      * @return created instance
      */
-    public static InlineExpressionParser newInstance() {
-        return TypedSPILoader.getService(InlineExpressionParser.class, 
IS_SUBSTRATE_VM ? "PURELIST" : "HOTSPOT");
+    public static InlineExpressionParser newInstance(final String 
inlineExpression) {
+        Properties props = new Properties();
+        if (null == inlineExpression) {
+            return TypedSPILoader.getService(InlineExpressionParser.class, 
"GROOVY", props);
+        }
+        if (!inlineExpression.startsWith(TYPE_NAME_BEGIN_SYMBOL)) {
+            props.setProperty(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
inlineExpression);
+            return TypedSPILoader.getService(InlineExpressionParser.class, 
"GROOVY", props);
+        }
+        Integer typeBeginIndex = 
inlineExpression.indexOf(TYPE_NAME_BEGIN_SYMBOL);
+        Integer typeEndIndex = inlineExpression.indexOf(TYPE_NAME_END_SYMBOL);
+        props.setProperty(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
removeTypeNameInExpr(inlineExpression, typeBeginIndex, typeEndIndex));
+        return TypedSPILoader.getService(InlineExpressionParser.class, 
getTypeName(inlineExpression, typeBeginIndex, typeEndIndex), props);
+    }
+    
+    private static String getTypeName(final String inlineExpression, final 
Integer beginIndex, final Integer endIndex) {
+        return beginIndex.equals(-1) || endIndex.equals(-1) ? "GROOVY" : 
inlineExpression.substring(beginIndex + 1, endIndex);
+    }
+    
+    private static String removeTypeNameInExpr(final String inlineExpression, 
final Integer beginIndex, final Integer endIndex) {
+        return inlineExpression.substring(0, beginIndex) + 
inlineExpression.substring(endIndex + 1);
     }
 }
diff --git 
a/infra/expr/core/src/test/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactoryTest.java
 
b/infra/expr/core/src/test/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactoryTest.java
index 931e47f3150..4ade13127fe 100644
--- 
a/infra/expr/core/src/test/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactoryTest.java
+++ 
b/infra/expr/core/src/test/java/org/apache/shardingsphere/infra/expr/core/InlineExpressionParserFactoryTest.java
@@ -17,34 +17,49 @@
 
 package org.apache.shardingsphere.infra.expr.core;
 
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
+import 
org.apache.shardingsphere.infra.spi.exception.ServiceProviderNotFoundException;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledInNativeImage;
+
+import java.util.Arrays;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 class InlineExpressionParserFactoryTest {
     
-    private String originalImageCode;
-    
-    @BeforeEach
-    public void setUp() {
-        originalImageCode = 
System.getProperty("org.graalvm.nativeimage.imagecode");
+    @Test
+    @DisabledInNativeImage
+    void assertNewInstance() {
+        assertThat(InlineExpressionParserFactory.newInstance("t_order_0, 
t_order_1").getType(), is("GROOVY"));
+        assertThat(InlineExpressionParserFactory.newInstance("t_order_0, 
t_order_1").handlePlaceHolder(), is("t_order_0, t_order_1"));
+        
assertThat(InlineExpressionParserFactory.newInstance("<GROOVY>t_order_0, 
t_order_1").getType(), is("GROOVY"));
+        
assertThat(InlineExpressionParserFactory.newInstance("<GROOVY>t_order_0, 
t_order_1").handlePlaceHolder(), is("t_order_0, t_order_1"));
+        
assertThat(InlineExpressionParserFactory.newInstance("<PURELIST>t_order_0, 
t_order_1").getType(), is("PURELIST"));
+        
assertThat(InlineExpressionParserFactory.newInstance("<PURELIST>t_order_0, 
t_order_1").handlePlaceHolder(), is("t_order_0, t_order_1"));
     }
     
-    @AfterEach
-    public void tearDown() {
-        if (null != originalImageCode) {
-            System.setProperty("org.graalvm.nativeimage.imagecode", 
originalImageCode);
-        } else {
-            System.clearProperty("org.graalvm.nativeimage.imagecode");
-        }
+    @Test
+    void assertUndefinedInstance() {
+        assertThrows(ServiceProviderNotFoundException.class,
+                () -> 
InlineExpressionParserFactory.newInstance("<UNDEFINED>t_order_0, 
t_order_1").getType());
     }
     
     @Test
-    void assertNewInstance() {
-        System.setProperty("org.graalvm.nativeimage.imagecode", "");
-        assertThat(InlineExpressionParserFactory.newInstance().getType(), 
is("HOTSPOT"));
+    void assertFixtureInstance() {
+        
assertThat(InlineExpressionParserFactory.newInstance("<CUSTOM.FIXTURE>spring").splitAndEvaluate(),
+                is(Arrays.asList("t_order_2023_03", "t_order_2023_04", 
"t_order_2023_05")));
+        
assertThat(InlineExpressionParserFactory.newInstance("<CUSTOM.FIXTURE>summer").splitAndEvaluate(),
+                is(Arrays.asList("t_order_2023_06", "t_order_2023_07", 
"t_order_2023_08")));
+        
assertThat(InlineExpressionParserFactory.newInstance("<CUSTOM.FIXTURE>autumn").splitAndEvaluate(),
+                is(Arrays.asList("t_order_2023_09", "t_order_2023_10", 
"t_order_2023_11")));
+        
assertThat(InlineExpressionParserFactory.newInstance("<CUSTOM.FIXTURE>winter").splitAndEvaluate(),
+                is(Arrays.asList("t_order_2023_12", "t_order_2024_01", 
"t_order_2024_02")));
+        
assertThat(InlineExpressionParserFactory.newInstance("<CUSTOM.FIXTURE>").splitAndEvaluate(),
+                is(Arrays.asList("t_order_2023_03", "t_order_2023_04", 
"t_order_2023_05",
+                        "t_order_2023_06", "t_order_2023_07", 
"t_order_2023_08",
+                        "t_order_2023_09", "t_order_2023_10", 
"t_order_2023_11",
+                        "t_order_2023_12", "t_order_2024_01", 
"t_order_2024_02")));
     }
 }
diff --git 
a/infra/expr/core/src/test/java/org/apache/shardingsphere/infra/expr/core/fixture/CustomInlineExpressionParserFixture.java
 
b/infra/expr/core/src/test/java/org/apache/shardingsphere/infra/expr/core/fixture/CustomInlineExpressionParserFixture.java
new file mode 100644
index 00000000000..3f0f8d5a59d
--- /dev/null
+++ 
b/infra/expr/core/src/test/java/org/apache/shardingsphere/infra/expr/core/fixture/CustomInlineExpressionParserFixture.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.expr.core.fixture;
+
+import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+public final class CustomInlineExpressionParserFixture implements 
InlineExpressionParser {
+    
+    private String inlineExpression;
+    
+    @Override
+    public void init(final Properties props) {
+        this.inlineExpression = props.getProperty(INLINE_EXPRESSION_KEY);
+    }
+    
+    @Override
+    public String handlePlaceHolder() {
+        return inlineExpression;
+    }
+    
+    @Override
+    public List<String> splitAndEvaluate() {
+        switch (inlineExpression) {
+            case "spring":
+                return Arrays.asList("t_order_2023_03", "t_order_2023_04", 
"t_order_2023_05");
+            case "summer":
+                return Arrays.asList("t_order_2023_06", "t_order_2023_07", 
"t_order_2023_08");
+            case "autumn":
+                return Arrays.asList("t_order_2023_09", "t_order_2023_10", 
"t_order_2023_11");
+            case "winter":
+                return Arrays.asList("t_order_2023_12", "t_order_2024_01", 
"t_order_2024_02");
+            default:
+                return Arrays.asList("t_order_2023_03", "t_order_2023_04", 
"t_order_2023_05",
+                        "t_order_2023_06", "t_order_2023_07", 
"t_order_2023_08",
+                        "t_order_2023_09", "t_order_2023_10", 
"t_order_2023_11",
+                        "t_order_2023_12", "t_order_2024_01", 
"t_order_2024_02");
+        }
+    }
+    
+    @Override
+    public Object getType() {
+        return "CUSTOM.FIXTURE";
+    }
+}
diff --git 
a/infra/expr/hotsopt/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
 
b/infra/expr/core/src/test/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
similarity index 90%
copy from 
infra/expr/hotsopt/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
copy to 
infra/expr/core/src/test/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
index 48cf905c9a5..2af948cb146 100644
--- 
a/infra/expr/hotsopt/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
+++ 
b/infra/expr/core/src/test/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
@@ -15,4 +15,4 @@
 # limitations under the License.
 #
 
-org.apache.shardingsphere.infra.expr.hotsopt.HotspotInlineExpressionParser
+org.apache.shardingsphere.infra.expr.core.fixture.CustomInlineExpressionParserFixture
diff --git a/infra/expr/espresso/pom.xml b/infra/expr/espresso/pom.xml
index 653fe6e1653..df7c6fc1cfb 100644
--- a/infra/expr/espresso/pom.xml
+++ b/infra/expr/espresso/pom.xml
@@ -26,6 +26,10 @@
     <artifactId>shardingsphere-infra-expr-espresso</artifactId>
     <name>${project.artifactId}</name>
     
+    <properties>
+        <truffle-api.version>21.2.0</truffle-api.version>
+    </properties>
+    
     <dependencies>
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
@@ -46,6 +50,14 @@
         <dependency>
             <groupId>org.graalvm.truffle</groupId>
             <artifactId>truffle-api</artifactId>
+            <version>${truffle-api.version}</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-test-util</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
     
diff --git 
a/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
 
b/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
index bfe5201bb08..8e9b33fc3ad 100644
--- 
a/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
+++ 
b/infra/expr/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
@@ -19,7 +19,6 @@ package org.apache.shardingsphere.infra.expr.espresso;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.Sets;
-import groovy.lang.Closure;
 import groovy.lang.GroovyShell;
 import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
 import org.graalvm.polyglot.Context;
@@ -32,6 +31,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Properties;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -44,31 +44,53 @@ public final class EspressoInlineExpressionParser 
implements InlineExpressionPar
     
     private static final char SPLITTER = ',';
     
+    private String inlineExpression;
+    
     static {
         URL resource = 
Thread.currentThread().getContextClassLoader().getResource("espresso-need-libs");
         String dir = null == resource ? null : resource.getPath();
         JAVA_CLASSPATH = dir + File.separator + "groovy.jar";
     }
     
+    /**
+     * Initialize SPI.
+     *
+     * @param props A Properties instance that carries inlineExpression.
+     *              And for compatibility reasons, inlineExpression allows to 
be null.
+     */
     @Override
-    public String handlePlaceHolder(final String inlineExpression) {
-        return inlineExpression.contains("$->{") ? 
inlineExpression.replaceAll("\\$->\\{", "\\$\\{") : inlineExpression;
+    public void init(final Properties props) {
+        this.inlineExpression = props.getProperty(INLINE_EXPRESSION_KEY);
     }
     
     @Override
-    public List<String> splitAndEvaluate(final String inlineExpression) {
-        try (Context context = createContext()) {
-            return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : flatten(evaluate(split(inlineExpression), context));
-        }
+    public String handlePlaceHolder() {
+        return handlePlaceHolder(inlineExpression);
+    }
+    
+    /**
+     * Replace all inline expression placeholders.
+     *
+     * @param inlineExpression inline expression with {@code $->}
+     * @return result inline expression with {@code $}
+     */
+    private String handlePlaceHolder(final String inlineExpression) {
+        return inlineExpression.contains("$->{") ? 
inlineExpression.replaceAll("\\$->\\{", "\\$\\{") : inlineExpression;
     }
     
     @Override
-    public Closure<?> evaluateClosure(final String inlineExpression) {
-        throw new UnsupportedOperationException("GraalVM Truffle's Espresso 
implementation cannot return an instance of `groovy.lang.Closure` to the Host 
JVM.");
+    public List<String> splitAndEvaluate() {
+        try (Context context = createContext()) {
+            return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : 
flatten(evaluate(split(handlePlaceHolder(inlineExpression)), context));
+        }
     }
     
+    /**
+     * TODO <a href="https://github.com/oracle/graal/issues/4555";>espressoHome 
not defined</a> not yet closed.
+     *
+     * @return the Truffle Context Instance.
+     */
     private Context createContext() {
-        // TODO https://github.com/oracle/graal/issues/4555 not yet closed
         return Context.newBuilder()
                 .allowAllAccess(true)
                 .option("java.Properties.org.graalvm.home", 
System.getenv("JAVA_HOME"))
diff --git 
a/infra/expr/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
 
b/infra/expr/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
index 3f7999f5e4c..ca6deb1c66e 100644
--- 
a/infra/expr/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
+++ 
b/infra/expr/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.expr.espresso;
 
+import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.test.util.PropertiesBuilder;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
@@ -24,6 +27,7 @@ import org.junit.jupiter.api.condition.EnabledInNativeImage;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Properties;
 
 import static org.hamcrest.CoreMatchers.hasItems;
 import static org.hamcrest.CoreMatchers.is;
@@ -35,62 +39,71 @@ class EspressoInlineExpressionParserTest {
     
     @Test
     void assertEvaluateForExpressionIsNull() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate(null);
+        InlineExpressionParser parser = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", new 
Properties());
+        List<String> expected = parser.splitAndEvaluate();
         assertThat(expected, is(Collections.<String>emptyList()));
     }
     
     @Test
     void assertEvaluateForSimpleString() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate(" t_order_0, t_order_1 ");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, " 
t_order_0, t_order_1 "))).splitAndEvaluate();
         assertThat(expected.size(), is(2));
         assertThat(expected, hasItems("t_order_0", "t_order_1"));
     }
     
     @Test
     void assertEvaluateForNull() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate("t_order_${null}");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${null}"))).splitAndEvaluate();
         assertThat(expected.size(), is(1));
         assertThat(expected, hasItems("t_order_"));
     }
     
     @Test
     void assertEvaluateForLiteral() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate("t_order_${'xx'}");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${'xx'}"))).splitAndEvaluate();
         assertThat(expected.size(), is(1));
         assertThat(expected, hasItems("t_order_xx"));
     }
     
     @Test
     void assertEvaluateForArray() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate("t_order_${[0, 1, 
2]},t_order_item_${[0, 2]}");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${[0, 1, 2]},t_order_item_${[0, 2]}"))).splitAndEvaluate();
         assertThat(expected.size(), is(5));
         assertThat(expected, hasItems("t_order_0", "t_order_1", "t_order_2", 
"t_order_item_0", "t_order_item_2"));
     }
     
     @Test
     void assertEvaluateForRange() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate("t_order_${0..2},t_order_item_${0..1}");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${0..2},t_order_item_${0..1}"))).splitAndEvaluate();
         assertThat(expected.size(), is(5));
         assertThat(expected, hasItems("t_order_0", "t_order_1", "t_order_2", 
"t_order_item_0", "t_order_item_1"));
     }
     
     @Test
     void assertEvaluateForComplex() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate("t_${['new','old']}_order_${1..2},
 t_config");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_${['new','old']}_order_${1..2}, t_config"))).splitAndEvaluate();
         assertThat(expected.size(), is(5));
         assertThat(expected, hasItems("t_new_order_1", "t_new_order_2", 
"t_old_order_1", "t_old_order_2", "t_config"));
     }
     
     @Test
     void assertEvaluateForCalculate() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate("t_${[\"new${1+2}\",'old']}_order_${1..2}");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_${[\"new${1+2}\",'old']}_order_${1..2}"))).splitAndEvaluate();
         assertThat(expected.size(), is(4));
         assertThat(expected, hasItems("t_new3_order_1", "t_new3_order_2", 
"t_old_order_1", "t_old_order_2"));
     }
     
     @Test
     void assertEvaluateForExpressionPlaceHolder() {
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate("t_$->{[\"new$->{1+2}\",'old']}_order_$->{1..2}");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_$->{[\"new$->{1+2}\",'old']}_order_$->{1..2}"))).splitAndEvaluate();
         assertThat(expected.size(), is(4));
         assertThat(expected, hasItems("t_new3_order_1", "t_new3_order_2", 
"t_old_order_1", "t_old_order_2"));
     }
@@ -107,15 +120,18 @@ class EspressoInlineExpressionParserTest {
                 expression.append(",");
             }
         }
-        List<String> expected = new 
EspressoInlineExpressionParser().splitAndEvaluate(expression.toString());
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "ESPRESSO", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
expression.toString()))).splitAndEvaluate();
         assertThat(expected.size(), is(1024));
         assertThat(expected, hasItems("ds_0.t_user_0", "ds_15.t_user_1023"));
     }
     
     @Test
     void assertHandlePlaceHolder() {
-        assertThat(new 
EspressoInlineExpressionParser().handlePlaceHolder("t_$->{[\"new$->{1+2}\"]}"), 
is("t_${[\"new${1+2}\"]}"));
-        assertThat(new 
EspressoInlineExpressionParser().handlePlaceHolder("t_${[\"new$->{1+2}\"]}"), 
is("t_${[\"new${1+2}\"]}"));
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"ESPRESSO", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_$->{[\"new$->{1+2}\"]}"))).handlePlaceHolder(), is("t_${[\"new${1+2}\"]}"));
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"ESPRESSO", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_${[\"new$->{1+2}\"]}"))).handlePlaceHolder(), is("t_${[\"new${1+2}\"]}"));
     }
     
     /*
@@ -125,6 +141,7 @@ class EspressoInlineExpressionParserTest {
     @Test
     @Disabled("See java doc")
     void assertEvaluateClosure() {
-        assertThat(new 
EspressoInlineExpressionParser().evaluateClosure("${1+2}").call().toString(), 
is("3"));
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"ESPRESSO", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"${1+2}"))).evaluateClosure().call().toString(), is("3"));
     }
 }
diff --git a/infra/expr/hotsopt/pom.xml b/infra/expr/groovy/pom.xml
similarity index 86%
rename from infra/expr/hotsopt/pom.xml
rename to infra/expr/groovy/pom.xml
index 2fa03655f3b..cbc18ed0bed 100644
--- a/infra/expr/hotsopt/pom.xml
+++ b/infra/expr/groovy/pom.xml
@@ -23,7 +23,7 @@
         <artifactId>shardingsphere-infra-expr</artifactId>
         <version>5.4.1-SNAPSHOT</version>
     </parent>
-    <artifactId>shardingsphere-infra-expr-hotsopt</artifactId>
+    <artifactId>shardingsphere-infra-expr-groovy</artifactId>
     <name>${project.artifactId}</name>
     
     <dependencies>
@@ -34,8 +34,10 @@
         </dependency>
         
         <dependency>
-            <groupId>org.apache.groovy</groupId>
-            <artifactId>groovy</artifactId>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-test-util</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
diff --git 
a/infra/expr/hotsopt/src/main/java/org/apache/shardingsphere/infra/expr/hotsopt/HotspotInlineExpressionParser.java
 
b/infra/expr/groovy/src/main/java/org/apache/shardingsphere/infra/expr/groovy/GroovyInlineExpressionParser.java
similarity index 78%
rename from 
infra/expr/hotsopt/src/main/java/org/apache/shardingsphere/infra/expr/hotsopt/HotspotInlineExpressionParser.java
rename to 
infra/expr/groovy/src/main/java/org/apache/shardingsphere/infra/expr/groovy/GroovyInlineExpressionParser.java
index 1ec58bb940c..27411402be0 100644
--- 
a/infra/expr/hotsopt/src/main/java/org/apache/shardingsphere/infra/expr/hotsopt/HotspotInlineExpressionParser.java
+++ 
b/infra/expr/groovy/src/main/java/org/apache/shardingsphere/infra/expr/groovy/GroovyInlineExpressionParser.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.expr.hotsopt;
+package org.apache.shardingsphere.infra.expr.groovy;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.Sets;
@@ -31,34 +31,70 @@ import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
 /**
- * Hotspot inline expression parser.
+ * Groovy inline expression parser.
  */
-public final class HotspotInlineExpressionParser implements 
InlineExpressionParser {
+public final class GroovyInlineExpressionParser implements 
InlineExpressionParser {
     
     private static final char SPLITTER = ',';
     
+    private static final String INLINE_EXPRESSION_KEY = "inlineExpression";
+    
     private static final Map<String, Script> SCRIPTS = new 
ConcurrentHashMap<>();
     
     private static final GroovyShell SHELL = new GroovyShell();
     
+    private String inlineExpression;
+    
+    /**
+     * Initialize SPI.
+     *
+     * @param props A Properties instance that carries inlineExpression.
+     *              And for compatibility reasons, inlineExpression allows to 
be null.
+     */
     @Override
-    public String handlePlaceHolder(final String inlineExpression) {
+    public void init(final Properties props) {
+        this.inlineExpression = props.getProperty(INLINE_EXPRESSION_KEY);
+    }
+    
+    @Override
+    public String handlePlaceHolder() {
+        return handlePlaceHolder(inlineExpression);
+    }
+    
+    /**
+     * Replace all inline expression placeholders.
+     *
+     * @param inlineExpression inline expression with {@code $->}
+     * @return result inline expression with {@code $}
+     */
+    private String handlePlaceHolder(final String inlineExpression) {
         return inlineExpression.contains("$->{") ? 
inlineExpression.replaceAll("\\$->\\{", "\\$\\{") : inlineExpression;
     }
     
+    /**
+     * Split and Evaluate inline expression. This function will replace all 
inline expression placeholders.
+     *
+     * @return result inline expression with {@code $}
+     */
     @Override
-    public List<String> splitAndEvaluate(final String inlineExpression) {
-        return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : flatten(evaluate(split(inlineExpression)));
+    public List<String> splitAndEvaluate() {
+        return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : 
flatten(evaluate(split(handlePlaceHolder(inlineExpression))));
     }
     
+    /**
+     * Turn inline expression into Groovy Closure. This function will replace 
all inline expression placeholders.
+     *
+     * @return The result of the Groovy Closure pattern.
+     */
     @Override
-    public Closure<?> evaluateClosure(final String inlineExpression) {
-        return (Closure<?>) evaluate("{it -> \"" + inlineExpression + "\"}");
+    public Closure<?> evaluateClosure() {
+        return (Closure<?>) evaluate("{it -> \"" + 
handlePlaceHolder(inlineExpression) + "\"}");
     }
     
     private List<Object> evaluate(final List<String> inlineExpressions) {
@@ -178,7 +214,7 @@ public final class HotspotInlineExpressionParser implements 
InlineExpressionPars
     
     @Override
     public String getType() {
-        return "HOTSPOT";
+        return "GROOVY";
     }
     
     @Override
diff --git 
a/infra/expr/hotsopt/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
 
b/infra/expr/groovy/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
similarity index 91%
rename from 
infra/expr/hotsopt/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
rename to 
infra/expr/groovy/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
index 48cf905c9a5..1eab5f0f7be 100644
--- 
a/infra/expr/hotsopt/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
+++ 
b/infra/expr/groovy/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser
@@ -15,4 +15,4 @@
 # limitations under the License.
 #
 
-org.apache.shardingsphere.infra.expr.hotsopt.HotspotInlineExpressionParser
+org.apache.shardingsphere.infra.expr.groovy.GroovyInlineExpressionParser
diff --git 
a/infra/expr/groovy/src/test/java/org/apache/shardingsphere/infra/expr/groovy/GroovyInlineExpressionParserTest.java
 
b/infra/expr/groovy/src/test/java/org/apache/shardingsphere/infra/expr/groovy/GroovyInlineExpressionParserTest.java
new file mode 100644
index 00000000000..b2a2940720f
--- /dev/null
+++ 
b/infra/expr/groovy/src/test/java/org/apache/shardingsphere/infra/expr/groovy/GroovyInlineExpressionParserTest.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.expr.groovy;
+
+import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.test.util.PropertiesBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledInNativeImage;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+@DisabledInNativeImage
+class GroovyInlineExpressionParserTest {
+    
+    @Test
+    void assertEvaluateForExpressionIsNull() {
+        InlineExpressionParser parser = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", new 
Properties());
+        List<String> expected = parser.splitAndEvaluate();
+        assertThat(expected, is(Collections.<String>emptyList()));
+    }
+    
+    @Test
+    void assertEvaluateForSimpleString() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, " 
t_order_0, t_order_1 "))).splitAndEvaluate();
+        assertThat(expected.size(), is(2));
+        assertThat(expected, hasItems("t_order_0", "t_order_1"));
+    }
+    
+    @Test
+    void assertEvaluateForNull() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${null}"))).splitAndEvaluate();
+        assertThat(expected.size(), is(1));
+        assertThat(expected, hasItems("t_order_"));
+    }
+    
+    @Test
+    void assertEvaluateForLiteral() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${'xx'}"))).splitAndEvaluate();
+        assertThat(expected.size(), is(1));
+        assertThat(expected, hasItems("t_order_xx"));
+    }
+    
+    @Test
+    void assertEvaluateForArray() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${[0, 1, 2]},t_order_item_${[0, 2]}"))).splitAndEvaluate();
+        assertThat(expected.size(), is(5));
+        assertThat(expected, hasItems("t_order_0", "t_order_1", "t_order_2", 
"t_order_item_0", "t_order_item_2"));
+    }
+    
+    @Test
+    void assertEvaluateForRange() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_order_${0..2},t_order_item_${0..1}"))).splitAndEvaluate();
+        assertThat(expected.size(), is(5));
+        assertThat(expected, hasItems("t_order_0", "t_order_1", "t_order_2", 
"t_order_item_0", "t_order_item_1"));
+    }
+    
+    @Test
+    void assertEvaluateForComplex() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_${['new','old']}_order_${1..2}, t_config"))).splitAndEvaluate();
+        assertThat(expected.size(), is(5));
+        assertThat(expected, hasItems("t_new_order_1", "t_new_order_2", 
"t_old_order_1", "t_old_order_2", "t_config"));
+    }
+    
+    @Test
+    void assertEvaluateForCalculate() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_${[\"new${1+2}\",'old']}_order_${1..2}"))).splitAndEvaluate();
+        assertThat(expected.size(), is(4));
+        assertThat(expected, hasItems("t_new3_order_1", "t_new3_order_2", 
"t_old_order_1", "t_old_order_2"));
+    }
+    
+    @Test
+    void assertEvaluateForExpressionPlaceHolder() {
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_$->{[\"new$->{1+2}\",'old']}_order_$->{1..2}"))).splitAndEvaluate();
+        assertThat(expected.size(), is(4));
+        assertThat(expected, hasItems("t_new3_order_1", "t_new3_order_2", 
"t_old_order_1", "t_old_order_2"));
+    }
+    
+    @Test
+    void assertEvaluateForLong() {
+        StringBuilder expression = new StringBuilder();
+        for (int i = 0; i < 1024; i++) {
+            expression.append("ds_");
+            expression.append(i / 64);
+            expression.append(".t_user_");
+            expression.append(i);
+            if (i != 1023) {
+                expression.append(",");
+            }
+        }
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "GROOVY", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
expression.toString()))).splitAndEvaluate();
+        assertThat(expected.size(), is(1024));
+        assertThat(expected, hasItems("ds_0.t_user_0", "ds_15.t_user_1023"));
+    }
+    
+    @Test
+    void assertHandlePlaceHolder() {
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"GROOVY", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_$->{[\"new$->{1+2}\"]}"))).handlePlaceHolder(), is("t_${[\"new${1+2}\"]}"));
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"GROOVY", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_${[\"new$->{1+2}\"]}"))).handlePlaceHolder(), is("t_${[\"new${1+2}\"]}"));
+    }
+    
+    @Test
+    void assertEvaluateClosure() {
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"GROOVY", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"${1+2}"))).evaluateClosure().call().toString(), is("3"));
+    }
+}
diff --git 
a/infra/expr/hotsopt/src/test/java/org/apache/shardingsphere/infra/expr/hotsopt/HotspotInlineExpressionParserTest.java
 
b/infra/expr/hotsopt/src/test/java/org/apache/shardingsphere/infra/expr/hotsopt/HotspotInlineExpressionParserTest.java
deleted file mode 100644
index 9a836eff0f9..00000000000
--- 
a/infra/expr/hotsopt/src/test/java/org/apache/shardingsphere/infra/expr/hotsopt/HotspotInlineExpressionParserTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shardingsphere.infra.expr.hotsopt;
-
-import org.junit.jupiter.api.Test;
-
-import java.util.Collections;
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.hasItems;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-class HotspotInlineExpressionParserTest {
-    
-    @Test
-    void assertEvaluateForExpressionIsNull() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate(null);
-        assertThat(expected, is(Collections.<String>emptyList()));
-    }
-    
-    @Test
-    void assertEvaluateForSimpleString() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate(" t_order_0, t_order_1 ");
-        assertThat(expected.size(), is(2));
-        assertThat(expected, hasItems("t_order_0", "t_order_1"));
-    }
-    
-    @Test
-    void assertEvaluateForNull() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate("t_order_${null}");
-        assertThat(expected.size(), is(1));
-        assertThat(expected, hasItems("t_order_"));
-    }
-    
-    @Test
-    void assertEvaluateForLiteral() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate("t_order_${'xx'}");
-        assertThat(expected.size(), is(1));
-        assertThat(expected, hasItems("t_order_xx"));
-    }
-    
-    @Test
-    void assertEvaluateForArray() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate("t_order_${[0, 1, 
2]},t_order_item_${[0, 2]}");
-        assertThat(expected.size(), is(5));
-        assertThat(expected, hasItems("t_order_0", "t_order_1", "t_order_2", 
"t_order_item_0", "t_order_item_2"));
-    }
-    
-    @Test
-    void assertEvaluateForRange() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate("t_order_${0..2},t_order_item_${0..1}");
-        assertThat(expected.size(), is(5));
-        assertThat(expected, hasItems("t_order_0", "t_order_1", "t_order_2", 
"t_order_item_0", "t_order_item_1"));
-    }
-    
-    @Test
-    void assertEvaluateForComplex() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate("t_${['new','old']}_order_${1..2},
 t_config");
-        assertThat(expected.size(), is(5));
-        assertThat(expected, hasItems("t_new_order_1", "t_new_order_2", 
"t_old_order_1", "t_old_order_2", "t_config"));
-    }
-    
-    @Test
-    void assertEvaluateForCalculate() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate("t_${[\"new${1+2}\",'old']}_order_${1..2}");
-        assertThat(expected.size(), is(4));
-        assertThat(expected, hasItems("t_new3_order_1", "t_new3_order_2", 
"t_old_order_1", "t_old_order_2"));
-    }
-    
-    @Test
-    void assertEvaluateForExpressionPlaceHolder() {
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate("t_$->{[\"new$->{1+2}\",'old']}_order_$->{1..2}");
-        assertThat(expected.size(), is(4));
-        assertThat(expected, hasItems("t_new3_order_1", "t_new3_order_2", 
"t_old_order_1", "t_old_order_2"));
-    }
-    
-    @Test
-    void assertEvaluateForLong() {
-        StringBuilder expression = new StringBuilder();
-        for (int i = 0; i < 1024; i++) {
-            expression.append("ds_");
-            expression.append(i / 64);
-            expression.append(".t_user_");
-            expression.append(i);
-            if (i != 1023) {
-                expression.append(",");
-            }
-        }
-        List<String> expected = new 
HotspotInlineExpressionParser().splitAndEvaluate(expression.toString());
-        assertThat(expected.size(), is(1024));
-        assertThat(expected, hasItems("ds_0.t_user_0", "ds_15.t_user_1023"));
-    }
-    
-    @Test
-    void assertHandlePlaceHolder() {
-        assertThat(new 
HotspotInlineExpressionParser().handlePlaceHolder("t_$->{[\"new$->{1+2}\"]}"), 
is("t_${[\"new${1+2}\"]}"));
-        assertThat(new 
HotspotInlineExpressionParser().handlePlaceHolder("t_${[\"new$->{1+2}\"]}"), 
is("t_${[\"new${1+2}\"]}"));
-    }
-    
-    @Test
-    void assertEvaluateClosure() {
-        assertThat(new 
HotspotInlineExpressionParser().evaluateClosure("${1+2}").call().toString(), 
is("3"));
-    }
-}
diff --git a/infra/expr/pom.xml b/infra/expr/pom.xml
index 14aa380d873..9f9e4e7cb64 100644
--- a/infra/expr/pom.xml
+++ b/infra/expr/pom.xml
@@ -30,8 +30,8 @@
     <modules>
         <module>spi</module>
         <module>core</module>
-        <module>hotsopt</module>
-        <module>espresso</module>
+        <module>groovy</module>
         <module>purelist</module>
+        <module>espresso</module>
     </modules>
 </project>
diff --git a/infra/expr/purelist/pom.xml b/infra/expr/purelist/pom.xml
index b45ff489b37..0e3d95b390b 100644
--- a/infra/expr/purelist/pom.xml
+++ b/infra/expr/purelist/pom.xml
@@ -34,8 +34,10 @@
         </dependency>
         
         <dependency>
-            <groupId>org.apache.groovy</groupId>
-            <artifactId>groovy</artifactId>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-test-util</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
diff --git 
a/infra/expr/purelist/src/main/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParser.java
 
b/infra/expr/purelist/src/main/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParser.java
index 347b6d4f3e2..ab1d3a34af2 100644
--- 
a/infra/expr/purelist/src/main/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParser.java
+++ 
b/infra/expr/purelist/src/main/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParser.java
@@ -18,12 +18,12 @@
 package org.apache.shardingsphere.infra.expr.purelist;
 
 import com.google.common.base.Strings;
-import groovy.lang.Closure;
 import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Properties;
 
 /**
  * Pure List inline expression parser.
@@ -32,19 +32,27 @@ public final class PureListInlineExpressionParser 
implements InlineExpressionPar
     
     private static final char SPLITTER = ',';
     
+    private String inlineExpression;
+    
+    /**
+     * Initialize SPI.
+     *
+     * @param props A Properties instance that carries inlineExpression.
+     *              And for compatibility reasons, inlineExpression allows to 
be null.
+     */
     @Override
-    public String handlePlaceHolder(final String inlineExpression) {
-        return inlineExpression.contains("$->{") ? 
inlineExpression.replaceAll("\\$->\\{", "\\$\\{") : inlineExpression;
+    public void init(final Properties props) {
+        this.inlineExpression = props.getProperty(INLINE_EXPRESSION_KEY);
     }
     
     @Override
-    public List<String> splitAndEvaluate(final String inlineExpression) {
-        return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : split(inlineExpression);
+    public String handlePlaceHolder() {
+        return inlineExpression;
     }
     
     @Override
-    public Closure<?> evaluateClosure(final String inlineExpression) {
-        throw new UnsupportedOperationException("Groovy classes cannot be used 
directly within GraalVM Native Image.");
+    public List<String> splitAndEvaluate() {
+        return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : split(inlineExpression);
     }
     
     private List<String> split(final String inlineExpression) {
diff --git 
a/infra/expr/purelist/src/test/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParserTest.java
 
b/infra/expr/purelist/src/test/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParserTest.java
index bb8ebbf8855..2ddeacdd7b4 100644
--- 
a/infra/expr/purelist/src/test/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParserTest.java
+++ 
b/infra/expr/purelist/src/test/java/org/apache/shardingsphere/infra/expr/purelist/PureListInlineExpressionParserTest.java
@@ -17,26 +17,33 @@
 
 package org.apache.shardingsphere.infra.expr.purelist;
 
+import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.test.util.PropertiesBuilder;
 import org.junit.jupiter.api.Test;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Properties;
 
 import static org.hamcrest.CoreMatchers.hasItems;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 class PureListInlineExpressionParserTest {
     
     @Test
     void assertEvaluateForExpressionIsNull() {
-        List<String> expected = new 
PureListInlineExpressionParser().splitAndEvaluate(null);
+        InlineExpressionParser parser = 
TypedSPILoader.getService(InlineExpressionParser.class, "PURELIST", new 
Properties());
+        List<String> expected = parser.splitAndEvaluate();
         assertThat(expected, is(Collections.<String>emptyList()));
     }
     
     @Test
     void assertEvaluateForSimpleString() {
-        List<String> expected = new 
PureListInlineExpressionParser().splitAndEvaluate(" t_order_0, t_order_1 ");
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "PURELIST", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, " 
t_order_0, t_order_1 "))).splitAndEvaluate();
         assertThat(expected.size(), is(2));
         assertThat(expected, hasItems("t_order_0", "t_order_1"));
     }
@@ -53,8 +60,23 @@ class PureListInlineExpressionParserTest {
                 expression.append(",");
             }
         }
-        List<String> expected = new 
PureListInlineExpressionParser().splitAndEvaluate(expression.toString());
+        List<String> expected = 
TypedSPILoader.getService(InlineExpressionParser.class, "PURELIST", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
expression.toString()))).splitAndEvaluate();
         assertThat(expected.size(), is(1024));
         assertThat(expected, hasItems("ds_0.t_user_0", "ds_15.t_user_1023"));
     }
+    
+    @Test
+    void assertHandlePlaceHolder() {
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"PURELIST", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_$->{[\"new$->{1+2}\"]}"))).handlePlaceHolder(), 
is("t_$->{[\"new$->{1+2}\"]}"));
+        assertThat(TypedSPILoader.getService(InlineExpressionParser.class, 
"PURELIST", PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"t_${[\"new$->{1+2}\"]}"))).handlePlaceHolder(), is("t_${[\"new$->{1+2}\"]}"));
+    }
+    
+    @Test
+    void assertEvaluateClosure() {
+        assertThrows(UnsupportedOperationException.class, () -> 
TypedSPILoader.getService(InlineExpressionParser.class, "PURELIST", 
PropertiesBuilder.build(
+                new 
PropertiesBuilder.Property(InlineExpressionParser.INLINE_EXPRESSION_KEY, 
"${1+2}"))).evaluateClosure().call().toString());
+    }
 }
diff --git 
a/infra/expr/spi/src/main/java/org/apache/shardingsphere/infra/expr/spi/InlineExpressionParser.java
 
b/infra/expr/spi/src/main/java/org/apache/shardingsphere/infra/expr/spi/InlineExpressionParser.java
index 7baa8728629..7578f5f8f2d 100644
--- 
a/infra/expr/spi/src/main/java/org/apache/shardingsphere/infra/expr/spi/InlineExpressionParser.java
+++ 
b/infra/expr/spi/src/main/java/org/apache/shardingsphere/infra/expr/spi/InlineExpressionParser.java
@@ -30,26 +30,34 @@ import java.util.List;
 public interface InlineExpressionParser extends TypedSPI {
     
     /**
-     * Replace all inline expression placeholders.
+     * The expression used to build the InlineExpressionParser instance will 
be saved to the Properties instance via this key.
+     */
+    String INLINE_EXPRESSION_KEY = "inlineExpression";
+    
+    /**
+     * This method is used to return the inlineExpression String itself. In 
some cases, you may want to do
+     * additional processing on inlineExpression to return a specific value, 
in which case you need to override this
+     * method.
      *
-     * @param inlineExpression inline expression with {@code $->}
-     * @return result inline expression with {@code $}
+     * @return result processed inline expression defined by the SPI 
implementation.
      */
-    String handlePlaceHolder(String inlineExpression);
+    String handlePlaceHolder();
     
     /**
      * Split and evaluate inline expression.
      *
-     * @param inlineExpression inline expression
      * @return result list
      */
-    List<String> splitAndEvaluate(String inlineExpression);
+    List<String> splitAndEvaluate();
     
     /**
      * Evaluate closure.
      *
-     * @param inlineExpression inline expression
      * @return closure
+     * @throws UnsupportedOperationException In most cases, users should not 
implement this method, and the return value
+     *                                       of this method can only be a 
Groovy Closure.
      */
-    Closure<?> evaluateClosure(String inlineExpression);
+    default Closure<?> evaluateClosure() {
+        throw new UnsupportedOperationException("This SPI implementation does 
not support the use of this method.");
+    }
 }
diff --git a/pom.xml b/pom.xml
index aa743a7b073..c1a8677d656 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,7 +82,6 @@
         <jaxb.version>2.3.0</jaxb.version>
         <annotation-api.version>1.3.2</annotation-api.version>
         <activation-api.version>1.2.0</activation-api.version>
-        <truffle-api.version>21.2.0</truffle-api.version>
         
         <calcite.version>1.35.0</calcite.version>
         <immutables.version>2.9.3</immutables.version>
@@ -627,12 +626,6 @@
                 <version>${awaitility.version}</version>
                 <scope>test</scope>
             </dependency>
-            
-            <dependency>
-                <groupId>org.graalvm.truffle</groupId>
-                <artifactId>truffle-api</artifactId>
-                <version>${truffle-api.version}</version>
-            </dependency>
         </dependencies>
     </dependencyManagement>
     
@@ -1209,7 +1202,6 @@
         <profile>
             <id>generateStandardMetadata</id>
             <properties>
-                <truffle-api.version>23.0.1</truffle-api.version>
                 <jacoco.skip>true</jacoco.skip>
                 <maven.javadoc.skip>true</maven.javadoc.skip>
                 <checkstyle.skip>true</checkstyle.skip>
diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/common/checker/ShardingRuleConfigurationImportChecker.java
 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/common/checker/ShardingRuleConfigurationImportChecker.java
index 2260ffbdf90..6d95d37e16f 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/common/checker/ShardingRuleConfigurationImportChecker.java
+++ 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/common/checker/ShardingRuleConfigurationImportChecker.java
@@ -90,12 +90,12 @@ public final class ShardingRuleConfigurationImportChecker {
     }
     
     private Collection<String> getDataSourceNames(final 
ShardingAutoTableRuleConfiguration shardingAutoTableRuleConfig) {
-        Collection<String> actualDataSources = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(shardingAutoTableRuleConfig.getActualDataSources());
+        Collection<String> actualDataSources = 
InlineExpressionParserFactory.newInstance(shardingAutoTableRuleConfig.getActualDataSources()).splitAndEvaluate();
         return new HashSet<>(actualDataSources);
     }
     
     private Collection<String> getDataSourceNames(final 
ShardingTableRuleConfiguration shardingTableRuleConfig) {
-        Collection<String> actualDataNodes = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(shardingTableRuleConfig.getActualDataNodes());
+        Collection<String> actualDataNodes = 
InlineExpressionParserFactory.newInstance(shardingTableRuleConfig.getActualDataNodes()).splitAndEvaluate();
         return actualDataNodes.stream().map(each -> new 
DataNode(each).getDataSourceName()).collect(Collectors.toList());
     }
     
diff --git 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/dataset/DataSet.java
 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/dataset/DataSet.java
index c973887c289..0d393b83c70 100644
--- 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/dataset/DataSet.java
+++ 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/dataset/DataSet.java
@@ -65,7 +65,7 @@ public final class DataSet {
      * @return data set meta data belong to current data node
      */
     public DataSetMetaData findMetaData(final DataNode dataNode) {
-        Optional<DataSetMetaData> result = metaDataList.stream().filter(each 
-> 
contains(InlineExpressionParserFactory.newInstance().splitAndEvaluate(each.getDataNodes()),
 dataNode)).findFirst();
+        Optional<DataSetMetaData> result = metaDataList.stream().filter(each 
-> 
contains(InlineExpressionParserFactory.newInstance(each.getDataNodes()).splitAndEvaluate(),
 dataNode)).findFirst();
         return result.orElseThrow(() -> new 
IllegalArgumentException(String.format("Cannot find data node: %s", dataNode)));
     }
     
diff --git 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/composer/BatchE2EContainerComposer.java
 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/composer/BatchE2EContainerComposer.java
index d6b1341f633..d11bc084292 100644
--- 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/composer/BatchE2EContainerComposer.java
+++ 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/composer/BatchE2EContainerComposer.java
@@ -85,7 +85,7 @@ public final class BatchE2EContainerComposer extends 
E2EContainerComposer implem
         DataSet expected = getDataSet(actualUpdateCounts);
         assertThat("Only support single table for DML.", 
expected.getMetaDataList().size(), is(1));
         DataSetMetaData expectedDataSetMetaData = 
expected.getMetaDataList().get(0);
-        for (String each : 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(expectedDataSetMetaData.getDataNodes()))
 {
+        for (String each : 
InlineExpressionParserFactory.newInstance(expectedDataSetMetaData.getDataNodes()).splitAndEvaluate())
 {
             DataNode dataNode = new DataNode(each);
             DataSource dataSource = 
getActualDataSourceMap().get(dataNode.getDataSourceName());
             try (
diff --git 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/DDLE2EIT.java
 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/DDLE2EIT.java
index cc2bd74b670..1beba8c29f9 100644
--- 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/DDLE2EIT.java
+++ 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/DDLE2EIT.java
@@ -170,7 +170,7 @@ class DDLE2EIT {
     private void assertTableMetaData(final AssertionTestParameter testParam, 
final SingleE2EContainerComposer containerComposer) throws SQLException {
         String tableName = 
containerComposer.getAssertion().getInitialSQL().getAffectedTable();
         DataSetMetaData expected = 
containerComposer.getDataSet().findMetaData(tableName);
-        Collection<DataNode> dataNodes = 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(expected.getDataNodes()).stream().map(DataNode::new).collect(Collectors.toList());
+        Collection<DataNode> dataNodes = 
InlineExpressionParserFactory.newInstance(expected.getDataNodes()).splitAndEvaluate().stream().map(DataNode::new).collect(Collectors.toList());
         if (expected.getColumns().isEmpty()) {
             assertNotContainsTable(containerComposer, dataNodes);
             return;
diff --git 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java
 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java
index e1a71a5cf6d..1d6cb531ef1 100644
--- 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java
+++ 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java
@@ -93,7 +93,7 @@ public abstract class BaseDMLE2EIT {
     }
     
     private void assertDataSet(final AssertionTestParameter testParam, final 
SingleE2EContainerComposer containerComposer, final DataSetMetaData 
expectedDataSetMetaData) throws SQLException {
-        for (String each : 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(expectedDataSetMetaData.getDataNodes()))
 {
+        for (String each : 
InlineExpressionParserFactory.newInstance(expectedDataSetMetaData.getDataNodes()).splitAndEvaluate())
 {
             DataNode dataNode = new DataNode(each);
             DataSource dataSource = 
containerComposer.getActualDataSourceMap().get(dataNode.getDataSourceName());
             try (
diff --git 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/env/DataSetEnvironmentManager.java
 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/env/DataSetEnvironmentManager.java
index a611f55a036..8fb260e443d 100644
--- 
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/env/DataSetEnvironmentManager.java
+++ 
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/env/DataSetEnvironmentManager.java
@@ -167,7 +167,7 @@ public final class DataSetEnvironmentManager {
     
     private Map<String, Collection<String>> getDataNodeMap(final 
DataSetMetaData dataSetMetaData) {
         Map<String, Collection<String>> result = new LinkedHashMap<>();
-        for (String each : 
InlineExpressionParserFactory.newInstance().splitAndEvaluate(dataSetMetaData.getDataNodes()))
 {
+        for (String each : 
InlineExpressionParserFactory.newInstance(dataSetMetaData.getDataNodes()).splitAndEvaluate())
 {
             DataNode dataNode = new DataNode(each);
             if (!result.containsKey(dataNode.getDataSourceName())) {
                 result.put(dataNode.getDataSourceName(), new LinkedList<>());

Reply via email to