From 3b8668ef9b047fe1991268a4a65f737a559cf63f Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Fri, 14 Nov 2025 14:31:39 +0800
Subject: [PATCH 1/9] =?UTF-8?q?fixed:=20#6081=201.=E6=8A=BD=E5=8F=96Plugin?=
=?UTF-8?q?Data=E3=80=81SelectorData=20=E5=92=8C=20RuleData=20=E5=85=AC?=
=?UTF-8?q?=E5=85=B1=E9=83=A8=E5=88=86=E4=B8=BA=20BaseData=202.=20?=
=?UTF-8?q?=E8=A7=84=E5=88=99=E9=80=89=E6=8B=A9=E9=80=BB=E8=BE=91=E9=87=8D?=
=?UTF-8?q?=E6=9E=84=20=20=E5=AE=9A=E4=B9=89=E6=95=B0=E6=8D=AE=E5=86=B3?=
=?UTF-8?q?=E7=AD=96=E5=A4=84=E7=90=86=E7=B1=BB=EF=BC=8C=E6=8F=90=E5=8F=96?=
=?UTF-8?q?=E5=85=AC=E5=85=B1=E9=83=A8=E5=88=86=E7=9A=84=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E5=B9=B6=E5=81=9A=E5=B0=81=E8=A3=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../apache/shenyu/common/dto/BaseData.java | 107 +++++++++
.../apache/shenyu/common/dto/PluginData.java | 118 +---------
.../apache/shenyu/common/dto/RuleData.java | 220 ++++--------------
.../shenyu/common/dto/SelectorData.java | 194 ++++-----------
.../plugin/base/AbstractShenyuPlugin.java | 161 ++++++-------
.../maker/AbstractMatchDecisionMaker.java | 27 +++
.../base/maker/PluginDataDecisionMaker.java | 30 +++
.../base/maker/RuleDataDecisionMaker.java | 30 +++
.../base/maker/SelectorDataDecisionMaker.java | 30 +++
.../plugin/base/provider/DataProvider.java | 7 +
.../base/provider/PluginDataProvider.java | 15 ++
.../base/provider/RuleDataProvider.java | 15 ++
.../base/provider/SelectorDataProvider.java | 18 ++
13 files changed, 450 insertions(+), 522 deletions(-)
create mode 100644 shenyu-common/src/main/java/org/apache/shenyu/common/dto/BaseData.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
create mode 100644 shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/BaseData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/BaseData.java
new file mode 100644
index 000000000000..f9a95bbead05
--- /dev/null
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/BaseData.java
@@ -0,0 +1,107 @@
+package org.apache.shenyu.common.dto;
+
+public class BaseData {
+
+ protected String id;
+
+ protected String name;
+
+ protected Boolean enabled;
+
+ protected Integer sort;
+
+ protected String namespaceId;
+
+
+ /**
+ * get id.
+ *
+ * @return id
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * set id.
+ *
+ * @param id id
+ */
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ /**
+ * get name.
+ *
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * set name.
+ *
+ * @param name name
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * get enabled.
+ *
+ * @return enabled
+ */
+ public Boolean getEnabled() {
+ return enabled;
+ }
+
+
+ /**
+ * set enabled.
+ *
+ * @param enabled enabled
+ */
+ public void setEnabled(final Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ /**
+ * get sort.
+ *
+ * @return enabled
+ */
+ public Integer getSort() {
+ return sort;
+ }
+
+
+ /**
+ * set sort.
+ *
+ * @param sort sort value
+ */
+ public void setSort(final Integer sort) {
+ this.sort = sort;
+ }
+
+ /**
+ * get namespaceId.
+ *
+ * @return namespaceId
+ */
+ public String getNamespaceId() {
+ return namespaceId;
+ }
+
+ /**
+ * set namespaceId.
+ *
+ * @param namespaceId namespaceId
+ */
+ public void setNamespaceId(final String namespaceId) {
+ this.namespaceId = namespaceId;
+ }
+}
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java
index 1ed11aa14acd..7a6c462dd7d0 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java
@@ -24,24 +24,14 @@
*
* @since 2.0.0
*/
-public class PluginData {
-
- private String id;
-
- private String name;
+public class PluginData extends BaseData {
private String config;
private String role;
- private Boolean enabled;
-
- private Integer sort;
-
private String pluginJar;
- private String namespaceId;
-
/**
* no args constructor.
*/
@@ -132,41 +122,6 @@ public static Builder builder() {
return new Builder();
}
- /**
- * get id.
- *
- * @return id
- */
- public String getId() {
- return id;
- }
-
- /**
- * set id.
- *
- * @param id id
- */
- public void setId(final String id) {
- this.id = id;
- }
-
- /**
- * get name.
- *
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * set name.
- *
- * @param name name
- */
- public void setName(final String name) {
- this.name = name;
- }
/**
* get config.
@@ -204,14 +159,6 @@ public void setRole(final String role) {
this.role = role;
}
- /**
- * get enabled.
- *
- * @return enabled
- */
- public Boolean getEnabled() {
- return enabled;
- }
/**
* get pluginJar.
@@ -231,52 +178,6 @@ public void setPluginJar(final String pluginJar) {
this.pluginJar = pluginJar;
}
- /**
- * get sort.
- *
- * @return enabled
- */
- public Integer getSort() {
- return sort;
- }
-
-
- /**
- * set sort.
- *
- * @param sort sort value
- */
- public void setSort(final Integer sort) {
- this.sort = sort;
- }
-
- /**
- * set enabled.
- *
- * @param enabled enabled
- */
- public void setEnabled(final Boolean enabled) {
- this.enabled = enabled;
- }
-
- /**
- * get namespaceId.
- *
- * @return namespaceId
- */
- public String getNamespaceId() {
- return namespaceId;
- }
-
- /**
- * set namespaceId.
- *
- * @param namespaceId namespaceId
- */
- public void setNamespaceId(final String namespaceId) {
- this.namespaceId = namespaceId;
- }
-
@Override
public boolean equals(final Object o) {
if (this == o) {
@@ -287,8 +188,8 @@ public boolean equals(final Object o) {
}
PluginData that = (PluginData) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(config, that.config)
- && Objects.equals(role, that.role) && Objects.equals(enabled, that.enabled) && Objects.equals(sort, that.sort)
- && Objects.equals(pluginJar, that.pluginJar) && Objects.equals(namespaceId, that.namespaceId);
+ && Objects.equals(role, that.role) && Objects.equals(enabled, that.enabled) && Objects.equals(sort, that.sort)
+ && Objects.equals(pluginJar, that.pluginJar) && Objects.equals(namespaceId, that.namespaceId);
}
@Override
@@ -296,24 +197,13 @@ public int hashCode() {
return Objects.hash(id, name, config, role, enabled, sort, pluginJar, namespaceId);
}
- public static final class Builder {
-
- private String id;
-
- private String name;
+ public static final class Builder extends BaseData{
private String config;
private String role;
- private Boolean enabled;
-
- private Integer sort;
-
private String pluginJar;
-
- private String namespaceId;
-
/**
* no args constructor.
*/
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java
index 2e2efa05d4f6..d0d2abc736aa 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java
@@ -25,11 +25,7 @@
*
* @since 2.0.0
*/
-public class RuleData {
-
- private String id;
-
- private String name;
+public class RuleData extends BaseData{
private String pluginName;
@@ -40,10 +36,6 @@ public class RuleData {
*/
private Integer matchMode;
- private Integer sort;
-
- private Boolean enabled;
-
private Boolean loged;
/**
@@ -54,16 +46,11 @@ public class RuleData {
private List conditionDataList;
private List beforeConditionDataList;
-
+
/**
* match restful.
*/
private Boolean matchRestful;
-
- /**
- * namespaceId.
- */
- private String namespaceId;
/**
* no args constructor.
@@ -101,46 +88,6 @@ public static Builder builder() {
return new Builder();
}
- /**
- * get id.
- *
- * @return id
- */
- public String getId() {
- return id;
- }
-
- /**
- * set id.
- *
- * @param id id
- * @return this
- */
- public RuleData setId(final String id) {
- this.id = id;
- return this;
- }
-
- /**
- * get name.
- *
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * set name.
- *
- * @param name name
- * @return this
- */
- public RuleData setName(final String name) {
- this.name = name;
- return this;
- }
-
/**
* get pluginName.
*
@@ -201,46 +148,6 @@ public RuleData setMatchMode(final Integer matchMode) {
return this;
}
- /**
- * get sort.
- *
- * @return sort
- */
- public Integer getSort() {
- return sort;
- }
-
- /**
- * set sort.
- *
- * @param sort sort
- * @return this
- */
- public RuleData setSort(final Integer sort) {
- this.sort = sort;
- return this;
- }
-
- /**
- * get enabled.
- *
- * @return enabled
- */
- public Boolean getEnabled() {
- return enabled;
- }
-
- /**
- * set enabled.
- *
- * @param enabled enabled
- * @return this
- */
- public RuleData setEnabled(final Boolean enabled) {
- this.enabled = enabled;
- return this;
- }
-
/**
* get loged.
*
@@ -318,7 +225,7 @@ public List getBeforeConditionDataList() {
public void setBeforeConditionDataList(final List beforeConditionDataList) {
this.beforeConditionDataList = beforeConditionDataList;
}
-
+
/**
* get match restful.
*
@@ -327,7 +234,7 @@ public void setBeforeConditionDataList(final List beforeCondition
public Boolean getMatchRestful() {
return matchRestful;
}
-
+
/**
* set match restful.
*
@@ -336,23 +243,8 @@ public Boolean getMatchRestful() {
public void setMatchRestful(final Boolean matchRestful) {
this.matchRestful = matchRestful;
}
-
- /**
- * get namespaceId.
- * @return namespaceId
- */
- public String getNamespaceId() {
- return namespaceId;
- }
-
- /**
- * set namespaceId.
- * @param namespaceId namespaceId
- */
- public void setNamespaceId(final String namespaceId) {
- this.namespaceId = namespaceId;
- }
-
+
+
@Override
public boolean equals(final Object o) {
if (this == o) {
@@ -363,67 +255,63 @@ public boolean equals(final Object o) {
}
final RuleData ruleData = (RuleData) o;
return Objects.equals(id, ruleData.id)
- && Objects.equals(name, ruleData.name)
- && Objects.equals(pluginName, ruleData.pluginName)
- && Objects.equals(selectorId, ruleData.selectorId)
- && Objects.equals(matchMode, ruleData.matchMode)
- && Objects.equals(sort, ruleData.sort)
- && Objects.equals(enabled, ruleData.enabled)
- && Objects.equals(loged, ruleData.loged)
- && Objects.equals(handle, ruleData.handle)
- && Objects.equals(conditionDataList, ruleData.conditionDataList)
- && Objects.equals(beforeConditionDataList, ruleData.beforeConditionDataList)
- && Objects.equals(matchRestful, ruleData.matchRestful)
- && Objects.equals(namespaceId, ruleData.namespaceId);
+ && Objects.equals(name, ruleData.name)
+ && Objects.equals(pluginName, ruleData.pluginName)
+ && Objects.equals(selectorId, ruleData.selectorId)
+ && Objects.equals(matchMode, ruleData.matchMode)
+ && Objects.equals(sort, ruleData.sort)
+ && Objects.equals(enabled, ruleData.enabled)
+ && Objects.equals(loged, ruleData.loged)
+ && Objects.equals(handle, ruleData.handle)
+ && Objects.equals(conditionDataList, ruleData.conditionDataList)
+ && Objects.equals(beforeConditionDataList, ruleData.beforeConditionDataList)
+ && Objects.equals(matchRestful, ruleData.matchRestful)
+ && Objects.equals(namespaceId, ruleData.namespaceId);
}
@Override
public int hashCode() {
return Objects.hash(id, name, pluginName, selectorId, matchMode, sort, enabled, loged, handle, conditionDataList,
- beforeConditionDataList, matchRestful, namespaceId);
+ beforeConditionDataList, matchRestful, namespaceId);
}
@Override
public String toString() {
return "RuleData{"
- + "id='"
- + id
- + '\''
- + ", name='"
- + name
- + '\''
- + ", pluginName='"
- + pluginName
- + '\''
- + ", selectorId='"
- + selectorId
- + '\''
- + ", matchMode="
- + matchMode
- + ", sort="
- + sort
- + ", enabled="
- + enabled
- + ", loged="
- + loged
- + ", handle='"
- + handle
- + '\''
- + ", conditionDataList="
- + conditionDataList
- + ", matchRestful="
- + matchRestful
- + '}';
+ + "id='"
+ + id
+ + '\''
+ + ", name='"
+ + name
+ + '\''
+ + ", pluginName='"
+ + pluginName
+ + '\''
+ + ", selectorId='"
+ + selectorId
+ + '\''
+ + ", matchMode="
+ + matchMode
+ + ", sort="
+ + sort
+ + ", enabled="
+ + enabled
+ + ", loged="
+ + loged
+ + ", handle='"
+ + handle
+ + '\''
+ + ", conditionDataList="
+ + conditionDataList
+ + ", matchRestful="
+ + matchRestful
+ + '}';
}
/**
* class builder.
*/
- public static final class Builder {
-
- private String id;
-
- private String name;
+ public static final class Builder extends BaseData {
private String pluginName;
@@ -431,10 +319,6 @@ public static final class Builder {
private Integer matchMode;
- private Integer sort;
-
- private Boolean enabled;
-
private Boolean loged;
private String handle;
@@ -442,10 +326,8 @@ public static final class Builder {
private List conditionDataList;
private List beforeConditionDataList;
-
+
private Boolean matchRestful;
-
- private String namespaceId;
/**
* no args constructor.
@@ -582,7 +464,7 @@ public Builder beforeConditionDataList(final List beforeCondition
this.beforeConditionDataList = beforeConditionDataList;
return this;
}
-
+
/**
* build match restful.
*
@@ -593,7 +475,7 @@ public Builder matchRestful(final Boolean matchRestful) {
this.matchRestful = matchRestful;
return this;
}
-
+
/**
* build namespaceId.
*
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
index 616154c1a1c6..0749031a60a4 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
@@ -25,9 +25,7 @@
*
* @since 2.0.0
*/
-public class SelectorData {
-
- private String id;
+public class SelectorData extends BaseData {
private String pluginId;
@@ -36,8 +34,6 @@ public class SelectorData {
*/
private String pluginName;
- private String name;
-
/**
* matchMode(0 and 1 or).
*/
@@ -48,10 +44,6 @@ public class SelectorData {
*/
private Integer type;
- private Integer sort;
-
- private Boolean enabled;
-
private Boolean logged;
private Boolean continued = Boolean.TRUE;
@@ -67,11 +59,6 @@ public class SelectorData {
*/
private Boolean matchRestful;
- /**
- * namespaceId.
- */
- private String namespaceId;
-
/**
* no args constructor.
*/
@@ -110,23 +97,6 @@ public static Builder builder() {
return new Builder();
}
- /**
- * get id.
- *
- * @return id
- */
- public String getId() {
- return id;
- }
-
- /**
- * set id.
- *
- * @param id id
- */
- public void setId(final String id) {
- this.id = id;
- }
/**
* get pluginId.
@@ -164,23 +134,6 @@ public void setPluginName(final String pluginName) {
this.pluginName = pluginName;
}
- /**
- * get name.
- *
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * set name.
- *
- * @param name name
- */
- public void setName(final String name) {
- this.name = name;
- }
/**
* get matchMode.
@@ -218,42 +171,6 @@ public void setType(final Integer type) {
this.type = type;
}
- /**
- * get sort.
- *
- * @return sort
- */
- public Integer getSort() {
- return sort;
- }
-
- /**
- * set sort.
- *
- * @param sort sort
- */
- public void setSort(final Integer sort) {
- this.sort = sort;
- }
-
- /**
- * get enabled.
- *
- * @return enabled
- */
- public Boolean getEnabled() {
- return enabled;
- }
-
- /**
- * set enabled.
- *
- * @param enabled enabled
- */
- public void setEnabled(final Boolean enabled) {
- this.enabled = enabled;
- }
-
/**
* get logged.
*
@@ -365,24 +282,6 @@ public void setBeforeConditionList(final List beforeConditionList
this.beforeConditionList = beforeConditionList;
}
- /**
- * get namespaceId.
- *
- * @return namespaceId
- */
- public String getNamespaceId() {
- return namespaceId;
- }
-
- /**
- * set namespaceId.
- *
- * @param namespaceId namespaceId
- */
- public void setNamespaceId(final String namespaceId) {
- this.namespaceId = namespaceId;
- }
-
@Override
public boolean equals(final Object o) {
if (this == o) {
@@ -393,11 +292,11 @@ public boolean equals(final Object o) {
}
SelectorData that = (SelectorData) o;
return Objects.equals(id, that.id) && Objects.equals(pluginId, that.pluginId) && Objects.equals(pluginName, that.pluginName)
- && Objects.equals(name, that.name) && Objects.equals(matchMode, that.matchMode) && Objects.equals(type, that.type)
- && Objects.equals(sort, that.sort) && Objects.equals(enabled, that.enabled) && Objects.equals(logged, that.logged)
- && Objects.equals(continued, that.continued) && Objects.equals(handle, that.handle) && Objects.equals(conditionList, that.conditionList)
- && Objects.equals(beforeConditionList, that.beforeConditionList) && Objects.equals(matchRestful, that.matchRestful)
- && Objects.equals(namespaceId, that.namespaceId);
+ && Objects.equals(name, that.name) && Objects.equals(matchMode, that.matchMode) && Objects.equals(type, that.type)
+ && Objects.equals(sort, that.sort) && Objects.equals(enabled, that.enabled) && Objects.equals(logged, that.logged)
+ && Objects.equals(continued, that.continued) && Objects.equals(handle, that.handle) && Objects.equals(conditionList, that.conditionList)
+ && Objects.equals(beforeConditionList, that.beforeConditionList) && Objects.equals(matchRestful, that.matchRestful)
+ && Objects.equals(namespaceId, that.namespaceId);
}
@Override
@@ -408,63 +307,55 @@ public int hashCode() {
@Override
public String toString() {
return "SelectorData{"
- + "id='"
- + id
- + '\''
- + ", pluginId='"
- + pluginId
- + '\''
- + ", pluginName='"
- + pluginName
- + '\''
- + ", name='"
- + name
- + '\''
- + ", matchMode="
- + matchMode
- + ", type="
- + type
- + ", sort="
- + sort
- + ", enabled="
- + enabled
- + ", logged="
- + logged
- + ", continued="
- + continued
- + ", handle='"
- + handle
- + '\''
- + ", conditionList="
- + conditionList
- + ", matchRestful="
- + matchRestful
- + ", namespaceId="
- + namespaceId
- + '}';
+ + "id='"
+ + id
+ + '\''
+ + ", pluginId='"
+ + pluginId
+ + '\''
+ + ", pluginName='"
+ + pluginName
+ + '\''
+ + ", name='"
+ + name
+ + '\''
+ + ", matchMode="
+ + matchMode
+ + ", type="
+ + type
+ + ", sort="
+ + sort
+ + ", enabled="
+ + enabled
+ + ", logged="
+ + logged
+ + ", continued="
+ + continued
+ + ", handle='"
+ + handle
+ + '\''
+ + ", conditionList="
+ + conditionList
+ + ", matchRestful="
+ + matchRestful
+ + ", namespaceId="
+ + namespaceId
+ + '}';
}
/**
* class builder.
*/
- public static final class Builder {
-
- private String id;
+ public static final class Builder extends BaseData {
private String pluginId;
private String pluginName;
- private String name;
-
private Integer matchMode;
private Integer type;
- private Integer sort;
-
- private Boolean enabled;
-
private Boolean logged;
private Boolean continued;
@@ -476,9 +367,6 @@ public static final class Builder {
private Boolean matchRestful;
private List beforeConditionList;
-
- private String namespaceId;
-
/**
* no args constructor.
*/
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
index 46d019790507..38dbaf1ee605 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
@@ -37,6 +37,10 @@
import org.apache.shenyu.plugin.base.cache.BaseDataCache;
import org.apache.shenyu.plugin.base.cache.MatchDataCache;
import org.apache.shenyu.plugin.base.condition.strategy.MatchStrategyFactory;
+import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
+import org.apache.shenyu.plugin.base.maker.PluginDataDecisionMaker;
+import org.apache.shenyu.plugin.base.maker.RuleDataDecisionMaker;
+import org.apache.shenyu.plugin.base.maker.SelectorDataDecisionMaker;
import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
import org.apache.shenyu.plugin.base.trie.ShenyuTrieNode;
import org.slf4j.Logger;
@@ -60,13 +64,13 @@ public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
private static final Logger LOG = LoggerFactory.getLogger(AbstractShenyuPlugin.class);
private static final String URI_CONDITION_TYPE = "uri";
-
+
private ShenyuTrie selectorTrie;
-
+
private ShenyuTrie ruleTrie;
-
+
private ShenyuConfig.SelectorMatchCache selectorMatchConfig;
-
+
private ShenyuConfig.RuleMatchCache ruleMatchConfig;
/**
@@ -92,71 +96,56 @@ public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
public Mono execute(final ServerWebExchange exchange, final ShenyuPluginChain chain) {
initCacheConfig();
final String pluginName = named();
- PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
- // early exit
- if (Objects.isNull(pluginData) || !pluginData.getEnabled()) {
- return chain.execute(exchange);
- }
final String path = getRawPath(exchange);
- List selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
- if (CollectionUtils.isEmpty(selectors)) {
- return handleSelectorIfNull(pluginName, exchange, chain);
+
+ PluginDataDecisionMaker pluginDataDecisionMaker = new PluginDataDecisionMaker();
+ List pluginDataList = pluginDataDecisionMaker.getData(pluginName);
+ if (CollectionUtils.isEmpty(pluginDataList) || !pluginDataDecisionMaker.shouldContinue(pluginDataList.get(0))) {
+ return pluginDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
- SelectorData selectorData = obtainSelectorDataCacheIfEnabled(path);
- // handle Selector
- if (Objects.nonNull(selectorData) && StringUtils.isBlank(selectorData.getId())) {
- return handleSelectorIfNull(pluginName, exchange, chain);
+
+ SelectorDataDecisionMaker selectorDataDecisionMaker = new SelectorDataDecisionMaker();
+ List selectorDataList = selectorDataDecisionMaker.getData(pluginName);
+ if (CollectionUtils.isEmpty(selectorDataList)) {
+ return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
- if (Objects.isNull(selectorData)) {
- selectorData = trieMatchSelector(exchange, pluginName, path);
- if (Objects.isNull(selectorData)) {
- selectorData = defaultMatchSelector(exchange, selectors, path);
- if (Objects.isNull(selectorData)) {
- return handleSelectorIfNull(pluginName, exchange, chain);
- }
- }
+
+ SelectorData selectorData = selectorDataDecisionMaker.matchData(exchange, selectorDataList, path);
+ if (selectorData == null) {
+ return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
+
printLog(selectorData, pluginName);
- if (!selectorData.getContinued()) {
- // if continued, not match rules
+ if (!selectorDataDecisionMaker.shouldContinue(selectorData)) {
return doExecute(exchange, chain, selectorData, defaultRuleData(selectorData));
}
- List rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
- if (CollectionUtils.isEmpty(rules)) {
- return handleRuleIfNull(pluginName, exchange, chain);
+
+
+ RuleDataDecisionMaker ruleDataDecisionMaker = new RuleDataDecisionMaker();
+ List ruleDataList = ruleDataDecisionMaker.getData(selectorData.getId());
+ if (CollectionUtils.isEmpty(ruleDataList)) {
+ return ruleDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
+
if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
- //get last
- RuleData rule = rules.get(rules.size() - 1);
+ RuleData rule = ruleDataList.get(ruleDataList.size() - 1);
printLog(rule, pluginName);
return doExecute(exchange, chain, selectorData, rule);
}
- // lru map as L1 cache,the cache is enabled by default.
- // if the L1 cache fails to hit, using L2 cache based on trie cache.
- // if the L2 cache fails to hit, execute default strategy.
- RuleData ruleData = obtainRuleDataCacheIfEnabled(path);
- if (Objects.nonNull(ruleData) && Objects.isNull(ruleData.getId())) {
- return handleRuleIfNull(pluginName, exchange, chain);
- }
- if (Objects.isNull(ruleData)) {
- // L1 cache not exist data, try to get data through trie cache
- ruleData = trieMatchRule(exchange, selectorData, path);
- // trie cache fails to hit, execute default strategy
- if (Objects.isNull(ruleData)) {
- ruleData = defaultMatchRule(exchange, rules, path);
- if (Objects.isNull(ruleData)) {
- return handleRuleIfNull(pluginName, exchange, chain);
- }
- }
+
+ RuleData ruleData = ruleDataDecisionMaker.matchData(exchange, ruleDataList, path);
+ if (ruleData == null) {
+ return ruleDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
+
printLog(ruleData, pluginName);
return doExecute(exchange, chain, selectorData, ruleData);
}
-
+
protected String getRawPath(final ServerWebExchange exchange) {
return exchange.getRequest().getURI().getRawPath();
}
-
+
private void initCacheConfig() {
if (Objects.isNull(selectorMatchConfig) || Objects.isNull(ruleMatchConfig)) {
ShenyuConfig shenyuConfig = SpringBeanUtils.getInstance().getBean(ShenyuConfig.class);
@@ -168,18 +157,18 @@ private void initCacheConfig() {
ruleTrie = SpringBeanUtils.getInstance().getBean(TrieCacheTypeEnum.RULE.getTrieType());
}
}
-
+
private SelectorData obtainSelectorDataCacheIfEnabled(final String path) {
return selectorMatchConfig.getCache().getEnabled() ? MatchDataCache.getInstance().obtainSelectorData(named(), path) : null;
}
-
+
private RuleData obtainRuleDataCacheIfEnabled(final String path) {
return ruleMatchConfig.getCache().getEnabled() ? MatchDataCache.getInstance().obtainRuleData(named(), path) : null;
}
private void cacheSelectorData(final String path, final SelectorData selectorData) {
if (Boolean.FALSE.equals(selectorMatchConfig.getCache().getEnabled()) || Objects.isNull(selectorData)
- || Boolean.TRUE.equals(selectorData.getMatchRestful())) {
+ || Boolean.TRUE.equals(selectorData.getMatchRestful())) {
return;
}
int initialCapacity = selectorMatchConfig.getCache().getInitialCapacity();
@@ -196,11 +185,11 @@ private void cacheSelectorData(final String path, final SelectorData selectorDat
}
}
}
-
+
private void cacheRuleData(final String path, final RuleData ruleData) {
// if the ruleCache is disabled or rule data is null, not cache rule data.
if (Boolean.FALSE.equals(ruleMatchConfig.getCache().getEnabled()) || Objects.isNull(ruleData)
- || Boolean.TRUE.equals(ruleData.getMatchRestful())) {
+ || Boolean.TRUE.equals(ruleData.getMatchRestful())) {
return;
}
int initialCapacity = ruleMatchConfig.getCache().getInitialCapacity();
@@ -225,7 +214,7 @@ private RuleData defaultRuleData(final SelectorData selectorData) {
ruleData.setId(Constants.DEFAULT_RULE);
return ruleData;
}
-
+
/**
* Handle selector if null mono.
*
@@ -237,7 +226,7 @@ private RuleData defaultRuleData(final SelectorData selectorData) {
protected Mono handleSelectorIfNull(final String pluginName, final ServerWebExchange exchange, final ShenyuPluginChain chain) {
return chain.execute(exchange);
}
-
+
/**
* Handle rule if null mono.
*
@@ -252,9 +241,9 @@ protected Mono handleRuleIfNull(final String pluginName, final ServerWebEx
private Pair matchSelector(final ServerWebExchange exchange, final Collection selectors) {
List filterCollectors = selectors.stream()
- .filter(selector -> selector.getEnabled() && filterSelector(selector, exchange))
- .distinct()
- .collect(Collectors.toList());
+ .filter(selector -> selector.getEnabled() && filterSelector(selector, exchange))
+ .distinct()
+ .collect(Collectors.toList());
if (filterCollectors.size() > 1) {
return Pair.of(Boolean.FALSE, manyMatchSelector(filterCollectors));
} else {
@@ -266,14 +255,14 @@ private SelectorData manyMatchSelector(final List filterCollectors
//What needs to be dealt with here is the and condition. If the number of and conditions is the same and is matched at the same time,
// it will be sorted by the sort field.
Map>> collect =
- filterCollectors.stream().map(selector -> {
- boolean match = MatchModeEnum.match(selector.getMatchMode(), MatchModeEnum.AND);
- int sort = 0;
- if (match) {
- sort = selector.getConditionList().size();
- }
- return Pair.of(sort, selector);
- }).collect(Collectors.groupingBy(Pair::getLeft));
+ filterCollectors.stream().map(selector -> {
+ boolean match = MatchModeEnum.match(selector.getMatchMode(), MatchModeEnum.AND);
+ int sort = 0;
+ if (match) {
+ sort = selector.getConditionList().size();
+ }
+ return Pair.of(sort, selector);
+ }).collect(Collectors.groupingBy(Pair::getLeft));
Integer max = Collections.max(collect.keySet());
List> pairs = collect.get(max);
return pairs.stream().map(Pair::getRight).min(Comparator.comparing(SelectorData::getSort)).orElse(null);
@@ -291,9 +280,9 @@ private Boolean filterSelector(final SelectorData selector, final ServerWebExcha
private Pair matchRule(final ServerWebExchange exchange, final Collection rules) {
List filterRuleData = rules.stream()
- .filter(rule -> filterRule(rule, exchange))
- .distinct()
- .collect(Collectors.toList());
+ .filter(rule -> filterRule(rule, exchange))
+ .distinct()
+ .collect(Collectors.toList());
if (filterRuleData.size() > 1) {
return Pair.of(Boolean.FALSE, manyMatchRule(filterRuleData));
} else {
@@ -303,14 +292,14 @@ private Pair matchRule(final ServerWebExchange exchange, fina
private RuleData manyMatchRule(final List filterRuleData) {
Map>> collect =
- filterRuleData.stream().map(rule -> {
- boolean match = MatchModeEnum.match(rule.getMatchMode(), MatchModeEnum.AND);
- int sort = 0;
- if (match) {
- sort = rule.getConditionDataList().size();
- }
- return Pair.of(sort, rule);
- }).collect(Collectors.groupingBy(Pair::getLeft));
+ filterRuleData.stream().map(rule -> {
+ boolean match = MatchModeEnum.match(rule.getMatchMode(), MatchModeEnum.AND);
+ int sort = 0;
+ if (match) {
+ sort = rule.getConditionDataList().size();
+ }
+ return Pair.of(sort, rule);
+ }).collect(Collectors.groupingBy(Pair::getLeft));
Integer max = Collections.max(collect.keySet());
List> pairs = collect.get(max);
return pairs.stream().map(Pair::getRight).min(Comparator.comparing(RuleData::getSort)).orElse(null);
@@ -319,7 +308,7 @@ private RuleData manyMatchRule(final List filterRuleData) {
private Boolean filterRule(final RuleData ruleData, final ServerWebExchange exchange) {
return ruleData.getEnabled() && MatchStrategyFactory.match(ruleData.getMatchMode(), ruleData.getConditionDataList(), exchange);
}
-
+
private SelectorData trieMatchSelector(final ServerWebExchange exchange, final String pluginName, final String path) {
if (!selectorMatchConfig.getTrie().getEnabled()) {
return null;
@@ -347,7 +336,7 @@ private SelectorData trieMatchSelector(final ServerWebExchange exchange, final S
}
return selectorData;
}
-
+
private RuleData trieMatchRule(final ServerWebExchange exchange, final SelectorData selectorData, final String path) {
if (!ruleMatchConfig.getTrie().getEnabled()) {
return null;
@@ -376,7 +365,7 @@ private RuleData trieMatchRule(final ServerWebExchange exchange, final SelectorD
}
return ruleData;
}
-
+
private SelectorData defaultMatchSelector(final ServerWebExchange exchange, final List selectors, final String path) {
Pair matchSelectorPair = matchSelector(exchange, selectors);
SelectorData selectorData = matchSelectorPair.getRight();
@@ -396,7 +385,7 @@ private SelectorData defaultMatchSelector(final ServerWebExchange exchange, fina
return null;
}
}
-
+
private RuleData defaultMatchRule(final ServerWebExchange exchange, final List rules, final String path) {
Pair matchRulePair = matchRule(exchange, rules);
RuleData ruleData = matchRulePair.getRight();
@@ -416,7 +405,7 @@ private RuleData defaultMatchRule(final ServerWebExchange exchange, final List {
+ private final DataProvider dataProvider;
+
+ protected AbstractMatchDecisionMaker(DataProvider dataProvider) {
+ this.dataProvider = dataProvider;
+ }
+
+ public List getData(String key) {
+ return dataProvider.getData(key);
+ }
+
+ protected abstract Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain);
+
+ protected abstract T matchData(ServerWebExchange exchange, List dataList, String path);
+
+ protected abstract boolean shouldContinue(T data);
+}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
new file mode 100644
index 000000000000..7513086ac087
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
@@ -0,0 +1,30 @@
+package org.apache.shenyu.plugin.base.maker;
+
+import org.apache.shenyu.common.dto.PluginData;
+import org.apache.shenyu.plugin.api.ShenyuPluginChain;
+import org.apache.shenyu.plugin.base.provider.PluginDataProvider;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+public class PluginDataDecisionMaker extends AbstractMatchDecisionMaker {
+ public PluginDataDecisionMaker() {
+ super(new PluginDataProvider());
+ }
+
+ @Override
+ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
+ return chain.execute(exchange);
+ }
+
+ @Override
+ protected PluginData matchData(ServerWebExchange exchange, List dataList, String path) {
+ return dataList.isEmpty() ? null : dataList.get(0);
+ }
+
+ @Override
+ public boolean shouldContinue(PluginData data) {
+ return data != null && data.getEnabled();
+ }
+}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
new file mode 100644
index 000000000000..d75a11c8282d
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
@@ -0,0 +1,30 @@
+package org.apache.shenyu.plugin.base.maker;
+
+import org.apache.shenyu.common.dto.RuleData;
+import org.apache.shenyu.plugin.api.ShenyuPluginChain;
+import org.apache.shenyu.plugin.base.provider.RuleDataProvider;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+public class RuleDataDecisionMaker extends AbstractMatchDecisionMaker {
+ public RuleDataDecisionMaker() {
+ super(new RuleDataProvider());
+ }
+
+ @Override
+ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
+ return chain.execute(exchange);
+ }
+
+ @Override
+ public RuleData matchData(ServerWebExchange exchange, List dataList, String path) {
+ return dataList.isEmpty() ? null : dataList.get(0);
+ }
+
+ @Override
+ protected boolean shouldContinue(RuleData data) {
+ return data != null && data.getEnabled();
+ }
+}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
new file mode 100644
index 000000000000..ff373d026f8c
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
@@ -0,0 +1,30 @@
+package org.apache.shenyu.plugin.base.maker;
+
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.plugin.api.ShenyuPluginChain;
+import org.apache.shenyu.plugin.base.provider.SelectorDataProvider;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+public class SelectorDataDecisionMaker extends AbstractMatchDecisionMaker {
+ public SelectorDataDecisionMaker() {
+ super(new SelectorDataProvider());
+ }
+
+ @Override
+ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
+ return chain.execute(exchange);
+ }
+
+ @Override
+ public SelectorData matchData(ServerWebExchange exchange, List dataList, String path) {
+ return dataList.isEmpty() ? null : dataList.get(0);
+ }
+
+ @Override
+ public boolean shouldContinue(SelectorData data) {
+ return data != null && data.getEnabled();
+ }
+}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
new file mode 100644
index 000000000000..7bed0ebf1195
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
@@ -0,0 +1,7 @@
+package org.apache.shenyu.plugin.base.provider;
+
+import java.util.List;
+
+public interface DataProvider {
+ List getData(String key);
+}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
new file mode 100644
index 000000000000..b5e6697ad3d0
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
@@ -0,0 +1,15 @@
+package org.apache.shenyu.plugin.base.provider;
+
+import org.apache.shenyu.common.dto.PluginData;
+import org.apache.shenyu.plugin.base.cache.BaseDataCache;
+
+import java.util.Collections;
+import java.util.List;
+
+public class PluginDataProvider implements DataProvider {
+ @Override
+ public List getData(String pluginName) {
+ PluginData data = BaseDataCache.getInstance().obtainPluginData(pluginName);
+ return data != null ? Collections.singletonList(data) : Collections.emptyList();
+ }
+}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
new file mode 100644
index 000000000000..f6b73c8b9b88
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
@@ -0,0 +1,15 @@
+package org.apache.shenyu.plugin.base.provider;
+import org.apache.shenyu.common.dto.RuleData;
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.plugin.base.cache.BaseDataCache;
+
+import java.util.Collections;
+import java.util.List;
+
+public class RuleDataProvider implements DataProvider {
+ @Override
+ public List getData(String ruleName) {
+ List data = BaseDataCache.getInstance().obtainRuleData(ruleName);
+ return data != null ? data : Collections.emptyList();
+ }
+}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
new file mode 100644
index 000000000000..d50dc4f80122
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
@@ -0,0 +1,18 @@
+package org.apache.shenyu.plugin.base.provider;
+
+
+
+
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.plugin.base.cache.BaseDataCache;
+
+import java.util.Collections;
+import java.util.List;
+
+public class SelectorDataProvider implements DataProvider {
+ @Override
+ public List getData(String selectorName) {
+ List data = BaseDataCache.getInstance().obtainSelectorData(selectorName);
+ return data != null ? data : Collections.emptyList();
+ }
+}
\ No newline at end of file
From c9a42172ef1d2185e18bfb5a2be8bc334e50835a Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Fri, 14 Nov 2025 15:06:17 +0800
Subject: [PATCH 2/9] =?UTF-8?q?fixed:=20=E8=A7=A3=E5=86=B3=E4=B8=8E?=
=?UTF-8?q?=E4=B8=BB=E5=88=86=E6=94=AF=E5=86=B2=E7=AA=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../apache/shenyu/common/dto/PluginData.java | 32 +++++++------------
.../apache/shenyu/common/dto/RuleData.java | 20 ++++++------
.../shenyu/common/dto/SelectorData.java | 20 ++++++------
3 files changed, 31 insertions(+), 41 deletions(-)
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java
index a93e39e3f6b9..99f83720c550 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java
@@ -180,24 +180,14 @@ public int hashCode() {
return Objects.hash(getId(), getName(), config, role, getEnabled(), getSort(), pluginJar, getNamespaceId());
}
- public static final class Builder {
-
- private String id;
-
- private String name;
+ public static final class Builder extends BaseData {
private String config;
private String role;
- private Boolean enabled;
-
- private Integer sort;
-
private String pluginJar;
- private String namespaceId;
-
/**
* no args constructor.
*/
@@ -220,7 +210,7 @@ public static Builder builder() {
* @return this
*/
public Builder id(final String id) {
- this.id = id;
+ setId(id);
return this;
}
@@ -231,7 +221,7 @@ public Builder id(final String id) {
* @return this
*/
public Builder name(final String name) {
- this.name = name;
+ setName(name);
return this;
}
@@ -264,7 +254,7 @@ public Builder role(final String role) {
* @return this
*/
public Builder enabled(final Boolean enabled) {
- this.enabled = enabled;
+ setEnabled(enabled);
return this;
}
@@ -275,7 +265,7 @@ public Builder enabled(final Boolean enabled) {
* @return this
*/
public Builder sort(final Integer sort) {
- this.sort = sort;
+ setSort(sort);
return this;
}
@@ -297,7 +287,7 @@ public Builder pluginJar(final String pluginJar) {
* @return this
*/
public Builder namespaceId(final String namespaceId) {
- this.namespaceId = namespaceId;
+ setNamespaceId(namespaceId);
return this;
}
@@ -308,14 +298,14 @@ public Builder namespaceId(final String namespaceId) {
*/
public PluginData build() {
PluginData pluginData = new PluginData();
- pluginData.setId(id);
- pluginData.setName(name);
+ pluginData.setId(getId());
+ pluginData.setName(getName());
pluginData.setConfig(config);
pluginData.setRole(role);
- pluginData.setEnabled(enabled);
- pluginData.setSort(sort);
+ pluginData.setEnabled(getEnabled());
+ pluginData.setSort(getSort());
pluginData.setPluginJar(pluginJar);
- pluginData.setNamespaceId(namespaceId);
+ pluginData.setNamespaceId(getNamespaceId());
return pluginData;
}
}
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java
index b431c51954e6..9a6c0b64d997 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java
@@ -64,19 +64,19 @@ public RuleData() {
* @param builder builder
*/
private RuleData(final Builder builder) {
- this.setId(builder.id);
- this.setName(builder.name);
+ this.setId(builder.getId());
+ this.setName(builder.getName());
this.pluginName = builder.pluginName;
this.selectorId = builder.selectorId;
this.matchMode = builder.matchMode;
- this.setSort(builder.sort);
- this.setEnabled(builder.enabled);
+ this.setSort(builder.getSort());
+ this.setEnabled(builder.getEnabled());
this.loged = builder.loged;
this.handle = builder.handle;
this.conditionDataList = builder.conditionDataList;
this.beforeConditionDataList = builder.beforeConditionDataList;
this.matchRestful = builder.matchRestful;
- this.setNamespaceId(builder.namespaceId);
+ this.setNamespaceId(builder.getNamespaceId());
}
/**
@@ -405,7 +405,7 @@ public RuleData build() {
* @return this
*/
public Builder id(final String id) {
- this.id = id;
+ setId(id);
return this;
}
@@ -416,7 +416,7 @@ public Builder id(final String id) {
* @return this
*/
public Builder name(final String name) {
- this.name = name;
+ setName(name);
return this;
}
@@ -460,7 +460,7 @@ public Builder matchMode(final Integer matchMode) {
* @return this
*/
public Builder sort(final Integer sort) {
- this.sort = sort;
+ setSort(sort);
return this;
}
@@ -471,7 +471,7 @@ public Builder sort(final Integer sort) {
* @return this
*/
public Builder enabled(final Boolean enabled) {
- this.enabled = enabled;
+ setEnabled(enabled);
return this;
}
@@ -537,7 +537,7 @@ public Builder matchRestful(final Boolean matchRestful) {
* @return this
*/
public Builder namespaceId(final String namespaceId) {
- this.namespaceId = namespaceId;
+ setNamespaceId(namespaceId);
return this;
}
}
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
index ae2d7b92421d..c688b72b1aaf 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
@@ -71,21 +71,21 @@ public SelectorData() {
* @param builder builder
*/
private SelectorData(final Builder builder) {
- this.setId(builder.id);
+ this.setId(builder.getId());
this.pluginId = builder.pluginId;
this.pluginName = builder.pluginName;
- this.setName(builder.name);
+ this.setName(builder.getName());
this.matchMode = builder.matchMode;
this.type = builder.type;
- this.setSort(builder.sort);
- this.setEnabled(builder.enabled);
+ this.setSort(builder.getSort());
+ this.setEnabled(builder.getEnabled());
this.logged = builder.logged;
this.continued = builder.continued;
this.handle = builder.handle;
this.conditionList = builder.conditionList;
this.matchRestful = builder.matchRestful;
this.beforeConditionList = builder.beforeConditionList;
- this.setNamespaceId(builder.namespaceId);
+ this.setNamespaceId(builder.getNamespaceId());
}
/**
@@ -388,7 +388,7 @@ public SelectorData build() {
* @return this
*/
public Builder id(final String id) {
- this.id = id;
+ setId(id);
return this;
}
@@ -421,7 +421,7 @@ public Builder pluginName(final String pluginName) {
* @return this
*/
public Builder name(final String name) {
- this.name = name;
+ setName(name);
return this;
}
@@ -454,7 +454,7 @@ public Builder type(final Integer type) {
* @return this
*/
public Builder sort(final Integer sort) {
- this.sort = sort;
+ setSort(sort);
return this;
}
@@ -465,7 +465,7 @@ public Builder sort(final Integer sort) {
* @return this
*/
public Builder enabled(final Boolean enabled) {
- this.enabled = enabled;
+ setEnabled(enabled);
return this;
}
@@ -542,7 +542,7 @@ public Builder beforeConditionList(final List beforeConditionList
* @return this
*/
public Builder namespaceId(final String namespaceId) {
- this.namespaceId = namespaceId;
+ setNamespaceId(namespaceId);
return this;
}
}
From 837f02a8a4a7d9a811651201880e3214973f1adc Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Thu, 27 Nov 2025 16:49:34 +0800
Subject: [PATCH 3/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DAI=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../plugin/base/AbstractShenyuPlugin.java | 7 ++--
.../base/maker/PluginDataDecisionMaker.java | 2 +-
.../base/maker/RuleDataDecisionMaker.java | 2 +-
.../base/maker/SelectorDataDecisionMaker.java | 2 +-
.../plugin/base/provider/DataProvider.java | 16 +++++++++
.../base/provider/PluginDataProvider.java | 35 +++++++++++++++++++
.../base/provider/SelectorDataProvider.java | 3 --
7 files changed, 59 insertions(+), 8 deletions(-)
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
index 38dbaf1ee605..9eea4dab173d 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
@@ -73,6 +73,10 @@ public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
private ShenyuConfig.RuleMatchCache ruleMatchConfig;
+ private SelectorDataDecisionMaker selectorDataDecisionMaker = new SelectorDataDecisionMaker();
+
+ private RuleDataDecisionMaker ruleDataDecisionMaker = new RuleDataDecisionMaker();
+
/**
* this is Template Method child has implements your own logic.
*
@@ -104,7 +108,6 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
return pluginDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
- SelectorDataDecisionMaker selectorDataDecisionMaker = new SelectorDataDecisionMaker();
List selectorDataList = selectorDataDecisionMaker.getData(pluginName);
if (CollectionUtils.isEmpty(selectorDataList)) {
return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
@@ -121,7 +124,7 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
}
- RuleDataDecisionMaker ruleDataDecisionMaker = new RuleDataDecisionMaker();
+
List ruleDataList = ruleDataDecisionMaker.getData(selectorData.getId());
if (CollectionUtils.isEmpty(ruleDataList)) {
return ruleDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
index 7513086ac087..f02624af5fea 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
@@ -19,7 +19,7 @@ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, She
}
@Override
- protected PluginData matchData(ServerWebExchange exchange, List dataList, String path) {
+ public PluginData matchData(ServerWebExchange exchange, List dataList, String path) {
return dataList.isEmpty() ? null : dataList.get(0);
}
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
index d75a11c8282d..3136095767d9 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
@@ -24,7 +24,7 @@ public RuleData matchData(ServerWebExchange exchange, List dataList, S
}
@Override
- protected boolean shouldContinue(RuleData data) {
+ public boolean shouldContinue(RuleData data) {
return data != null && data.getEnabled();
}
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
index ff373d026f8c..6b270d8c7cb5 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
@@ -25,6 +25,6 @@ public SelectorData matchData(ServerWebExchange exchange, List dat
@Override
public boolean shouldContinue(SelectorData data) {
- return data != null && data.getEnabled();
+ return data != null && data.getEnabled() && data.getContinued();
}
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
index 7bed0ebf1195..c2d8a5b5b97d 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
@@ -2,6 +2,22 @@
import java.util.List;
+/**
+ * A generic interface for providing data based on a given key.
+ *
+ * Implementations of this interface are responsible for retrieving a list of data items
+ * of type {@code T} associated with the specified key. This can be used in plugin systems
+ * or other contexts where data needs to be fetched dynamically.
+ *
+ * @param Names of various data types
+ */
public interface DataProvider {
+ /**
+ * Retrieves a list of data items associated with the specified key.
+ *
+ * @param key the key used to look up the data; its meaning is defined by the implementation
+ * @return a list of data items of type {@code T} associated with the given key,
+ * or an empty list if no data is found
+ */
List getData(String key);
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
index b5e6697ad3d0..b31987c9f01f 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
@@ -6,7 +6,42 @@
import java.util.Collections;
import java.util.List;
+/**
+ * A concrete implementation of the data provider pattern for retrieving plugin data
+ * in the ShenYu gateway system.
+ *
+ * This class is responsible for fetching {@link PluginData} objects from the underlying
+ * data cache ({@link BaseDataCache}) based on the provided plugin name. It implements
+ * the {@code DataProvider} interface, providing a standardized way to
+ * access plugin configuration data throughout the application.
+ *
+ *
+ * In the ShenYu plugin architecture, this class serves as a specific layer in the data
+ * access mechanism, interacting with the system's caching infrastructure through an
+ * data provider interface to efficiently supply plugin information to
+ * upstream services or components that require it.
+ *
+ *
+ * @see org.apache.shenyu.plugin.base.cache.BaseDataCache
+ * @see PluginData
+ */
public class PluginDataProvider implements DataProvider {
+
+ /**
+ * Retrieves plugin data from the base data cache for the specified plugin name.
+ *
+ * This method queries the internally maintained cache instance. If plugin data
+ * matching the given name is found, it is wrapped in a singleton list and returned.
+ * If no matching data is found (i.e., the plugin name does not exist in the cache),
+ * an empty immutable list is returned.
+ *
+ *
+ * @param pluginName the name of the plugin to retrieve. This parameter should not be null,
+ * though the current implementation may return an empty list rather than
+ * throwing an exception for null values.
+ * @return an immutable list containing a single {@link PluginData} object if the plugin
+ * is found, otherwise an empty immutable list. The return value will never be null.
+ */
@Override
public List getData(String pluginName) {
PluginData data = BaseDataCache.getInstance().obtainPluginData(pluginName);
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
index d50dc4f80122..9339d2b4a239 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
@@ -1,8 +1,5 @@
package org.apache.shenyu.plugin.base.provider;
-
-
-
import org.apache.shenyu.common.dto.SelectorData;
import org.apache.shenyu.plugin.base.cache.BaseDataCache;
From 0148888a668c38edcc79624c14941cd08c334357 Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Tue, 2 Dec 2025 17:38:54 +0800
Subject: [PATCH 4/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DAI=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA=E7=9A=84=E6=B2=A1=E6=9C=89=E5=8C=B9=E9=85=8D=E7=BC=93?=
=?UTF-8?q?=E5=AD=98=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../plugin/base/AbstractShenyuPlugin.java | 127 ++---------------
.../maker/AbstractMatchDecisionMaker.java | 4 +-
.../base/maker/RuleDataDecisionMaker.java | 43 +++++-
.../base/maker/SelectorDataDecisionMaker.java | 131 +++++++++++++++++-
4 files changed, 180 insertions(+), 125 deletions(-)
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
index 9eea4dab173d..0414c2fa21eb 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
@@ -63,13 +63,11 @@ public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
private static final Logger LOG = LoggerFactory.getLogger(AbstractShenyuPlugin.class);
- private static final String URI_CONDITION_TYPE = "uri";
+// private static final String URI_CONDITION_TYPE = "uri";
- private ShenyuTrie selectorTrie;
- private ShenyuTrie ruleTrie;
- private ShenyuConfig.SelectorMatchCache selectorMatchConfig;
+ private ShenyuTrie ruleTrie;
private ShenyuConfig.RuleMatchCache ruleMatchConfig;
@@ -77,6 +75,8 @@ public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
private RuleDataDecisionMaker ruleDataDecisionMaker = new RuleDataDecisionMaker();
+ private PluginDataDecisionMaker pluginDataDecisionMaker = new PluginDataDecisionMaker();
+
/**
* this is Template Method child has implements your own logic.
*
@@ -102,7 +102,7 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
final String pluginName = named();
final String path = getRawPath(exchange);
- PluginDataDecisionMaker pluginDataDecisionMaker = new PluginDataDecisionMaker();
+
List pluginDataList = pluginDataDecisionMaker.getData(pluginName);
if (CollectionUtils.isEmpty(pluginDataList) || !pluginDataDecisionMaker.shouldContinue(pluginDataList.get(0))) {
return pluginDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
@@ -113,7 +113,7 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
- SelectorData selectorData = selectorDataDecisionMaker.matchData(exchange, selectorDataList, path);
+ SelectorData selectorData = selectorDataDecisionMaker.matchData(exchange,pluginName, selectorDataList, path, selectorMatchConfig, selectorTrie);
if (selectorData == null) {
return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
@@ -169,25 +169,6 @@ private RuleData obtainRuleDataCacheIfEnabled(final String path) {
return ruleMatchConfig.getCache().getEnabled() ? MatchDataCache.getInstance().obtainRuleData(named(), path) : null;
}
- private void cacheSelectorData(final String path, final SelectorData selectorData) {
- if (Boolean.FALSE.equals(selectorMatchConfig.getCache().getEnabled()) || Objects.isNull(selectorData)
- || Boolean.TRUE.equals(selectorData.getMatchRestful())) {
- return;
- }
- int initialCapacity = selectorMatchConfig.getCache().getInitialCapacity();
- long maximumSize = selectorMatchConfig.getCache().getMaximumSize();
- if (StringUtils.isBlank(selectorData.getId())) {
- MatchDataCache.getInstance().cacheSelectorData(path, selectorData, initialCapacity, maximumSize);
- return;
- }
- List conditionList = selectorData.getConditionList();
- if (CollectionUtils.isNotEmpty(conditionList)) {
- boolean isUriCondition = conditionList.stream().allMatch(v -> URI_CONDITION_TYPE.equals(v.getParamType()));
- if (isUriCondition) {
- MatchDataCache.getInstance().cacheSelectorData(path, selectorData, initialCapacity, maximumSize);
- }
- }
- }
private void cacheRuleData(final String path, final RuleData ruleData) {
// if the ruleCache is disabled or rule data is null, not cache rule data.
@@ -242,45 +223,6 @@ protected Mono handleRuleIfNull(final String pluginName, final ServerWebEx
return chain.execute(exchange);
}
- private Pair matchSelector(final ServerWebExchange exchange, final Collection selectors) {
- List filterCollectors = selectors.stream()
- .filter(selector -> selector.getEnabled() && filterSelector(selector, exchange))
- .distinct()
- .collect(Collectors.toList());
- if (filterCollectors.size() > 1) {
- return Pair.of(Boolean.FALSE, manyMatchSelector(filterCollectors));
- } else {
- return Pair.of(Boolean.TRUE, filterCollectors.stream().findFirst().orElse(null));
- }
- }
-
- private SelectorData manyMatchSelector(final List filterCollectors) {
- //What needs to be dealt with here is the and condition. If the number of and conditions is the same and is matched at the same time,
- // it will be sorted by the sort field.
- Map>> collect =
- filterCollectors.stream().map(selector -> {
- boolean match = MatchModeEnum.match(selector.getMatchMode(), MatchModeEnum.AND);
- int sort = 0;
- if (match) {
- sort = selector.getConditionList().size();
- }
- return Pair.of(sort, selector);
- }).collect(Collectors.groupingBy(Pair::getLeft));
- Integer max = Collections.max(collect.keySet());
- List> pairs = collect.get(max);
- return pairs.stream().map(Pair::getRight).min(Comparator.comparing(SelectorData::getSort)).orElse(null);
- }
-
- private Boolean filterSelector(final SelectorData selector, final ServerWebExchange exchange) {
- if (selector.getType() == SelectorTypeEnum.CUSTOM_FLOW.getCode()) {
- if (CollectionUtils.isEmpty(selector.getConditionList())) {
- return false;
- }
- return MatchStrategyFactory.match(selector.getMatchMode(), selector.getConditionList(), exchange);
- }
- return true;
- }
-
private Pair matchRule(final ServerWebExchange exchange, final Collection rules) {
List filterRuleData = rules.stream()
.filter(rule -> filterRule(rule, exchange))
@@ -312,62 +254,9 @@ private Boolean filterRule(final RuleData ruleData, final ServerWebExchange exch
return ruleData.getEnabled() && MatchStrategyFactory.match(ruleData.getMatchMode(), ruleData.getConditionDataList(), exchange);
}
- private SelectorData trieMatchSelector(final ServerWebExchange exchange, final String pluginName, final String path) {
- if (!selectorMatchConfig.getTrie().getEnabled()) {
- return null;
- }
- SelectorData selectorData = null;
- ShenyuTrieNode shenyuTrieNode = selectorTrie.match(path, pluginName);
- if (Objects.nonNull(shenyuTrieNode)) {
- LogUtils.info(LOG, "{} selector match path from shenyu trie, path:{}", pluginName, path);
- List> collection = shenyuTrieNode.getPathCache().get(pluginName);
- if (CollectionUtils.isNotEmpty(collection)) {
- Pair selectorDataPair;
- if (collection.size() > 1) {
- selectorDataPair = matchSelector(exchange, ListUtil.castList(collection, SelectorData.class::cast));
- } else {
- Object selectorObj = collection.stream().findFirst().orElse(null);
- SelectorData selector = Objects.nonNull(selectorObj) ? (SelectorData) selectorObj : null;
- boolean cached = Objects.nonNull(selector) && selector.getConditionList().stream().allMatch(condition -> URI_CONDITION_TYPE.equals(condition.getParamType()));
- selectorDataPair = Pair.of(cached, selector);
- }
- selectorData = selectorDataPair.getRight();
- if (selectorDataPair.getLeft() && Objects.nonNull(selectorData)) {
- cacheSelectorData(path, selectorData);
- }
- }
- }
- return selectorData;
- }
- private RuleData trieMatchRule(final ServerWebExchange exchange, final SelectorData selectorData, final String path) {
- if (!ruleMatchConfig.getTrie().getEnabled()) {
- return null;
- }
- RuleData ruleData = null;
- ShenyuTrieNode shenyuTrieNode = ruleTrie.match(path, selectorData.getId());
- if (Objects.nonNull(shenyuTrieNode)) {
- LogUtils.info(LOG, "{} rule match path from shenyu trie", named());
- List> collection = shenyuTrieNode.getPathCache().get(selectorData.getId());
- if (CollectionUtils.isNotEmpty(collection)) {
- Pair ruleDataPair;
- if (collection.size() > 1) {
- ruleDataPair = matchRule(exchange, ListUtil.castList(collection, RuleData.class::cast));
- } else {
- Object ruleObj = collection.stream().findFirst().orElse(null);
- RuleData rule = Objects.nonNull(ruleObj) ? (RuleData) ruleObj : null;
- boolean cached = Objects.nonNull(rule) && rule.getConditionDataList().stream().allMatch(condition -> URI_CONDITION_TYPE.equals(condition.getParamType()));
- ruleDataPair = Pair.of(cached, rule);
- }
- ruleData = ruleDataPair.getRight();
- if (ruleDataPair.getLeft() && Objects.nonNull(ruleData)) {
- // exist only one rule data, cache rule
- cacheRuleData(path, ruleData);
- }
- }
- }
- return ruleData;
- }
+
+
private SelectorData defaultMatchSelector(final ServerWebExchange exchange, final List selectors, final String path) {
Pair matchSelectorPair = matchSelector(exchange, selectors);
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
index 2f823b8d918f..555283b8addb 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
@@ -1,8 +1,10 @@
package org.apache.shenyu.plugin.base.maker;
+import org.apache.shenyu.common.config.ShenyuConfig;
import org.apache.shenyu.common.dto.BaseData;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
import org.apache.shenyu.plugin.base.provider.DataProvider;
+import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@@ -21,7 +23,7 @@ public List getData(String key) {
protected abstract Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain);
- protected abstract T matchData(ServerWebExchange exchange, List dataList, String path);
+ protected abstract T matchData(ServerWebExchange exchange, String dataName, List dataList, String path, ShenyuConfig.SelectorMatchCache selectorMatchConfig, ShenyuTrie selectorTrie);
protected abstract boolean shouldContinue(T data);
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
index 3136095767d9..ec7fd69e7068 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
@@ -1,12 +1,21 @@
package org.apache.shenyu.plugin.base.maker;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.shenyu.common.config.ShenyuConfig;
import org.apache.shenyu.common.dto.RuleData;
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.utils.ListUtil;
+import org.apache.shenyu.common.utils.LogUtils;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
import org.apache.shenyu.plugin.base.provider.RuleDataProvider;
+import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
+import org.apache.shenyu.plugin.base.trie.ShenyuTrieNode;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
+import java.util.Objects;
public class RuleDataDecisionMaker extends AbstractMatchDecisionMaker {
public RuleDataDecisionMaker() {
@@ -19,12 +28,42 @@ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, She
}
@Override
- public RuleData matchData(ServerWebExchange exchange, List dataList, String path) {
- return dataList.isEmpty() ? null : dataList.get(0);
+ public RuleData matchData(ServerWebExchange exchange, String ruleName, List dataList, String path, ShenyuConfig.SelectorMatchCache selectorMatchConfig, ShenyuTrie selectorTrie) {
+ return dataList.isEmpty() ? trieMatchRule() : dataList.get(0);
}
@Override
public boolean shouldContinue(RuleData data) {
return data != null && data.getEnabled();
}
+
+
+ private RuleData trieMatchRule(final ServerWebExchange exchange, final SelectorData selectorData, final String path) {
+ if (!ruleMatchConfig.getTrie().getEnabled()) {
+ return null;
+ }
+ RuleData ruleData = null;
+ ShenyuTrieNode shenyuTrieNode = ruleTrie.match(path, selectorData.getId());
+ if (Objects.nonNull(shenyuTrieNode)) {
+ LogUtils.info(LOG, "{} rule match path from shenyu trie", named());
+ List> collection = shenyuTrieNode.getPathCache().get(selectorData.getId());
+ if (CollectionUtils.isNotEmpty(collection)) {
+ Pair ruleDataPair;
+ if (collection.size() > 1) {
+ ruleDataPair = matchRule(exchange, ListUtil.castList(collection, RuleData.class::cast));
+ } else {
+ Object ruleObj = collection.stream().findFirst().orElse(null);
+ RuleData rule = Objects.nonNull(ruleObj) ? (RuleData) ruleObj : null;
+ boolean cached = Objects.nonNull(rule) && rule.getConditionDataList().stream().allMatch(condition -> URI_CONDITION_TYPE.equals(condition.getParamType()));
+ ruleDataPair = Pair.of(cached, rule);
+ }
+ ruleData = ruleDataPair.getRight();
+ if (ruleDataPair.getLeft() && Objects.nonNull(ruleData)) {
+ // exist only one rule data, cache rule
+ cacheRuleData(path, ruleData);
+ }
+ }
+ }
+ return ruleData;
+ }
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
index 6b270d8c7cb5..a87d53247960 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
@@ -1,14 +1,39 @@
package org.apache.shenyu.plugin.base.maker;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.shenyu.common.config.ShenyuConfig;
+import org.apache.shenyu.common.dto.ConditionData;
import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.enums.MatchModeEnum;
+import org.apache.shenyu.common.enums.SelectorTypeEnum;
+import org.apache.shenyu.common.enums.TrieCacheTypeEnum;
+import org.apache.shenyu.common.utils.ListUtil;
+import org.apache.shenyu.common.utils.LogUtils;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
+import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
+import org.apache.shenyu.plugin.base.cache.MatchDataCache;
+import org.apache.shenyu.plugin.base.condition.strategy.MatchStrategyFactory;
import org.apache.shenyu.plugin.base.provider.SelectorDataProvider;
+import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
+import org.apache.shenyu.plugin.base.trie.ShenyuTrieNode;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.apache.shenyu.plugin.api.ShenyuPlugin.LOG;
public class SelectorDataDecisionMaker extends AbstractMatchDecisionMaker {
+
+ private static final String URI_CONDITION_TYPE = "uri";
+
+ private ShenyuConfig.SelectorMatchCache selectorMatchConfig;
+
+ private ShenyuTrie selectorTrie;
+
public SelectorDataDecisionMaker() {
super(new SelectorDataProvider());
}
@@ -19,12 +44,112 @@ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, She
}
@Override
- public SelectorData matchData(ServerWebExchange exchange, List dataList, String path) {
- return dataList.isEmpty() ? null : dataList.get(0);
+ public SelectorData matchData(ServerWebExchange exchange,String pluginName, List dataList, String path,ShenyuConfig.SelectorMatchCache selectorMatchConfig,ShenyuTrie selectorTrie) {
+ return dataList.isEmpty() ? trieMatchSelector(exchange, pluginName, path, selectorMatchConfig, selectorTrie) : dataList.get(0);
}
@Override
public boolean shouldContinue(SelectorData data) {
return data != null && data.getEnabled() && data.getContinued();
}
+
+ private void initCacheConfig() {
+ if (Objects.isNull(selectorMatchConfig)) {
+ ShenyuConfig shenyuConfig = SpringBeanUtils.getInstance().getBean(ShenyuConfig.class);
+ selectorMatchConfig = shenyuConfig.getSelectorMatchCache();
+ }
+
+ if (Objects.isNull(selectorTrie)) {
+ selectorTrie = SpringBeanUtils.getInstance().getBean(TrieCacheTypeEnum.SELECTOR.getTrieType());
+ }
+ }
+
+
+ private SelectorData trieMatchSelector(final ServerWebExchange exchange, final String pluginName, final String path, ShenyuConfig.SelectorMatchCache selectorMatchConfig, ShenyuTrie selectorTrie) {
+ if (!selectorMatchConfig.getTrie().getEnabled()) {
+ return null;
+ }
+ SelectorData selectorData = null;
+ ShenyuTrieNode shenyuTrieNode = selectorTrie.match(path, pluginName);
+ if (Objects.nonNull(shenyuTrieNode)) {
+ LogUtils.info(LOG, "{} selector match path from shenyu trie, path:{}", pluginName, path);
+ List> collection = shenyuTrieNode.getPathCache().get(pluginName);
+ if (CollectionUtils.isNotEmpty(collection)) {
+ Pair selectorDataPair;
+ if (collection.size() > 1) {
+ selectorDataPair = matchSelector(exchange, ListUtil.castList(collection, SelectorData.class::cast));
+ } else {
+ Object selectorObj = collection.stream().findFirst().orElse(null);
+ SelectorData selector = Objects.nonNull(selectorObj) ? (SelectorData) selectorObj : null;
+ boolean cached = Objects.nonNull(selector) && selector.getConditionList().stream().allMatch(condition -> URI_CONDITION_TYPE.equals(condition.getParamType()));
+ selectorDataPair = Pair.of(cached, selector);
+ }
+ selectorData = selectorDataPair.getRight();
+ if (selectorDataPair.getLeft() && Objects.nonNull(selectorData)) {
+ cacheSelectorData(path, selectorData,selectorMatchConfig);
+ }
+ }
+ }
+ return selectorData;
+ }
+
+ private Pair matchSelector(final ServerWebExchange exchange, final Collection selectors) {
+ List filterCollectors = selectors.stream()
+ .filter(selector -> selector.getEnabled() && filterSelector(selector, exchange))
+ .distinct()
+ .collect(Collectors.toList());
+ if (filterCollectors.size() > 1) {
+ return Pair.of(Boolean.FALSE, manyMatchSelector(filterCollectors));
+ } else {
+ return Pair.of(Boolean.TRUE, filterCollectors.stream().findFirst().orElse(null));
+ }
+ }
+
+
+ private Boolean filterSelector(final SelectorData selector, final ServerWebExchange exchange) {
+ if (selector.getType() == SelectorTypeEnum.CUSTOM_FLOW.getCode()) {
+ if (CollectionUtils.isEmpty(selector.getConditionList())) {
+ return false;
+ }
+ return MatchStrategyFactory.match(selector.getMatchMode(), selector.getConditionList(), exchange);
+ }
+ return true;
+ }
+
+ private SelectorData manyMatchSelector(final List filterCollectors) {
+ //What needs to be dealt with here is the and condition. If the number of and conditions is the same and is matched at the same time,
+ // it will be sorted by the sort field.
+ Map>> collect =
+ filterCollectors.stream().map(selector -> {
+ boolean match = MatchModeEnum.match(selector.getMatchMode(), MatchModeEnum.AND);
+ int sort = 0;
+ if (match) {
+ sort = selector.getConditionList().size();
+ }
+ return Pair.of(sort, selector);
+ }).collect(Collectors.groupingBy(Pair::getLeft));
+ Integer max = Collections.max(collect.keySet());
+ List> pairs = collect.get(max);
+ return pairs.stream().map(Pair::getRight).min(Comparator.comparing(SelectorData::getSort)).orElse(null);
+ }
+
+ private void cacheSelectorData(final String path, final SelectorData selectorData,ShenyuConfig.SelectorMatchCache selectorMatchConfig) {
+ if (Boolean.FALSE.equals(selectorMatchConfig.getCache().getEnabled()) || Objects.isNull(selectorData)
+ || Boolean.TRUE.equals(selectorData.getMatchRestful())) {
+ return;
+ }
+ int initialCapacity = selectorMatchConfig.getCache().getInitialCapacity();
+ long maximumSize = selectorMatchConfig.getCache().getMaximumSize();
+ if (StringUtils.isBlank(selectorData.getId())) {
+ MatchDataCache.getInstance().cacheSelectorData(path, selectorData, initialCapacity, maximumSize);
+ return;
+ }
+ List conditionList = selectorData.getConditionList();
+ if (CollectionUtils.isNotEmpty(conditionList)) {
+ boolean isUriCondition = conditionList.stream().allMatch(v -> URI_CONDITION_TYPE.equals(v.getParamType()));
+ if (isUriCondition) {
+ MatchDataCache.getInstance().cacheSelectorData(path, selectorData, initialCapacity, maximumSize);
+ }
+ }
+ }
}
\ No newline at end of file
From 6a8ae43684ec351230fad0682fa5532a74033a98 Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Wed, 3 Dec 2025 17:46:59 +0800
Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DAI=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../plugin/base/AbstractShenyuPlugin.java | 129 +--------
.../maker/AbstractMatchDecisionMaker.java | 6 +-
.../base/maker/PluginDataDecisionMaker.java | 82 +++++-
.../base/maker/RuleDataDecisionMaker.java | 249 +++++++++++++++++-
.../base/maker/SelectorDataDecisionMaker.java | 171 +++++++++++-
.../base/provider/SelectorDataProvider.java | 46 ++++
6 files changed, 535 insertions(+), 148 deletions(-)
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
index 0414c2fa21eb..7f1fbf69408e 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
@@ -63,14 +63,6 @@ public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
private static final Logger LOG = LoggerFactory.getLogger(AbstractShenyuPlugin.class);
-// private static final String URI_CONDITION_TYPE = "uri";
-
-
-
- private ShenyuTrie ruleTrie;
-
- private ShenyuConfig.RuleMatchCache ruleMatchConfig;
-
private SelectorDataDecisionMaker selectorDataDecisionMaker = new SelectorDataDecisionMaker();
private RuleDataDecisionMaker ruleDataDecisionMaker = new RuleDataDecisionMaker();
@@ -98,7 +90,6 @@ public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
*/
@Override
public Mono execute(final ServerWebExchange exchange, final ShenyuPluginChain chain) {
- initCacheConfig();
final String pluginName = named();
final String path = getRawPath(exchange);
@@ -113,7 +104,7 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
- SelectorData selectorData = selectorDataDecisionMaker.matchData(exchange,pluginName, selectorDataList, path, selectorMatchConfig, selectorTrie);
+ SelectorData selectorData = selectorDataDecisionMaker.matchData(exchange,pluginName, selectorDataList, path, null);
if (selectorData == null) {
return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
@@ -136,7 +127,7 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
return doExecute(exchange, chain, selectorData, rule);
}
- RuleData ruleData = ruleDataDecisionMaker.matchData(exchange, ruleDataList, path);
+ RuleData ruleData = ruleDataDecisionMaker.matchData(exchange,named(), ruleDataList, path, selectorData);
if (ruleData == null) {
return ruleDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
@@ -149,47 +140,6 @@ protected String getRawPath(final ServerWebExchange exchange) {
return exchange.getRequest().getURI().getRawPath();
}
- private void initCacheConfig() {
- if (Objects.isNull(selectorMatchConfig) || Objects.isNull(ruleMatchConfig)) {
- ShenyuConfig shenyuConfig = SpringBeanUtils.getInstance().getBean(ShenyuConfig.class);
- selectorMatchConfig = shenyuConfig.getSelectorMatchCache();
- ruleMatchConfig = shenyuConfig.getRuleMatchCache();
- }
- if (Objects.isNull(selectorTrie) || Objects.isNull(ruleTrie)) {
- selectorTrie = SpringBeanUtils.getInstance().getBean(TrieCacheTypeEnum.SELECTOR.getTrieType());
- ruleTrie = SpringBeanUtils.getInstance().getBean(TrieCacheTypeEnum.RULE.getTrieType());
- }
- }
-
- private SelectorData obtainSelectorDataCacheIfEnabled(final String path) {
- return selectorMatchConfig.getCache().getEnabled() ? MatchDataCache.getInstance().obtainSelectorData(named(), path) : null;
- }
-
- private RuleData obtainRuleDataCacheIfEnabled(final String path) {
- return ruleMatchConfig.getCache().getEnabled() ? MatchDataCache.getInstance().obtainRuleData(named(), path) : null;
- }
-
-
- private void cacheRuleData(final String path, final RuleData ruleData) {
- // if the ruleCache is disabled or rule data is null, not cache rule data.
- if (Boolean.FALSE.equals(ruleMatchConfig.getCache().getEnabled()) || Objects.isNull(ruleData)
- || Boolean.TRUE.equals(ruleData.getMatchRestful())) {
- return;
- }
- int initialCapacity = ruleMatchConfig.getCache().getInitialCapacity();
- long maximumSize = ruleMatchConfig.getCache().getMaximumSize();
- if (StringUtils.isBlank(ruleData.getId())) {
- MatchDataCache.getInstance().cacheRuleData(path, ruleData, initialCapacity, maximumSize);
- return;
- }
- List conditionList = ruleData.getConditionDataList();
- if (CollectionUtils.isNotEmpty(conditionList)) {
- boolean isUriCondition = conditionList.stream().allMatch(v -> URI_CONDITION_TYPE.equals(v.getParamType()));
- if (isUriCondition) {
- MatchDataCache.getInstance().cacheRuleData(path, ruleData, initialCapacity, maximumSize);
- }
- }
- }
private RuleData defaultRuleData(final SelectorData selectorData) {
RuleData ruleData = new RuleData();
@@ -223,81 +173,6 @@ protected Mono handleRuleIfNull(final String pluginName, final ServerWebEx
return chain.execute(exchange);
}
- private Pair matchRule(final ServerWebExchange exchange, final Collection rules) {
- List filterRuleData = rules.stream()
- .filter(rule -> filterRule(rule, exchange))
- .distinct()
- .collect(Collectors.toList());
- if (filterRuleData.size() > 1) {
- return Pair.of(Boolean.FALSE, manyMatchRule(filterRuleData));
- } else {
- return Pair.of(Boolean.TRUE, filterRuleData.stream().findFirst().orElse(null));
- }
- }
-
- private RuleData manyMatchRule(final List filterRuleData) {
- Map>> collect =
- filterRuleData.stream().map(rule -> {
- boolean match = MatchModeEnum.match(rule.getMatchMode(), MatchModeEnum.AND);
- int sort = 0;
- if (match) {
- sort = rule.getConditionDataList().size();
- }
- return Pair.of(sort, rule);
- }).collect(Collectors.groupingBy(Pair::getLeft));
- Integer max = Collections.max(collect.keySet());
- List> pairs = collect.get(max);
- return pairs.stream().map(Pair::getRight).min(Comparator.comparing(RuleData::getSort)).orElse(null);
- }
-
- private Boolean filterRule(final RuleData ruleData, final ServerWebExchange exchange) {
- return ruleData.getEnabled() && MatchStrategyFactory.match(ruleData.getMatchMode(), ruleData.getConditionDataList(), exchange);
- }
-
-
-
-
-
- private SelectorData defaultMatchSelector(final ServerWebExchange exchange, final List selectors, final String path) {
- Pair matchSelectorPair = matchSelector(exchange, selectors);
- SelectorData selectorData = matchSelectorPair.getRight();
- if (Objects.nonNull(selectorData)) {
- LogUtils.info(LOG, "{} selector match success from default strategy", named());
- // cache selector data
- if (matchSelectorPair.getLeft()) {
- cacheSelectorData(path, selectorData);
- }
- return selectorData;
- } else {
- // if not match selector, cache empty selector data.
- if (matchSelectorPair.getLeft()) {
- SelectorData emptySelectorData = SelectorData.builder().pluginName(named()).build();
- cacheSelectorData(path, emptySelectorData);
- }
- return null;
- }
- }
-
- private RuleData defaultMatchRule(final ServerWebExchange exchange, final List rules, final String path) {
- Pair matchRulePair = matchRule(exchange, rules);
- RuleData ruleData = matchRulePair.getRight();
- if (Objects.nonNull(ruleData)) {
- LOG.info("{} rule match path from default strategy", named());
- // cache rule data
- if (matchRulePair.getLeft()) {
- cacheRuleData(path, ruleData);
- }
- return ruleData;
- } else {
- // if not match rule, cache empty rule data.
- if (matchRulePair.getLeft()) {
- RuleData emptyRuleData = RuleData.builder().pluginName(named()).build();
- cacheRuleData(path, emptyRuleData);
- }
- return null;
- }
- }
-
/**
* print selector log.
* please don't delete this method or refactor {@linkplain org.apache.shenyu.plugin.base.AbstractShenyuPlugin#printLog}
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
index 555283b8addb..869aa721bb27 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
@@ -1,10 +1,9 @@
package org.apache.shenyu.plugin.base.maker;
-import org.apache.shenyu.common.config.ShenyuConfig;
import org.apache.shenyu.common.dto.BaseData;
+import org.apache.shenyu.common.dto.SelectorData;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
import org.apache.shenyu.plugin.base.provider.DataProvider;
-import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@@ -12,6 +11,7 @@
public abstract class AbstractMatchDecisionMaker {
private final DataProvider dataProvider;
+ protected static final String URI_CONDITION_TYPE = "uri";
protected AbstractMatchDecisionMaker(DataProvider dataProvider) {
this.dataProvider = dataProvider;
@@ -23,7 +23,7 @@ public List getData(String key) {
protected abstract Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain);
- protected abstract T matchData(ServerWebExchange exchange, String dataName, List dataList, String path, ShenyuConfig.SelectorMatchCache selectorMatchConfig, ShenyuTrie selectorTrie);
+ protected abstract T matchData(ServerWebExchange exchange, String dataName, List dataList, String path, SelectorData selectorData);
protected abstract boolean shouldContinue(T data);
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
index f02624af5fea..bb6671703872 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
@@ -1,6 +1,7 @@
package org.apache.shenyu.plugin.base.maker;
import org.apache.shenyu.common.dto.PluginData;
+import org.apache.shenyu.common.dto.SelectorData;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
import org.apache.shenyu.plugin.base.provider.PluginDataProvider;
import org.springframework.web.server.ServerWebExchange;
@@ -8,21 +9,100 @@
import java.util.List;
+/**
+ * A specialized decision maker implementation responsible for plugin data matching and decision-making
+ * within the Apache ShenYu gateway ecosystem.
+ *
+ * This class extends {@link AbstractMatchDecisionMaker} to provide plugin-specific matching
+ * capabilities for {@link PluginData} objects. It serves as the foundational decision maker in
+ * ShenYu's three-tier matching system (Plugin → Selector → Rule), determining which plugins should
+ * process incoming requests based on their enabled status and configuration data.
+ *
+ * In the ShenYu gateway architecture, this component operates at the highest level of the
+ * decision hierarchy:
+ *
+ * - Plugin Level: Determines if a plugin is enabled and should process the request
+ * - Selector Level: Handles coarse-grained routing decisions
+ * - Rule Level: Applies fine-grained processing rules
+ *
+ * The PluginDataDecisionMaker ensures that only active and properly configured plugins participate
+ * in request processing, maintaining gateway efficiency and reliability.
+ *
+ * This decision maker integrates with ShenYu's plugin chain mechanism through the provided
+ * {@link PluginDataProvider}, which supplies the plugin configuration data needed for matching
+ * decisions. It follows the gateway's reactive programming model by returning {@link Mono} types
+ * for all asynchronous operations.
+ */
public class PluginDataDecisionMaker extends AbstractMatchDecisionMaker {
+
+ /**
+ * Constructs a new PluginDataDecisionMaker with a PluginDataProvider.
+ *
+ * This constructor initializes the decision maker with a dedicated data provider
+ * that supplies plugin configuration information. The provider enables access to
+ * plugin metadata including enabled status, configuration parameters, and execution
+ * order settings.
+ */
public PluginDataDecisionMaker() {
super(new PluginDataProvider());
}
+ /**
+ * Handles the scenario when no plugin data is found for the specified plugin.
+ *
+ * When no matching plugin data is available, this method ensures the request
+ * continues through the plugin chain without interruption. This graceful degradation
+ * approach maintains system reliability by allowing requests to proceed even when
+ * specific plugin configurations are missing or unavailable.
+ *
+ * @param pluginName the name of the plugin being processed
+ * @param exchange the current server web exchange containing request and response data
+ * @param chain the plugin chain for continued request processing
+ * @return a Mono indicating completion of the empty handler operation
+ */
@Override
public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
return chain.execute(exchange);
}
+ /**
+ * Matches plugin data against the current request context.
+ *
+ * This method implements the core plugin matching logic, selecting the appropriate
+ * plugin data from the available candidates. It employs a straightforward selection
+ * strategy: when multiple plugin data entries are available, it returns the first one
+ * from the list, assuming the list is pre-sorted by priority or relevance.
+ *
+ * In typical ShenYu usage, plugin data lists contain configuration for a specific
+ * plugin name, so returning the first entry is semantically correct as there should
+ * be only one active configuration per plugin.
+ *
+ * @param exchange the current server web exchange containing request information
+ * @param dataName the name of the plugin data being matched
+ * @param dataList the list of candidate plugin data for matching
+ * @param path the request path (currently unused in base implementation)
+ * @param selectorData the selector data context (currently unused in base implementation)
+ * @return the matched PluginData, or null if the data list is empty
+ */
@Override
- public PluginData matchData(ServerWebExchange exchange, List dataList, String path) {
+ public PluginData matchData(ServerWebExchange exchange, String dataName, List dataList, String path, SelectorData selectorData) {
return dataList.isEmpty() ? null : dataList.get(0);
}
+ /**
+ * Determines whether the plugin chain should continue processing after the current plugin.
+ *
+ * This decision is based solely on the plugin's enabled status. Only plugins that are
+ * explicitly enabled will allow continuation of the plugin chain. This provides a simple
+ * but effective mechanism for controlling plugin execution flow within the gateway.
+ *
+ * The continuation mechanism enables complex processing scenarios where certain plugins
+ * might terminate request processing (e.g., authentication failures) while others allow
+ * progression to subsequent processing stages.
+ *
+ * @param data the plugin data to evaluate for continuation
+ * @return true if the plugin is enabled and should continue processing, false otherwise
+ */
@Override
public boolean shouldContinue(PluginData data) {
return data != null && data.getEnabled();
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
index ec7fd69e7068..1d8fd05fa044 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java
@@ -1,51 +1,180 @@
package org.apache.shenyu.plugin.base.maker;
import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.shenyu.common.config.ShenyuConfig;
+import org.apache.shenyu.common.dto.ConditionData;
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.enums.MatchModeEnum;
+import org.apache.shenyu.common.enums.TrieCacheTypeEnum;
import org.apache.shenyu.common.utils.ListUtil;
import org.apache.shenyu.common.utils.LogUtils;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
+import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
+import org.apache.shenyu.plugin.base.cache.MatchDataCache;
+import org.apache.shenyu.plugin.base.condition.strategy.MatchStrategyFactory;
import org.apache.shenyu.plugin.base.provider.RuleDataProvider;
import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
import org.apache.shenyu.plugin.base.trie.ShenyuTrieNode;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
+import java.util.stream.Collectors;
+import static org.apache.shenyu.plugin.api.ShenyuPlugin.LOG;
+
+/**
+ * A specialized decision maker implementation that handles rule matching logic within the Apache ShenYu gateway.
+ *
+ * This class extends {@link AbstractMatchDecisionMaker} to provide sophisticated rule matching
+ * capabilities for {@link RuleData} objects. It implements the core decision-making logic for determining
+ * which specific rules should be applied to incoming requests based on path matching, conditions, and
+ * configurable matching strategies.
+ *
+ * The RuleDataDecisionMaker operates as the second level in ShenYu's two-tier routing system:
+ *
+ * - Selector Level: Coarse-grained routing using {@link SelectorData}
+ * - Rule Level: Fine-grained processing logic using {@link RuleData}
+ *
+ * After a selector matches a request, this component determines the specific rule to apply within that selector.
+ *
+ *
+ * The decision maker employs multiple matching strategies:
+ *
+ * - Trie-based path matching: Efficient URI path lookup using {@link ShenyuTrie}
+ * - Condition evaluation: Rule condition validation using {@link MatchStrategyFactory}
+ * - Priority resolution: Conflict resolution when multiple rules match the same request
+ * - Configurable caching: Performance optimization through {@link MatchDataCache}
+ *
+ *
+ *
+ * This component integrates with ShenYu's plugin architecture to provide precise rule-based
+ * request processing, supporting complex routing scenarios with conditional logic and performance
+ * optimization through intelligent caching mechanisms.
+ */
public class RuleDataDecisionMaker extends AbstractMatchDecisionMaker {
+
+ private ShenyuConfig.RuleMatchCache ruleMatchConfig;
+ private ShenyuTrie ruleTrie;
+
+ /**
+ * Constructs a new RuleDataDecisionMaker with a RuleDataProvider.
+ *
+ * Initializes the cache configuration and trie data structure specifically optimized
+ * for rule matching operations. The constructor sets up the necessary infrastructure
+ * for efficient rule lookup and matching performance.
+ */
public RuleDataDecisionMaker() {
super(new RuleDataProvider());
+ initCacheConfig();
}
+ /**
+ * Handles the scenario when no rule data is found for the given rule name.
+ *
+ * When no matching rules are found, this method allows the request to continue
+ * through the plugin chain without rule-specific processing. This ensures that
+ * the gateway can handle requests even when no specific rules are configured,
+ * maintaining system reliability and avoiding request processing interruptions.
+ *
+ * @param pluginName the name of the plugin being executed
+ * @param exchange the current server web exchange containing request and response data
+ * @param chain the plugin chain for continued request processing
+ * @return a Mono indicating completion of the empty handler operation
+ */
@Override
public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
return chain.execute(exchange);
}
+ /**
+ * Matches rule data against the current request context.
+ *
+ * This method implements the core rule matching logic, providing two matching strategies:
+ *
+ * - Direct matching: Uses pre-loaded rule data from the provided list when available
+ * - Trie-based matching: Falls back to sophisticated trie-based path matching
+ * when the data list is empty
+ *
+ * The method ensures optimal performance by prioritizing cached data while maintaining
+ * comprehensive matching capabilities through the trie structure.
+ *
+ *
+ * @param exchange the current server web exchange containing request information
+ * @param ruleName the name of the rule requesting matching
+ * @param dataList the list of candidate rule data for matching (may be empty)
+ * @param path the request path to match against rules
+ * @param selectorData the parent selector data context for rule matching
+ * @return the matched RuleData, or null if no suitable rule is found
+ */
@Override
- public RuleData matchData(ServerWebExchange exchange, String ruleName, List dataList, String path, ShenyuConfig.SelectorMatchCache selectorMatchConfig, ShenyuTrie selectorTrie) {
- return dataList.isEmpty() ? trieMatchRule() : dataList.get(0);
+ public RuleData matchData(ServerWebExchange exchange, String ruleName, List dataList, String path, SelectorData selectorData) {
+ return dataList.isEmpty() ? trieMatchRule(exchange, ruleName, selectorData, path) : dataList.get(0);
}
+ /**
+ * Determines whether the plugin chain should continue processing after the current rule.
+ *
+ * Rule continuation is based on the rule's enabled status. Only enabled rules
+ * permit further processing in the plugin chain. This allows for complex rule
+ * sequences where specific rules can terminate processing while others allow
+ * continuation to subsequent rules or plugins.
+ *
+ * @param data the rule data to evaluate for continuation
+ * @return true if the rule is enabled and should continue processing, false otherwise
+ */
@Override
public boolean shouldContinue(RuleData data) {
return data != null && data.getEnabled();
}
+ /**
+ * Initializes the cache configuration and trie data structure for rule matching.
+ *
+ * This method performs lazy initialization of the rule matching infrastructure,
+ * retrieving configuration from ShenYu's global configuration and obtaining the
+ * appropriate trie implementation based on the rule cache type enumeration.
+ */
+ private void initCacheConfig() {
+ if (Objects.isNull(ruleMatchConfig)) {
+ ShenyuConfig shenyuConfig = SpringBeanUtils.getInstance().getBean(ShenyuConfig.class);
+ ruleMatchConfig = shenyuConfig.getRuleMatchCache();
+ }
- private RuleData trieMatchRule(final ServerWebExchange exchange, final SelectorData selectorData, final String path) {
+ if (Objects.isNull(ruleTrie)) {
+ ruleTrie = SpringBeanUtils.getInstance().getBean(TrieCacheTypeEnum.RULE.getTrieType());
+ }
+ }
+
+ /**
+ * Performs trie-based matching for rules when no pre-loaded data is available.
+ *
+ * This method implements sophisticated trie-based matching that:
+ *
+ * - Validates that trie matching is enabled in the configuration
+ * - Uses the ShenyuTrie to find path matches based on selector context
+ * - Handles both single and multiple rule matches with appropriate resolution
+ * - Applies caching for performance optimization when conditions permit
+ *
+ *
+ *
+ * @param exchange the current server web exchange
+ * @param ruleName the name of the rule being processed
+ * @param selectorData the parent selector data providing context for rule matching
+ * @param path the request path to match
+ * @return the matched RuleData, or null if no match is found or trie matching is disabled
+ */
+ private RuleData trieMatchRule(final ServerWebExchange exchange, String ruleName, final SelectorData selectorData, final String path) {
if (!ruleMatchConfig.getTrie().getEnabled()) {
return null;
}
RuleData ruleData = null;
ShenyuTrieNode shenyuTrieNode = ruleTrie.match(path, selectorData.getId());
if (Objects.nonNull(shenyuTrieNode)) {
- LogUtils.info(LOG, "{} rule match path from shenyu trie", named());
+ LogUtils.info(LOG, "{} rule match path from shenyu trie", ruleName);
List> collection = shenyuTrieNode.getPathCache().get(selectorData.getId());
if (CollectionUtils.isNotEmpty(collection)) {
Pair ruleDataPair;
@@ -66,4 +195,112 @@ private RuleData trieMatchRule(final ServerWebExchange exchange, final SelectorD
}
return ruleData;
}
+
+ /**
+ * Filters and matches a collection of rules against the current exchange.
+ *
+ * This method applies rule conditions and matching strategies to determine
+ * which rules are appropriate for the current request. It handles conflict
+ * resolution when multiple rules match and provides caching recommendations
+ * based on the matching results.
+ *
+ * @param exchange the current server web exchange
+ * @param rules the collection of rules to filter and match
+ * @return a Pair where the left value indicates cacheability and the right value contains the matched RuleData
+ */
+ private Pair matchRule(final ServerWebExchange exchange, final Collection rules) {
+ List filterRuleData = rules.stream()
+ .filter(rule -> filterRule(rule, exchange))
+ .distinct()
+ .collect(Collectors.toList());
+ if (filterRuleData.size() > 1) {
+ return Pair.of(Boolean.FALSE, manyMatchRule(filterRuleData));
+ } else {
+ return Pair.of(Boolean.TRUE, filterRuleData.stream().findFirst().orElse(null));
+ }
+ }
+
+ /**
+ * Filters a single rule based on its enabled status and conditions.
+ *
+ * This method validates that a rule is enabled and applies the appropriate
+ * match strategy using the MatchStrategyFactory. It serves as the core
+ * condition evaluation mechanism for rule matching.
+ *
+ * @param ruleData the rule to filter
+ * @param exchange the current server web exchange for condition evaluation
+ * @return true if the rule is enabled and matches the current request conditions, false otherwise
+ */
+ private Boolean filterRule(final RuleData ruleData, final ServerWebExchange exchange) {
+ return ruleData.getEnabled() && MatchStrategyFactory.match(ruleData.getMatchMode(), ruleData.getConditionDataList(), exchange);
+ }
+
+ /**
+ * Resolves conflicts when multiple rules match the same request.
+ *
+ * This method implements sophisticated priority resolution logic that:
+ *
+ * - Groups rules by the number of AND conditions matched
+ * - Selects the group with the highest number of AND conditions
+ * - Within that group, chooses the rule with the lowest sort value
+ *
+ * This ensures that more specific rules (with more conditions) take precedence
+ * over general ones, providing predictable and configurable rule prioritization.
+ *
+ *
+ * @param filterRuleData the list of matching rules to resolve
+ * @return the highest priority rule according to the resolution rules
+ */
+ private RuleData manyMatchRule(final List filterRuleData) {
+ Map>> collect =
+ filterRuleData.stream().map(rule -> {
+ boolean match = MatchModeEnum.match(rule.getMatchMode(), MatchModeEnum.AND);
+ int sort = 0;
+ if (match) {
+ sort = rule.getConditionDataList().size();
+ }
+ return Pair.of(sort, rule);
+ }).collect(Collectors.groupingBy(Pair::getLeft));
+ Integer max = Collections.max(collect.keySet());
+ List> pairs = collect.get(max);
+ return pairs.stream().map(Pair::getRight).min(Comparator.comparing(RuleData::getSort)).orElse(null);
+ }
+
+ /**
+ * Caches matched rule data for improved performance on subsequent requests.
+ *
+ * This method implements configurable caching that stores rule data when:
+ *
+ * - Caching is enabled in the configuration
+ * - The rule data is not null
+ * - The rule doesn't represent a RESTful match
+ * - All conditions are URI-based (ensuring cache validity)
+ *
+ * The caching mechanism respects the configured initial capacity and maximum
+ * size parameters to optimize memory usage while maintaining performance.
+ *
+ *
+ * @param path the request path used as cache key
+ * @param ruleData the rule data to cache
+ */
+ private void cacheRuleData(final String path, final RuleData ruleData) {
+ // if the ruleCache is disabled or rule data is null, not cache rule data.
+ if (Boolean.FALSE.equals(ruleMatchConfig.getCache().getEnabled()) || Objects.isNull(ruleData)
+ || Boolean.TRUE.equals(ruleData.getMatchRestful())) {
+ return;
+ }
+ int initialCapacity = ruleMatchConfig.getCache().getInitialCapacity();
+ long maximumSize = ruleMatchConfig.getCache().getMaximumSize();
+ if (StringUtils.isBlank(ruleData.getId())) {
+ MatchDataCache.getInstance().cacheRuleData(path, ruleData, initialCapacity, maximumSize);
+ return;
+ }
+ List conditionList = ruleData.getConditionDataList();
+ if (CollectionUtils.isNotEmpty(conditionList)) {
+ boolean isUriCondition = conditionList.stream().allMatch(v -> URI_CONDITION_TYPE.equals(v.getParamType()));
+ if (isUriCondition) {
+ MatchDataCache.getInstance().cacheRuleData(path, ruleData, initialCapacity, maximumSize);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
index a87d53247960..99f5da82761e 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java
@@ -26,33 +26,114 @@
import static org.apache.shenyu.plugin.api.ShenyuPlugin.LOG;
+/**
+ * The core decision-making engine for selector matching in Apache ShenYu gateway.
+ *
+ * This class implements the matching logic that determines which selector should handle
+ * incoming requests based on request attributes, path patterns, and configured conditions.
+ * It extends the abstract matching framework and specializes in selector-level routing decisions.
+ *
+ * In the ShenYu architecture, selectors represent the first level of request routing where
+ * coarse-grained filtering occurs before more specific rule matching. This decision maker
+ * evaluates various matching strategies including trie-based path matching, condition-based
+ * filtering, and custom flow selectors.
+ *
+ * The class employs multiple matching techniques:
+ *
+ * - Trie-based matching: For efficient path pattern matching using prefix trees
+ * - Condition-based filtering: Using match strategies from {@link MatchStrategyFactory}
+ * - Custom flow selectors: For advanced, user-defined routing logic
+ *
+ *
+ *
+ * Caching is extensively used to optimize performance, with configurable cache settings
+ * for both trie structures and match results. The caching behavior can be tuned through
+ * {@link ShenyuConfig.SelectorMatchCache} configuration.
+ */
public class SelectorDataDecisionMaker extends AbstractMatchDecisionMaker {
- private static final String URI_CONDITION_TYPE = "uri";
-
private ShenyuConfig.SelectorMatchCache selectorMatchConfig;
-
private ShenyuTrie selectorTrie;
+ /**
+ * Constructs a new SelectorDataDecisionMaker with a SelectorDataProvider.
+ * Initializes cache configuration and trie structures for selector matching.
+ */
public SelectorDataDecisionMaker() {
super(new SelectorDataProvider());
+ initCacheConfig();
}
+ /**
+ * Handles the case when no selector data is found for the given plugin.
+ *
+ * When no matching selectors are found, this method allows the request to continue
+ * through the plugin chain without selector-specific processing. This ensures that
+ * requests can still be processed by subsequent plugins even when selector matching
+ * doesn't yield results.
+ *
+ * @param pluginName the name of the plugin being executed
+ * @param exchange the current server web exchange
+ * @param chain the plugin chain for continued processing
+ * @return a Mono indicating completion of the empty handling operation
+ */
@Override
public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
return chain.execute(exchange);
}
+ /**
+ * Performs the core selector matching logic for incoming requests.
+ *
+ * This method implements the selector matching algorithm that determines which
+ * selector should process the current request. It supports both direct list-based
+ * matching and advanced trie-based matching for path patterns.
+ *
+ * The matching process follows this hierarchy:
+ *
+ * - If pre-filtered data is available in the dataList, use the first match
+ * - Otherwise, perform trie-based matching on the request path
+ * - Apply condition filtering for custom flow selectors
+ * - Handle multiple matches using priority-based selection
+ *
+ *
+ *
+ * @param exchange the current server web exchange containing request information
+ * @param pluginName the name of the plugin requesting selector matching
+ * @param dataList pre-filtered list of selector data (may be empty)
+ * @param path the request path used for matching
+ * @param selectorData additional selector context (currently unused in base implementation)
+ * @return the matched SelectorData, or null if no match found
+ *
+ */
@Override
- public SelectorData matchData(ServerWebExchange exchange,String pluginName, List dataList, String path,ShenyuConfig.SelectorMatchCache selectorMatchConfig,ShenyuTrie selectorTrie) {
- return dataList.isEmpty() ? trieMatchSelector(exchange, pluginName, path, selectorMatchConfig, selectorTrie) : dataList.get(0);
+ public SelectorData matchData(ServerWebExchange exchange, String pluginName, List dataList, String path, SelectorData selectorData) {
+ return dataList.isEmpty() ? trieMatchSelector(exchange, pluginName, path) : dataList.get(0);
}
+ /**
+ * Determines whether the plugin chain should continue processing after selector matching.
+ *
+ * A selector can control the flow of the plugin chain by specifying continuation
+ * behavior. This method checks the selector's enabled status and continuation flag
+ * to determine if processing should proceed to the next plugin.
+ *
+ * @param data the selector data to evaluate for continuation
+ * @return true if the selector is enabled and configured to continue processing,
+ * false otherwise
+ */
@Override
public boolean shouldContinue(SelectorData data) {
return data != null && data.getEnabled() && data.getContinued();
}
+ /**
+ * Initializes the cache configuration and trie structures for selector matching.
+ *
+ * This method lazily initializes the caching infrastructure by retrieving
+ * configuration from Spring context. It ensures that cache settings and trie
+ * instances are properly configured before matching operations begin.
+ */
private void initCacheConfig() {
if (Objects.isNull(selectorMatchConfig)) {
ShenyuConfig shenyuConfig = SpringBeanUtils.getInstance().getBean(ShenyuConfig.class);
@@ -64,8 +145,28 @@ private void initCacheConfig() {
}
}
-
- private SelectorData trieMatchSelector(final ServerWebExchange exchange, final String pluginName, final String path, ShenyuConfig.SelectorMatchCache selectorMatchConfig, ShenyuTrie selectorTrie) {
+ /**
+ * Performs trie-based matching for selectors when no pre-filtered data is available.
+ *
+ * This method implements efficient path matching using a trie data structure,
+ * which provides O(m) time complexity where m is the path length. It's particularly
+ * effective for routing scenarios with large numbers of path-based selectors.
+ *
+ * The matching process includes:
+ *
+ * - Checking if trie matching is enabled in configuration
+ * - Finding the matching trie node for the given path
+ * - Handling single and multiple matches appropriately
+ * - Caching results for future requests when conditions allow
+ *
+ *
+ *
+ * @param exchange the current server web exchange
+ * @param pluginName the plugin name for context-specific matching
+ * @param path the request path to match against selector patterns
+ * @return the matched SelectorData, or null if no match found
+ */
+ private SelectorData trieMatchSelector(final ServerWebExchange exchange, final String pluginName, final String path) {
if (!selectorMatchConfig.getTrie().getEnabled()) {
return null;
}
@@ -86,13 +187,26 @@ private SelectorData trieMatchSelector(final ServerWebExchange exchange, final S
}
selectorData = selectorDataPair.getRight();
if (selectorDataPair.getLeft() && Objects.nonNull(selectorData)) {
- cacheSelectorData(path, selectorData,selectorMatchConfig);
+ cacheSelectorData(path, selectorData, selectorMatchConfig);
}
}
}
return selectorData;
}
+ /**
+ * Filters and matches a collection of selectors against the current exchange.
+ *
+ * This method applies condition-based filtering to determine which selectors
+ * are appropriate for the current request. It handles both single and multiple
+ * matches, with special logic for resolving conflicts when multiple selectors
+ * match the same request.
+ *
+ * @param exchange the server web exchange to match against
+ * @param selectors the collection of selectors to filter
+ * @return a Pair containing a Boolean indicating if the result can be cached,
+ * and the matched SelectorData
+ */
private Pair matchSelector(final ServerWebExchange exchange, final Collection selectors) {
List filterCollectors = selectors.stream()
.filter(selector -> selector.getEnabled() && filterSelector(selector, exchange))
@@ -105,7 +219,17 @@ private Pair matchSelector(final ServerWebExchange exchan
}
}
-
+ /**
+ * Filters individual selectors based on their type and conditions.
+ *
+ * Custom flow selectors undergo comprehensive condition matching using the
+ * configured match strategy, while other selector types are accepted by default
+ * assuming they've passed earlier filtering stages.
+ *
+ * @param selector the selector to evaluate
+ * @param exchange the server web exchange for condition evaluation
+ * @return true if the selector should be considered for matching, false otherwise
+ */
private Boolean filterSelector(final SelectorData selector, final ServerWebExchange exchange) {
if (selector.getType() == SelectorTypeEnum.CUSTOM_FLOW.getCode()) {
if (CollectionUtils.isEmpty(selector.getConditionList())) {
@@ -116,8 +240,22 @@ private Boolean filterSelector(final SelectorData selector, final ServerWebExcha
return true;
}
+ /**
+ * Resolves conflicts when multiple selectors match the same request.
+ *
+ * This method implements a priority-based selection algorithm that considers:
+ *
+ * - Match mode (AND conditions are prioritized)
+ * - Number of matching conditions
+ * - Selector sort order for tie-breaking
+ *
+ *
+ *
+ * @param filterCollectors the list of matching selectors
+ * @return the highest priority selector according to the conflict resolution rules
+ */
private SelectorData manyMatchSelector(final List filterCollectors) {
- //What needs to be dealt with here is the and condition. If the number of and conditions is the same and is matched at the same time,
+ // What needs to be dealt with here is the and condition. If the number of and conditions is the same and is matched at the same time,
// it will be sorted by the sort field.
Map>> collect =
filterCollectors.stream().map(selector -> {
@@ -133,7 +271,18 @@ private SelectorData manyMatchSelector(final List filterCollectors
return pairs.stream().map(Pair::getRight).min(Comparator.comparing(SelectorData::getSort)).orElse(null);
}
- private void cacheSelectorData(final String path, final SelectorData selectorData,ShenyuConfig.SelectorMatchCache selectorMatchConfig) {
+ /**
+ * Caches selector matching results for performance optimization.
+ *
+ * This method implements the caching strategy for selector matches, with
+ * configurable cache size and eligibility criteria. Only selectors with
+ * URI-based conditions are cached to ensure cache consistency.
+ *
+ * @param path the request path used as cache key
+ * @param selectorData the selector data to cache
+ * @param selectorMatchConfig the cache configuration parameters
+ */
+ private void cacheSelectorData(final String path, final SelectorData selectorData, ShenyuConfig.SelectorMatchCache selectorMatchConfig) {
if (Boolean.FALSE.equals(selectorMatchConfig.getCache().getEnabled()) || Objects.isNull(selectorData)
|| Boolean.TRUE.equals(selectorData.getMatchRestful())) {
return;
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
index 9339d2b4a239..cca559c24174 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
@@ -6,7 +6,53 @@
import java.util.Collections;
import java.util.List;
+/**
+ * A concrete implementation of the {@code DataProvider} interface that provides SelectorData
+ * retrieval functionality within the Apache ShenYu gateway ecosystem.
+ *
+ * This class implements the Data Provider pattern by serving as a specialized data source
+ * for selector information, which is crucial for request routing decisions in the gateway.
+ * Selectors define the coarse-grained routing rules that determine how incoming requests
+ * are matched to appropriate backend services.
+ *
+ * In the ShenYu architecture, this provider works within the plugin system to deliver
+ * selector configuration data that has been synchronized from the admin dashboard to the
+ * gateway's local cache. This enables efficient, in-memory lookup of routing rules during
+ * request processing without requiring database queries.
+ *
+ * The provider leverages the {@link BaseDataCache} singleton instance to access
+ * selector information that is maintained current through ShenYu's data synchronization
+ * mechanisms (WebSocket, ZooKeeper, Nacos, etc.).
+ *
+ */
public class SelectorDataProvider implements DataProvider {
+
+ /**
+ * Retrieves a list of SelectorData objects associated with the specified selector name.
+ *
+ * This method implements the core provider contract by querying the gateway's
+ * cache infrastructure for selector configuration data. Selectors contain matching
+ * rules and conditions that determine which plugin and backend service should handle
+ * incoming requests.
+ *
+ * In the ShenYu request processing pipeline, selectors work together with rules
+ * to form a two-level routing system:
+ *
+ * - Selectors perform coarse-grained routing based on request attributes
+ * - Rules apply fine-grained processing logic within matched selectors
+ *
+ *
+ *
+ * If no selectors are found for the given name, an empty list is returned rather
+ * than null, ensuring null-safe operation for consumers of this provider.
+ *
+ * @param selectorName the name of the selector to retrieve data for; this typically
+ * corresponds to a plugin name or specific selector identifier
+ * configured in the ShenYu admin dashboard
+ * @return a list of SelectorData objects associated with the specified name, or an
+ * empty list if no selectors are found for the given name (never null)
+ *
+ */
@Override
public List getData(String selectorName) {
List data = BaseDataCache.getInstance().obtainSelectorData(selectorName);
From 4b81131e10644bd1cda7304881ed87efedc2f33c Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Wed, 17 Dec 2025 14:44:01 +0800
Subject: [PATCH 6/9] =?UTF-8?q?fix:=20=E8=A1=A5=E5=85=85=E6=94=B9=E5=8A=A8?=
=?UTF-8?q?=E7=B1=BB=E7=9A=84=E7=B1=BB=E6=B3=A8=E9=87=8A=E5=92=8C=E6=96=B9?=
=?UTF-8?q?=E6=B3=95=E6=B3=A8=E9=87=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../plugin/base/AbstractShenyuPlugin.java | 22 --------
.../maker/AbstractMatchDecisionMaker.java | 53 +++++++++++++++++--
.../base/provider/RuleDataProvider.java | 17 +++++-
3 files changed, 65 insertions(+), 27 deletions(-)
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
index 7f1fbf69408e..c70d07f87765 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
@@ -18,43 +18,21 @@
package org.apache.shenyu.plugin.base;
import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.shenyu.common.config.ShenyuConfig;
import org.apache.shenyu.common.constant.Constants;
-import org.apache.shenyu.common.dto.ConditionData;
import org.apache.shenyu.common.dto.PluginData;
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.dto.SelectorData;
-import org.apache.shenyu.common.enums.MatchModeEnum;
import org.apache.shenyu.common.enums.SelectorTypeEnum;
-import org.apache.shenyu.common.enums.TrieCacheTypeEnum;
-import org.apache.shenyu.common.utils.ListUtil;
-import org.apache.shenyu.common.utils.LogUtils;
import org.apache.shenyu.plugin.api.ShenyuPlugin;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
-import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
-import org.apache.shenyu.plugin.base.cache.BaseDataCache;
-import org.apache.shenyu.plugin.base.cache.MatchDataCache;
-import org.apache.shenyu.plugin.base.condition.strategy.MatchStrategyFactory;
-import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
import org.apache.shenyu.plugin.base.maker.PluginDataDecisionMaker;
import org.apache.shenyu.plugin.base.maker.RuleDataDecisionMaker;
import org.apache.shenyu.plugin.base.maker.SelectorDataDecisionMaker;
-import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
-import org.apache.shenyu.plugin.base.trie.ShenyuTrieNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
/**
* abstract shenyu plugin please extends.
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
index 869aa721bb27..964deb4b53da 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
@@ -6,24 +6,71 @@
import org.apache.shenyu.plugin.base.provider.DataProvider;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
-
import java.util.List;
+/**
+ * Abstract base class for making match decisions in plugins using the Template Method pattern.
+ *
+ * This class provides a template for processing data matching logic in plugins. Subclasses are expected
+ * to implement the abstract methods to define specific behaviors for handling empty data, matching data,
+ * and determining whether processing should continue.
+ *
+ *
+ *
+ * The Template Method pattern is used here to allow subclasses to override certain steps of the algorithm
+ * without changing its structure.
+ *
+ *
+ * @param the type of data to be matched, extending {@link BaseData}
+ */
public abstract class AbstractMatchDecisionMaker {
private final DataProvider dataProvider;
protected static final String URI_CONDITION_TYPE = "uri";
+ /**
+ * Constructs an AbstractMatchDecisionMaker with the specified data provider.
+ *
+ * @param dataProvider the data provider used to retrieve data for matching
+ */
protected AbstractMatchDecisionMaker(DataProvider dataProvider) {
this.dataProvider = dataProvider;
}
+ /**
+ * Retrieves a list of data associated with the given key.
+ *
+ * @param key the key used to retrieve data
+ * @return a list of data objects associated with the key
+ */
public List getData(String key) {
return dataProvider.getData(key);
}
+ /**
+ * Handles the scenario when no matching data is found for the given plugin.
+ *
+ * @param pluginName the name of the plugin
+ * @param exchange the current server web exchange
+ * @param chain the plugin chain to continue processing
+ * @return a {@link Mono} that completes when the handling is done
+ */
protected abstract Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain);
-
+
+ /**
+ * Matches the appropriate data from the provided list based on the exchange and path.
+ *
+ * @param exchange the current server web exchange
+ * @param dataList the list of data to match against
+ * @param path the request path to use for matching
+ * @return the matched data object, or {@code null} if no match is found
+ */
protected abstract T matchData(ServerWebExchange exchange, String dataName, List dataList, String path, SelectorData selectorData);
-
+
+ /**
+ * Determines whether processing should continue based on the matched data.
+ *
+ * @param data the matched data object
+ * @return {@code true} if processing should continue, {@code false} otherwise
+ */
protected abstract boolean shouldContinue(T data);
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
index f6b73c8b9b88..baf39bb9c13e 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
@@ -1,12 +1,25 @@
package org.apache.shenyu.plugin.base.provider;
+
import org.apache.shenyu.common.dto.RuleData;
-import org.apache.shenyu.common.dto.SelectorData;
import org.apache.shenyu.plugin.base.cache.BaseDataCache;
-
import java.util.Collections;
import java.util.List;
+/**
+ * A data provider implementation for retrieving rule data from the base data cache.
+ * This class follows the Data Provider pattern to abstract data access logic and provide
+ * a consistent interface for obtaining rule configuration data throughout the Shenyu plugin system.
+ *
+ * The RuleDataProvider serves as a bridge between the plugin infrastructure and the cached
+ * rule data, ensuring efficient data retrieval while maintaining separation of concerns.
+ */
public class RuleDataProvider implements DataProvider {
+
+ /**
+ * Retrieves rule data from the base data cache based on the specified rule name.
+ * This method implements the data provider pattern by delegating to the singleton
+ *
+ */
@Override
public List getData(String ruleName) {
List data = BaseDataCache.getInstance().obtainRuleData(ruleName);
From 2bc515b44115561d5c0df630bd96d8cd16176d7c Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Mon, 12 Jan 2026 09:24:01 +0800
Subject: [PATCH 7/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DCI=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA=E7=9A=84=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC=E9=94=99?=
=?UTF-8?q?=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/java/org/apache/shenyu/common/dto/SelectorData.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
index c688b72b1aaf..71750e8afb8e 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
@@ -366,6 +366,7 @@ public static final class Builder extends BaseData {
private Boolean matchRestful;
private List beforeConditionList;
+
/**
* no args constructor.
*/
From b809e7e2cd71b321c0bcb8d4fb99cedab0e78606 Mon Sep 17 00:00:00 2001
From: aias00
Date: Thu, 15 Jan 2026 15:01:33 +0800
Subject: [PATCH 8/9] Update
shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../plugin/base/provider/DataProvider.java | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
index c2d8a5b5b97d..a149e14969e2 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
@@ -10,8 +10,24 @@
* or other contexts where data needs to be fetched dynamically.
*
* @param Names of various data types
+
+/**
+ * A generic interface for providing data based on a given key.
+ *
+ * Implementations of this interface are responsible for retrieving a list of data items
+ * of type {@code T} associated with the specified key. This can be used in plugin systems
+ * or other contexts where data needs to be fetched dynamically.
+ *
+ * @param the type of data provided by this provider
*/
public interface DataProvider {
+ /**
+ * Retrieves a list of data items associated with the specified key.
+ *
+ * @param key the key used to look up the data; its meaning is defined by the implementation
+ * @return a list of data items of type {@code T} associated with the given key,
+ * or an empty list if no data is found
+ */
/**
* Retrieves a list of data items associated with the specified key.
*
From 80554c08e265754a79738776dd08f8b739793f51 Mon Sep 17 00:00:00 2001
From: gumaomao <474317126@qq.com>
Date: Mon, 19 Jan 2026 17:21:04 +0800
Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=89=A9=E4=BD=99?=
=?UTF-8?q?69=E4=B8=AACI=E6=8F=90=E7=A4=BA=E7=9A=84=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E9=A3=8E=E6=A0=BC=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../plugin/base/AbstractShenyuPlugin.java | 12 +++---
.../maker/AbstractMatchDecisionMaker.java | 27 ++++++++++--
.../base/maker/PluginDataDecisionMaker.java | 25 +++++++++--
.../base/maker/RuleDataDecisionMaker.java | 37 +++++++++++++---
.../base/maker/SelectorDataDecisionMaker.java | 35 ++++++++++++---
.../plugin/base/provider/DataProvider.java | 30 +++++++------
.../base/provider/PluginDataProvider.java | 43 +++++++++----------
.../base/provider/RuleDataProvider.java | 23 ++++++++--
.../base/provider/SelectorDataProvider.java | 22 ++++++++--
9 files changed, 185 insertions(+), 69 deletions(-)
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
index c70d07f87765..139d66349bc6 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
@@ -33,6 +33,7 @@
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
+import java.util.Objects;
/**
* abstract shenyu plugin please extends.
@@ -71,7 +72,6 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
final String pluginName = named();
final String path = getRawPath(exchange);
-
List pluginDataList = pluginDataDecisionMaker.getData(pluginName);
if (CollectionUtils.isEmpty(pluginDataList) || !pluginDataDecisionMaker.shouldContinue(pluginDataList.get(0))) {
return pluginDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
@@ -82,8 +82,8 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
- SelectorData selectorData = selectorDataDecisionMaker.matchData(exchange,pluginName, selectorDataList, path, null);
- if (selectorData == null) {
+ SelectorData selectorData = selectorDataDecisionMaker.matchData(exchange, pluginName, selectorDataList, path, null);
+ if (Objects.isNull(selectorData)) {
return selectorDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
@@ -92,8 +92,6 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
return doExecute(exchange, chain, selectorData, defaultRuleData(selectorData));
}
-
-
List ruleDataList = ruleDataDecisionMaker.getData(selectorData.getId());
if (CollectionUtils.isEmpty(ruleDataList)) {
return ruleDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
@@ -105,8 +103,8 @@ public Mono execute(final ServerWebExchange exchange, final ShenyuPluginCh
return doExecute(exchange, chain, selectorData, rule);
}
- RuleData ruleData = ruleDataDecisionMaker.matchData(exchange,named(), ruleDataList, path, selectorData);
- if (ruleData == null) {
+ RuleData ruleData = ruleDataDecisionMaker.matchData(exchange, named(), ruleDataList, path, selectorData);
+ if (Objects.isNull(ruleData)) {
return ruleDataDecisionMaker.handleEmpty(pluginName, exchange, chain);
}
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
index 964deb4b53da..95d6ce703554 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java
@@ -1,3 +1,20 @@
+/*
+ * 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.shenyu.plugin.base.maker;
import org.apache.shenyu.common.dto.BaseData;
@@ -10,6 +27,7 @@
/**
* Abstract base class for making match decisions in plugins using the Template Method pattern.
+ *
*
* This class provides a template for processing data matching logic in plugins. Subclasses are expected
* to implement the abstract methods to define specific behaviors for handling empty data, matching data,
@@ -24,15 +42,18 @@
* @param the type of data to be matched, extending {@link BaseData}
*/
public abstract class AbstractMatchDecisionMaker {
- private final DataProvider dataProvider;
+
protected static final String URI_CONDITION_TYPE = "uri";
+ private final DataProvider dataProvider;
+
+
/**
* Constructs an AbstractMatchDecisionMaker with the specified data provider.
*
* @param dataProvider the data provider used to retrieve data for matching
*/
- protected AbstractMatchDecisionMaker(DataProvider dataProvider) {
+ protected AbstractMatchDecisionMaker(final DataProvider dataProvider) {
this.dataProvider = dataProvider;
}
@@ -42,7 +63,7 @@ protected AbstractMatchDecisionMaker(DataProvider dataProvider) {
* @param key the key used to retrieve data
* @return a list of data objects associated with the key
*/
- public List getData(String key) {
+ public List getData(final String key) {
return dataProvider.getData(key);
}
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
index bb6671703872..b851770239d2 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java
@@ -1,3 +1,20 @@
+/*
+ * 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.shenyu.plugin.base.maker;
import org.apache.shenyu.common.dto.PluginData;
@@ -61,7 +78,7 @@ public PluginDataDecisionMaker() {
* @return a Mono indicating completion of the empty handler operation
*/
@Override
- public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
+ public Mono handleEmpty(final String pluginName, final ServerWebExchange exchange, final ShenyuPluginChain chain) {
return chain.execute(exchange);
}
@@ -85,7 +102,7 @@ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, She
* @return the matched PluginData, or null if the data list is empty
*/
@Override
- public PluginData matchData(ServerWebExchange exchange, String dataName, List dataList, String path, SelectorData selectorData) {
+ public PluginData matchData(final ServerWebExchange exchange, final String dataName, final List dataList, final String path, final SelectorData selectorData) {
return dataList.isEmpty() ? null : dataList.get(0);
}
@@ -104,7 +121,7 @@ public PluginData matchData(ServerWebExchange exchange, String dataName, List {
private ShenyuConfig.RuleMatchCache ruleMatchConfig;
+
private ShenyuTrie ruleTrie;
/**
@@ -86,7 +108,7 @@ public RuleDataDecisionMaker() {
* @return a Mono indicating completion of the empty handler operation
*/
@Override
- public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
+ public Mono handleEmpty(final String pluginName, final ServerWebExchange exchange, final ShenyuPluginChain chain) {
return chain.execute(exchange);
}
@@ -111,7 +133,7 @@ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, She
* @return the matched RuleData, or null if no suitable rule is found
*/
@Override
- public RuleData matchData(ServerWebExchange exchange, String ruleName, List dataList, String path, SelectorData selectorData) {
+ public RuleData matchData(final ServerWebExchange exchange, final String ruleName, final List dataList, final String path, final SelectorData selectorData) {
return dataList.isEmpty() ? trieMatchRule(exchange, ruleName, selectorData, path) : dataList.get(0);
}
@@ -126,9 +148,10 @@ public RuleData matchData(ServerWebExchange exchange, String ruleName, List {
private ShenyuConfig.SelectorMatchCache selectorMatchConfig;
+
private ShenyuTrie selectorTrie;
/**
@@ -78,7 +101,7 @@ public SelectorDataDecisionMaker() {
* @return a Mono indicating completion of the empty handling operation
*/
@Override
- public Mono handleEmpty(String pluginName, ServerWebExchange exchange, ShenyuPluginChain chain) {
+ public Mono handleEmpty(final String pluginName, final ServerWebExchange exchange, final ShenyuPluginChain chain) {
return chain.execute(exchange);
}
@@ -107,7 +130,7 @@ public Mono handleEmpty(String pluginName, ServerWebExchange exchange, She
*
*/
@Override
- public SelectorData matchData(ServerWebExchange exchange, String pluginName, List dataList, String path, SelectorData selectorData) {
+ public SelectorData matchData(final ServerWebExchange exchange, final String pluginName, final List dataList, final String path, final SelectorData selectorData) {
return dataList.isEmpty() ? trieMatchSelector(exchange, pluginName, path) : dataList.get(0);
}
@@ -123,8 +146,8 @@ public SelectorData matchData(ServerWebExchange exchange, String pluginName, Lis
* false otherwise
*/
@Override
- public boolean shouldContinue(SelectorData data) {
- return data != null && data.getEnabled() && data.getContinued();
+ public boolean shouldContinue(final SelectorData data) {
+ return data.getEnabled() && data.getContinued();
}
/**
@@ -282,7 +305,7 @@ private SelectorData manyMatchSelector(final List filterCollectors
* @param selectorData the selector data to cache
* @param selectorMatchConfig the cache configuration parameters
*/
- private void cacheSelectorData(final String path, final SelectorData selectorData, ShenyuConfig.SelectorMatchCache selectorMatchConfig) {
+ private void cacheSelectorData(final String path, final SelectorData selectorData, final ShenyuConfig.SelectorMatchCache selectorMatchConfig) {
if (Boolean.FALSE.equals(selectorMatchConfig.getCache().getEnabled()) || Objects.isNull(selectorData)
|| Boolean.TRUE.equals(selectorData.getMatchRestful())) {
return;
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
index a149e14969e2..0a23ee1b8bfa 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java
@@ -1,22 +1,26 @@
+/*
+ * 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.shenyu.plugin.base.provider;
import java.util.List;
/**
* A generic interface for providing data based on a given key.
- *
- * Implementations of this interface are responsible for retrieving a list of data items
- * of type {@code T} associated with the specified key. This can be used in plugin systems
- * or other contexts where data needs to be fetched dynamically.
- *
- * @param Names of various data types
-
-/**
- * A generic interface for providing data based on a given key.
- *
- * Implementations of this interface are responsible for retrieving a list of data items
- * of type {@code T} associated with the specified key. This can be used in plugin systems
- * or other contexts where data needs to be fetched dynamically.
*
* @param the type of data provided by this provider
*/
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
index b31987c9f01f..2b5d1d2b2e83 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java
@@ -1,3 +1,20 @@
+/*
+ * 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.shenyu.plugin.base.provider;
import org.apache.shenyu.common.dto.PluginData;
@@ -5,36 +22,16 @@
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* A concrete implementation of the data provider pattern for retrieving plugin data
* in the ShenYu gateway system.
- *
- * This class is responsible for fetching {@link PluginData} objects from the underlying
- * data cache ({@link BaseDataCache}) based on the provided plugin name. It implements
- * the {@code DataProvider} interface, providing a standardized way to
- * access plugin configuration data throughout the application.
- *
- *
- * In the ShenYu plugin architecture, this class serves as a specific layer in the data
- * access mechanism, interacting with the system's caching infrastructure through an
- * data provider interface to efficiently supply plugin information to
- * upstream services or components that require it.
- *
- *
- * @see org.apache.shenyu.plugin.base.cache.BaseDataCache
- * @see PluginData
*/
public class PluginDataProvider implements DataProvider {
/**
* Retrieves plugin data from the base data cache for the specified plugin name.
- *
- * This method queries the internally maintained cache instance. If plugin data
- * matching the given name is found, it is wrapped in a singleton list and returned.
- * If no matching data is found (i.e., the plugin name does not exist in the cache),
- * an empty immutable list is returned.
- *
*
* @param pluginName the name of the plugin to retrieve. This parameter should not be null,
* though the current implementation may return an empty list rather than
@@ -43,8 +40,8 @@ public class PluginDataProvider implements DataProvider {
* is found, otherwise an empty immutable list. The return value will never be null.
*/
@Override
- public List getData(String pluginName) {
+ public List getData(final String pluginName) {
PluginData data = BaseDataCache.getInstance().obtainPluginData(pluginName);
- return data != null ? Collections.singletonList(data) : Collections.emptyList();
+ return Objects.nonNull(data) ? Collections.singletonList(data) : Collections.emptyList();
}
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
index baf39bb9c13e..80fad15bc714 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java
@@ -1,8 +1,25 @@
+/*
+ * 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.shenyu.plugin.base.provider;
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.plugin.base.cache.BaseDataCache;
-import java.util.Collections;
+
import java.util.List;
/**
@@ -21,8 +38,8 @@ public class RuleDataProvider implements DataProvider {
*
*/
@Override
- public List getData(String ruleName) {
+ public List getData(final String ruleName) {
List data = BaseDataCache.getInstance().obtainRuleData(ruleName);
- return data != null ? data : Collections.emptyList();
+ return data;
}
}
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
index cca559c24174..b9448349c2da 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java
@@ -1,9 +1,25 @@
+/*
+ * 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.shenyu.plugin.base.provider;
import org.apache.shenyu.common.dto.SelectorData;
import org.apache.shenyu.plugin.base.cache.BaseDataCache;
-import java.util.Collections;
import java.util.List;
/**
@@ -54,8 +70,8 @@ public class SelectorDataProvider implements DataProvider {
*
*/
@Override
- public List getData(String selectorName) {
+ public List getData(final String selectorName) {
List data = BaseDataCache.getInstance().obtainSelectorData(selectorName);
- return data != null ? data : Collections.emptyList();
+ return data;
}
}
\ No newline at end of file