@Override
    public Mono<Void> 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<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
        if (CollectionUtils.isEmpty(selectors)) {
            return handleSelectorIfNull(pluginName, exchange, chain);
        }
        SelectorData selectorData = obtainSelectorDataCacheIfEnabled(path);
        // handle Selector
        if (Objects.nonNull(selectorData) && StringUtils.isBlank(selectorData.getId())) {
            return handleSelectorIfNull(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);
                }
            }
        }
        printLog(selectorData, pluginName);
        if (!selectorData.getContinued()) {
            // if continued， not match rules
            return doExecute(exchange, chain, selectorData, defaultRuleData(selectorData));
        }
        List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
        if (CollectionUtils.isEmpty(rules)) {
            return handleRuleIfNull(pluginName, exchange, chain);
        }
        if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
            //get last
            RuleData rule = rules.get(rules.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);
                }
            }
        }
        printLog(ruleData, pluginName);
        return doExecute(exchange, chain, selectorData, ruleData);
    }
@Test
    public void executeRuleIsNullTest() {
        List<ConditionData> conditionDataList = Collections.singletonList(conditionData);
        this.selectorData.setMatchMode(0);
        this.selectorData.setLogged(true);
        this.selectorData.setMatchRestful(false);
        this.selectorData.setConditionList(conditionDataList);
        BaseDataCache.getInstance().cachePluginData(pluginData);
        BaseDataCache.getInstance().cacheSelectData(selectorData);
        StepVerifier.create(testShenyuPlugin.execute(exchange, shenyuPluginChain)).expectSubscription().verifyComplete();
        verify(shenyuPluginChain).execute(exchange);
    }