- Notifications
You must be signed in to change notification settings - Fork3k
[type:fix] Fix : selector logic refactoring#6081#6231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:master
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Conversation
1.抽取PluginData、SelectorData 和 RuleData 公共部分为 BaseData2. 规则选择逻辑重构 定义数据决策处理类,提取公共部分的代码并做封装
# Conflicts:#shenyu-common/src/main/java/org/apache/shenyu/common/dto/BaseData.java#shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java#shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java#shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Pull Request Overview
This pull request aims to refactor the selector and rule matching logic in the ShenYu plugin system by extracting common data fields into aBaseData class and introducing a decision maker pattern. However, the refactoring introduces several critical bugs and issues that need to be addressed.
Key Changes:
- Extracted common fields (id, name, enabled, sort, namespaceId) from PluginData, SelectorData, and RuleData into a new BaseData parent class
- Created a new DataProvider interface with implementations for Plugin, Selector, and Rule data
- Introduced AbstractMatchDecisionMaker and concrete decision maker classes to encapsulate matching logic
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
| shenyu-common/src/main/java/org/apache/shenyu/common/dto/BaseData.java | New base class containing common DTO fields |
| shenyu-common/src/main/java/org/apache/shenyu/common/dto/SelectorData.java | Builder class refactored to extend BaseData |
| shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java | Builder class refactored to extend BaseData |
| shenyu-common/src/main/java/org/apache/shenyu/common/dto/PluginData.java | Builder class refactored to extend BaseData |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/DataProvider.java | New interface for data retrieval abstraction |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/SelectorDataProvider.java | Implementation for selector data retrieval |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/RuleDataProvider.java | Implementation for rule data retrieval with unused import |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/provider/PluginDataProvider.java | Implementation for plugin data retrieval |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/AbstractMatchDecisionMaker.java | Abstract base class for decision making pattern |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/SelectorDataDecisionMaker.java | Decision maker for selectors with incorrect matching logic |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/RuleDataDecisionMaker.java | Decision maker for rules with incorrect matching logic |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/maker/PluginDataDecisionMaker.java | Decision maker for plugins |
| shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java | Refactored execute method using decision makers, but with critical bugs in selector continuation logic and missing trie/cache matching |
💡Add Copilot custom instructions for smarter, more guided reviews.Learn how to get started.
| publicinterfaceDataProvider<T> { |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Missing class-level and method-level documentation. This is a new public interface that should include Javadoc explaining its purpose, usage, and the meaning of the type parameterT and method parameterkey.
| publicinterfaceDataProvider<T> { | |
| /** | |
| *Agenericinterfaceforprovidingdatabasedonagivenkey. | |
| * <p> | |
| *Implementationsofthisinterfaceareresponsibleforretrievingalistofdataitems | |
| *oftype {@codeT}associatedwiththespecifiedkey.Thiscanbeusedinpluginsystems | |
| *orothercontextswheredataneedstobefetcheddynamically. | |
| * | |
| *@param <T>thetypeofdataprovidedbythisprovider | |
| */ | |
| publicinterfaceDataProvider<T> { | |
| /** | |
| *Retrievesalistofdataitemsassociatedwiththespecifiedkey. | |
| * | |
| *@paramkeythekeyusedtolookupthedata;itsmeaningisdefinedbytheimplementation | |
| *@returnalistofdataitemsoftype {@codeT}associatedwiththegivenkey, | |
| *oranemptylistifnodataisfound | |
| */ |
| printLog(selectorData,pluginName); | ||
| if (!selectorData.getContinued()) { | ||
| // if continued, not match rules | ||
| if (!selectorDataDecisionMaker.shouldContinue(selectorData)) { |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Incorrect usage ofshouldContinue(). TheshouldContinue method checks if data is enabled (data.getEnabled()), but the original logic checkedselectorData.getContinued() which indicates whether to continue processing rules. These are two different concepts:enabled controls if the selector is active, whilecontinued controls whether to proceed to rule matching. The correct check should beif (!selectorData.getContinued()) instead ofif (!selectorDataDecisionMaker.shouldContinue(selectorData)).
| if (!selectorDataDecisionMaker.shouldContinue(selectorData)) { | |
| if (!selectorData.getContinued()) { |
| @Override | ||
| publicbooleanshouldContinue(SelectorDatadata) { | ||
| returndata !=null &&data.getEnabled(); |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
TheshouldContinue method logic is incorrect for SelectorData. It checksdata.getEnabled(), but based on its usage in AbstractShenyuPlugin line 119, it should checkdata.getContinued() instead. Thecontinued field determines whether to continue processing rules after a selector matches, which is different from theenabled field that controls if the selector is active.
| returndata !=null &&data.getEnabled(); | |
| returndata !=null &&data.getContinued(); |
| publicclassPluginDataProviderimplementsDataProvider<PluginData> { | ||
| @Override | ||
| publicList<PluginData>getData(StringpluginName) { | ||
| PluginDatadata =BaseDataCache.getInstance().obtainPluginData(pluginName); | ||
| returndata !=null ?Collections.singletonList(data) :Collections.emptyList(); | ||
| } | ||
| } No newline at end of file |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Missing class-level and method-level documentation. This new public class should include Javadoc explaining its purpose and how it fits into the data provider pattern.
| if (Objects.nonNull(selectorData) &&StringUtils.isBlank(selectorData.getId())) { | ||
| returnhandleSelectorIfNull(pluginName,exchange,chain); | ||
| SelectorDataDecisionMakerselectorDataDecisionMaker =newSelectorDataDecisionMaker(); |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Creating a newSelectorDataDecisionMaker instance on every request is inefficient. This should be a reusable class field to avoid unnecessary object allocation.
| if (CollectionUtils.isEmpty(selectors)) { | ||
| returnhandleSelectorIfNull(pluginName,exchange,chain); | ||
| PluginDataDecisionMakerpluginDataDecisionMaker =newPluginDataDecisionMaker(); |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Creating a newPluginDataDecisionMaker instance on every request is inefficient. These DecisionMaker instances are stateless and should be created once as class fields (similar to how other components are reused) to avoid unnecessary object allocation on each request. The same issue applies toSelectorDataDecisionMaker (line 107) andRuleDataDecisionMaker (line 124).
| importorg.apache.shenyu.plugin.base.cache.BaseDataCache; | ||
| importorg.apache.shenyu.plugin.base.cache.MatchDataCache; | ||
| importorg.apache.shenyu.plugin.base.condition.strategy.MatchStrategyFactory; | ||
| importorg.apache.shenyu.plugin.base.handler.PluginDataHandler; |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Unused importPluginDataHandler. This import is not used anywhere in the class and should be removed.
| import org.apache.shenyu.plugin.base.handler.PluginDataHandler; |
| @@ -0,0 +1,15 @@ | |||
| packageorg.apache.shenyu.plugin.base.provider; | |||
| importorg.apache.shenyu.common.dto.RuleData; | |||
| importorg.apache.shenyu.common.dto.SelectorData; | |||
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Unused importSelectorData. This import is not used anywhere in the class and should be removed.
| import org.apache.shenyu.common.dto.SelectorData; |
| publicclassRuleDataProviderimplementsDataProvider<RuleData> { | ||
| @Override | ||
| publicList<RuleData>getData(StringruleName) { | ||
| List<RuleData>data =BaseDataCache.getInstance().obtainRuleData(ruleName); | ||
| returndata !=null ?data :Collections.emptyList(); | ||
| } | ||
| } No newline at end of file |
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Missing class-level and method-level documentation. This new public class should include Javadoc explaining its purpose and how it fits into the data provider pattern.
| publicabstractclassAbstractMatchDecisionMaker<TextendsBaseData> { | ||
| privatefinalDataProvider<T>dataProvider; | ||
| protectedAbstractMatchDecisionMaker(DataProvider<T>dataProvider) { | ||
| this.dataProvider =dataProvider; | ||
| } | ||
| publicList<T>getData(Stringkey) { | ||
| returndataProvider.getData(key); | ||
| } | ||
| protectedabstractMono<Void>handleEmpty(StringpluginName,ServerWebExchangeexchange,ShenyuPluginChainchain); | ||
| protectedabstractTmatchData(ServerWebExchangeexchange,List<T>dataList,Stringpath); | ||
CopilotAINov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Missing class-level and method-level documentation. This new public abstract class should include Javadoc explaining its purpose, the template method pattern it implements, and detailed documentation for each abstract method describing their responsibilities and expected behavior.
| publicabstractclassAbstractMatchDecisionMaker<TextendsBaseData> { | |
| privatefinalDataProvider<T>dataProvider; | |
| protectedAbstractMatchDecisionMaker(DataProvider<T>dataProvider) { | |
| this.dataProvider =dataProvider; | |
| } | |
| publicList<T>getData(Stringkey) { | |
| returndataProvider.getData(key); | |
| } | |
| protectedabstractMono<Void>handleEmpty(StringpluginName,ServerWebExchangeexchange,ShenyuPluginChainchain); | |
| protectedabstractTmatchData(ServerWebExchangeexchange,List<T>dataList,Stringpath); | |
| /** | |
| *AbstractbaseclassformakingmatchdecisionsinpluginsusingtheTemplateMethodpattern. | |
| * <p> | |
| *Thisclassprovidesatemplateforprocessingdatamatchinglogicinplugins.Subclassesareexpected | |
| *toimplementtheabstractmethodstodefinespecificbehaviorsforhandlingemptydata,matchingdata, | |
| *anddeterminingwhetherprocessingshouldcontinue. | |
| * </p> | |
| * | |
| * <p> | |
| *TheTemplateMethodpatternisusedheretoallowsubclassestooverridecertainstepsofthealgorithm | |
| *withoutchangingitsstructure. | |
| * </p> | |
| * | |
| *@param <T>thetypeofdatatobematched,extending {@linkBaseData} | |
| */ | |
| publicabstractclassAbstractMatchDecisionMaker<TextendsBaseData> { | |
| privatefinalDataProvider<T>dataProvider; | |
| /** | |
| *ConstructsanAbstractMatchDecisionMakerwiththespecifieddataprovider. | |
| * | |
| *@paramdataProviderthedataproviderusedtoretrievedataformatching | |
| */ | |
| protectedAbstractMatchDecisionMaker(DataProvider<T>dataProvider) { | |
| this.dataProvider =dataProvider; | |
| } | |
| /** | |
| *Retrievesalistofdataassociatedwiththegivenkey. | |
| * | |
| *@paramkeythekeyusedtoretrievedata | |
| *@returnalistofdataobjectsassociatedwiththekey | |
| */ | |
| publicList<T>getData(Stringkey) { | |
| returndataProvider.getData(key); | |
| } | |
| /** | |
| *Handlesthescenariowhennomatchingdataisfoundforthegivenplugin. | |
| * | |
| *@parampluginNamethenameoftheplugin | |
| *@paramexchangethecurrentserverwebexchange | |
| *@paramchainthepluginchaintocontinueprocessing | |
| *@returna {@linkMono}thatcompleteswhenthehandlingisdone | |
| */ | |
| protectedabstractMono<Void>handleEmpty(StringpluginName,ServerWebExchangeexchange,ShenyuPluginChainchain); | |
| /** | |
| *Matchestheappropriatedatafromtheprovidedlistbasedontheexchangeandpath. | |
| * | |
| *@paramexchangethecurrentserverwebexchange | |
| *@paramdataListthelistofdatatomatchagainst | |
| *@parampaththerequestpathtouseformatching | |
| *@returnthematcheddataobject,or {@codenull}ifnomatchisfound | |
| */ | |
| protectedabstractTmatchData(ServerWebExchangeexchange,List<T>dataList,Stringpath); | |
| /** | |
| *Determineswhetherprocessingshouldcontinuebasedonthematcheddata. | |
| * | |
| *@paramdatathematcheddataobject | |
| *@return {@codetrue}ifprocessingshouldcontinue, {@codefalse}otherwise | |
| */ |
fixed:#6081
1.抽取PluginData、SelectorData 和 RuleData 公共部分为 BaseData
2. 规则选择逻辑重构 定义数据决策处理类,提取公共部分的代码并做封装
Make sure that:
./mvnw clean install -Dmaven.javadoc.skip=true.