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

liuhongyu pushed a commit to branch feat/refactor
in repository https://gitbox.apache.org/repos/asf/shenyu.git

commit ffd7cedd4552af74bb43491decf3dd94aa525205
Author: liuhy <[email protected]>
AuthorDate: Thu Jan 8 16:20:43 2026 +0800

    feat: implement enhanced caching and routing mechanisms with adaptive 
strategies
---
 .../src/main/resources/application-enhanced.yml    | 225 +++++++++++++++
 .../plugin/base/EnhancedAbstractShenyuPlugin.java  | 227 +++++++++++++++
 .../base/cache/DefaultSmartCacheManager.java       | 310 +++++++++++++++++++++
 .../plugin/base/cache/HybridCacheInstance.java     | 106 +++++++
 .../shenyu/plugin/base/cache/SmartCacheConfig.java | 189 +++++++++++++
 .../plugin/base/cache/SmartCacheManager.java       | 126 +++++++++
 .../plugin/base/cache/TrieCacheInstance.java       |  86 ++++++
 .../base/config/PluginBaseAutoConfiguration.java   | 104 +++++++
 .../base/context/PluginExecutionContext.java       | 174 ++++++++++++
 .../shenyu/plugin/base/metrics/MetricsHelper.java  |  98 +++++++
 .../plugin/base/metrics/NoOpMetricsHelper.java     |  42 +++
 .../plugin/base/route/DefaultRouteResolver.java    | 199 +++++++++++++
 .../shenyu/plugin/base/route/RouteResolver.java    |  66 +++++
 .../shenyu/plugin/base/route/RouteResult.java      |  95 +++++++
 .../src/main/resources/META-INF/spring.factories   |   2 +
 .../base/context/PluginExecutionContextTest.java   | 166 +++++++++++
 .../base/route/DefaultRouteResolverTest.java       | 226 +++++++++++++++
 17 files changed, 2441 insertions(+)

diff --git a/shenyu-bootstrap/src/main/resources/application-enhanced.yml 
b/shenyu-bootstrap/src/main/resources/application-enhanced.yml
new file mode 100644
index 0000000000..f69a74016b
--- /dev/null
+++ b/shenyu-bootstrap/src/main/resources/application-enhanced.yml
@@ -0,0 +1,225 @@
+# ShenYu Enhanced Configuration - Phase 1 Optimized
+# This configuration enables the performance improvements from the enhanced 
architecture
+
+server:
+  port: 9195
+  address: 0.0.0.0
+  compression:
+    enabled: true
+    min-response-size: 1MB
+
+spring:
+  main:
+    allow-bean-definition-overriding: true
+  application:
+    name: shenyu-bootstrap
+  codec:
+    # Increased for better performance with large requests
+    max-in-memory-size: 8MB  # Enhanced from 2MB
+  cloud:
+    discovery:
+      enabled: false
+
+# Enhanced ShenYu Configuration
+shenyu:
+  # Core system configuration
+  core:
+    namespace: ${SHENYU_NAMESPACE:649330b6-c2d7-4edc-be8e-8a54df9eb385}
+    mode: ${SHENYU_MODE:standalone}  # standalone, cluster
+
+  # Enhanced performance configuration
+  performance:
+    # Smart caching with adaptive strategies
+    cache:
+      enabled: true
+      strategy: adaptive  # adaptive, lru_only, trie_only, hybrid
+
+      # Selector cache configuration
+      selector:
+        strategy: adaptive
+        initialCapacity: 10000
+        maximumSize: 65536
+        expireAfterWrite: 30m
+        expireAfterAccess: 10m
+
+      # Rule cache configuration
+      rule:
+        strategy: adaptive
+        initialCapacity: 20000
+        maximumSize: 131072
+        expireAfterWrite: 30m
+        expireAfterAccess: 10m
+
+      # Plugin metadata cache
+      plugin:
+        strategy: lru_only
+        initialCapacity: 1000
+        maximumSize: 10000
+        expireAfterWrite: 60m
+
+      # Adaptive behavior configuration
+      adaptive:
+        switchThreshold: 1000
+        hitRatioThreshold: 0.8
+        evaluationInterval: 5m
+        autoOptimization: true
+
+    # Netty performance tuning
+    netty:
+      enabled: true
+      bossThreads: 1
+      workerThreads: ${SHENYU_WORKER_THREADS:8}  # Enhanced: configurable via 
env
+      maxConnections: 10000
+      backlog: 1024
+
+    # Enhanced thread pool configuration
+    threadPool:
+      enabled: true  # Enhanced: enabled by default
+      coreSize: ${SHENYU_CORE_THREADS:200}
+      maxSize: ${SHENYU_MAX_THREADS:2000}
+      queueCapacity: ${SHENYU_QUEUE_CAPACITY:10000}
+      keepAliveTime: 60s
+      threadNamePrefix: "shenyu-exec-"
+
+  # Enhanced observability configuration
+  observability:
+    # Comprehensive metrics collection
+    metrics:
+      enabled: true  # Enhanced: enabled by default
+      provider: prometheus
+      endpoint: /actuator/prometheus
+      collectInterval: 15s
+
+      # Detailed metric categories
+      categories:
+        plugin_execution: true
+        cache_performance: true
+        route_matching: true
+        error_tracking: true
+        jvm_metrics: true
+
+      # Custom labels for better monitoring
+      labels:
+        application: ${spring.application.name}
+        instance: ${HOSTNAME:${random.value}}
+        version: ${shenyu.version:2.7.1-enhanced}
+        environment: ${SHENYU_ENV:development}
+
+    # Enhanced logging configuration
+    logging:
+      enabled: true
+      level: ${SHENYU_LOG_LEVEL:INFO}
+
+      # Structured logging patterns
+      patterns:
+        request: "[%thread] %X{traceId:-N/A} %X{pluginName:-system} - %msg%n"
+        plugin: "[%thread] %X{traceId:-N/A} [%X{pluginName}] - %msg%n"
+        cache: "[%thread] %X{traceId:-N/A} [CACHE-%X{cacheType}] - %msg%n"
+
+      # Log sampling for high-traffic scenarios
+      sampling:
+        enabled: true
+        rate: 0.1  # Log 10% of requests
+
+    # Distributed tracing
+    tracing:
+      enabled: ${SHENYU_TRACING_ENABLED:false}
+      provider: ${SHENYU_TRACING_PROVIDER:zipkin}  # zipkin, jaeger, otel
+      samplingProbability: 0.1
+
+  # Enhanced health checking
+  health:
+    enabled: true
+    paths:
+      - /actuator/health
+      - /health_check
+
+    # Deep health checks
+    checks:
+      cache: true
+      database: true
+      upstream: true
+      memory: true
+
+    # Health check thresholds
+    thresholds:
+      memoryUsagePercent: 90
+      cacheHitRatio: 0.5
+      errorRate: 0.05
+
+  # Enhanced upstream checking
+  upstreamCheck:
+    enabled: true  # Enhanced: enabled by default
+    poolSize: ${SHENYU_UPSTREAM_POOL_SIZE:20}  # Enhanced: increased pool size
+    timeout: ${SHENYU_UPSTREAM_TIMEOUT:3000}
+    healthyThreshold: 2  # Enhanced: stricter health requirements
+    unhealthyThreshold: 3
+    interval: ${SHENYU_UPSTREAM_INTERVAL:5000}
+    circuitBreakerEnabled: true  # Enhanced: circuit breaker support
+
+  # Smart plugin management
+  plugins:
+    # Intelligent defaults based on usage patterns
+    defaults:
+      globalPlugin: { enabled: true, order: 0 }
+      signPlugin: { enabled: true, order: 10 }
+      wafPlugin: { enabled: true, order: 20 }
+      rateLimiterPlugin: { enabled: true, order: 30 }
+      dividePlugin: { enabled: true, order: 100 }
+      springCloudPlugin: { enabled: false, order: 200 }
+      dubboPlugin: { enabled: false, order: 300 }
+      responsePlugin: { enabled: true, order: 1000 }
+
+    # Plugin auto-discovery and loading
+    discovery:
+      enabled: true
+      scanPackages:
+        - "org.apache.shenyu.plugin"
+        - "com.custom.shenyu.plugin"
+
+  # Legacy compatibility (for migration period)
+  legacy:
+    selectorMatchCache:
+      cache:
+        enabled: true  # Bridged to new cache system
+        initialCapacity: 10000
+        maximumSize: 10000
+    ruleMatchCache:
+      cache:
+        enabled: true  # Bridged to new cache system
+        initialCapacity: 10000
+        maximumSize: 65536
+
+# Spring Boot Actuator configuration for monitoring
+management:
+  endpoints:
+    web:
+      exposure:
+        include:
+          - 'health'
+          - 'info'
+          - 'metrics'
+          - 'prometheus'
+          - 'caches'
+          - 'threaddump'
+          - 'heapdump'
+  endpoint:
+    health:
+      show-details: always
+      show-components: always
+    metrics:
+      enabled: true
+    prometheus:
+      enabled: true
+
+# Enhanced logging configuration
+logging:
+  level:
+    root: ${SHENYU_LOG_LEVEL:INFO}
+    org.apache.shenyu: INFO
+    org.apache.shenyu.plugin.base.cache: DEBUG  # Enhanced cache logging
+    org.apache.shenyu.plugin.base.metrics: DEBUG  # Enhanced metrics logging
+    org.apache.shenyu.plugin.base.route: DEBUG   # Enhanced routing logging
+  pattern:
+    console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{traceId:-N/A} 
- %msg%n"
+    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} 
%X{traceId:-N/A} %X{pluginName:-system} - %msg%n"
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/EnhancedAbstractShenyuPlugin.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/EnhancedAbstractShenyuPlugin.java
new file mode 100644
index 0000000000..f98e0a3d97
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/EnhancedAbstractShenyuPlugin.java
@@ -0,0 +1,227 @@
+package org.apache.shenyu.plugin.base;
+
+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.plugin.api.ShenyuPlugin;
+import org.apache.shenyu.plugin.api.ShenyuPluginChain;
+import org.apache.shenyu.plugin.base.cache.BaseDataCache;
+import org.apache.shenyu.plugin.base.context.PluginExecutionContext;
+import org.apache.shenyu.plugin.base.metrics.MetricsHelper;
+import org.apache.shenyu.plugin.base.route.RouteResolver;
+import org.apache.shenyu.plugin.base.route.RouteResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.Objects;
+
+/**
+ * Enhanced AbstractShenyuPlugin with separated responsibilities.
+ *
+ * Key improvements:
+ * 1. Simplified execute() method using template method pattern
+ * 2. Delegated routing logic to RouteResolver
+ * 3. Built-in metrics collection
+ * 4. Cleaner error handling
+ * 5. Lazy initialization of dependencies
+ *
+ * Backward compatibility: This class maintains the same public interface
+ * as the original AbstractShenyuPlugin, ensuring existing plugins work 
without changes.
+ */
+public abstract class EnhancedAbstractShenyuPlugin implements ShenyuPlugin {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(EnhancedAbstractShenyuPlugin.class);
+
+    // Lazy-initialized dependencies
+    private volatile RouteResolver routeResolver;
+    private volatile MetricsHelper metricsHelper;
+    private volatile boolean initialized = false;
+
+    /**
+     * Template method for plugin execution.
+     *
+     * This method implements the main execution flow:
+     * 1. Check plugin enabled status
+     * 2. Create execution context
+     * 3. Resolve routing (selector + rule)
+     * 4. Execute plugin logic
+     * 5. Record metrics and handle errors
+     */
+    @Override
+    public final Mono<Void> execute(final ServerWebExchange exchange, final 
ShenyuPluginChain chain) {
+        // Lazy initialization on first use
+        if (!initialized) {
+            initializeDependencies();
+        }
+
+        final String pluginName = named();
+
+        return Mono.just(pluginName)
+                .flatMap(this::checkPluginEnabled)
+                .filter(enabled -> enabled)
+                .flatMap(enabled -> createExecutionContext(exchange))
+                .flatMap(context -> executeWithContext(context, chain))
+                .switchIfEmpty(chain.execute(exchange)) // Plugin disabled or 
not applicable
+                .doOnSuccess(v -> metricsHelper.recordSuccess(pluginName))
+                .doOnError(error -> {
+                    metricsHelper.recordError(pluginName, error);
+                    LOG.error("Plugin [{}] execution failed", pluginName, 
error);
+                })
+                .onErrorResume(error -> handlePluginError(exchange, chain, 
error));
+    }
+
+    /**
+     * Core plugin execution logic with context.
+     */
+    private Mono<Void> executeWithContext(PluginExecutionContext context, 
ShenyuPluginChain chain) {
+        final String pluginName = named();
+        final long startTime = System.nanoTime();
+
+        return routeResolver.resolveRoute(context, pluginName)
+                .flatMap(routeResult -> {
+                    if (!routeResult.isMatched()) {
+                        return handleNoMatch(context, chain);
+                    }
+
+                    // Record metrics for successful route resolution
+                    metricsHelper.recordRouteMatch(pluginName, 
routeResult.getMatchType());
+
+                    // Execute plugin business logic
+                    return executePluginLogic(context, chain, routeResult);
+                })
+                .doFinally(signal -> {
+                    long duration = System.nanoTime() - startTime;
+                    metricsHelper.recordExecutionTime(pluginName, duration);
+                })
+                .contextWrite(ctx -> ctx.put("pluginName", pluginName));
+    }
+
+    /**
+     * Execute the actual plugin business logic.
+     */
+    private Mono<Void> executePluginLogic(
+            PluginExecutionContext context,
+            ShenyuPluginChain chain,
+            RouteResult routeResult) {
+
+        SelectorData selector = routeResult.getSelector().orElse(null);
+        RuleData rule = 
routeResult.getRule().orElse(createDefaultRule(selector));
+
+        // Call the abstract method that subclasses implement
+        return Mono.fromRunnable(() -> printExecutionLog(selector, rule, 
named()))
+                .then(doExecute(context.getExchange(), chain, selector, rule));
+    }
+
+    /**
+     * Abstract method that subclasses must implement.
+     * This maintains backward compatibility with the original interface.
+     */
+    protected abstract Mono<Void> doExecute(
+            ServerWebExchange exchange,
+            ShenyuPluginChain chain,
+            SelectorData selector,
+            RuleData rule);
+
+    // === Hook Methods for Customization ===
+
+    /**
+     * Handle scenarios where no route is matched.
+     * Subclasses can override for custom behavior.
+     */
+    protected Mono<Void> handleNoMatch(PluginExecutionContext context, 
ShenyuPluginChain chain) {
+        return chain.execute(context.getExchange());
+    }
+
+    /**
+     * Handle plugin execution errors.
+     * Subclasses can override for custom error handling.
+     */
+    protected Mono<Void> handlePluginError(
+            ServerWebExchange exchange,
+            ShenyuPluginChain chain,
+            Throwable error) {
+        // Default: continue chain execution on error
+        return chain.execute(exchange);
+    }
+
+    /**
+     * Create execution context from exchange.
+     * Subclasses can override to add custom context data.
+     */
+    protected Mono<PluginExecutionContext> 
createExecutionContext(ServerWebExchange exchange) {
+        return Mono.just(PluginExecutionContext.fromExchange(exchange));
+    }
+
+    // === Helper Methods ===
+
+    /**
+     * Check if plugin is enabled.
+     */
+    private Mono<Boolean> checkPluginEnabled(String pluginName) {
+        return Mono.fromCallable(() -> {
+            PluginData pluginData = 
BaseDataCache.getInstance().obtainPluginData(pluginName);
+            return Objects.nonNull(pluginData) && pluginData.getEnabled();
+        });
+    }
+
+    /**
+     * Create default rule when selector doesn't continue to rules.
+     */
+    private RuleData createDefaultRule(SelectorData selector) {
+        if (selector == null) {
+            return null;
+        }
+
+        RuleData rule = new RuleData();
+        rule.setSelectorId(selector.getId());
+        rule.setPluginName(selector.getPluginName());
+        rule.setId("default_rule");
+        rule.setName("Default Rule");
+        return rule;
+    }
+
+    /**
+     * Print execution log if logging is enabled.
+     */
+    private void printExecutionLog(SelectorData selector, RuleData rule, 
String pluginName) {
+        if (selector != null && selector.getLogged()) {
+            LOG.info("{} selector success match, selector name: {}", 
pluginName, selector.getName());
+        }
+        if (rule != null && rule.getLoged()) {
+            LOG.info("{} rule success match, rule name: {}", pluginName, 
rule.getName());
+        }
+    }
+
+    /**
+     * Lazy initialization of dependencies to avoid startup overhead.
+     */
+    private synchronized void initializeDependencies() {
+        if (initialized) {
+            return;
+        }
+
+        try {
+            // Initialize RouteResolver
+            this.routeResolver = getSpringBean(RouteResolver.class);
+
+            // Initialize MetricsHelper
+            this.metricsHelper = getSpringBean(MetricsHelper.class);
+
+            initialized = true;
+            LOG.debug("Dependencies initialized for plugin: {}", named());
+
+        } catch (Exception e) {
+            LOG.error("Failed to initialize dependencies for plugin: {}", 
named(), e);
+            throw new IllegalStateException("Plugin initialization failed", e);
+        }
+    }
+
+    /**
+     * Get Spring bean - subclasses can override for different IoC strategies.
+     */
+    protected <T> T getSpringBean(Class<T> clazz) {
+        return 
org.apache.shenyu.plugin.api.utils.SpringBeanUtils.getInstance().getBean(clazz);
+    }
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/DefaultSmartCacheManager.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/DefaultSmartCacheManager.java
new file mode 100644
index 0000000000..edf60fc1f7
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/DefaultSmartCacheManager.java
@@ -0,0 +1,310 @@
+package org.apache.shenyu.plugin.base.cache;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.stats.CacheStats;
+import org.apache.shenyu.common.config.ShenyuConfig;
+import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Mono;
+
+import java.time.Duration;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Default implementation of SmartCacheManager with adaptive strategies.
+ *
+ * Supports multiple caching strategies:
+ * 1. LRU_ONLY - Pure LRU cache using Caffeine
+ * 2. TRIE_ONLY - Pure Trie-based cache for path matching
+ * 3. HYBRID - Combination of LRU (L1) + Trie (L2)
+ * 4. ADAPTIVE - Automatically switches between strategies based on performance
+ */
+@Component
+public class DefaultSmartCacheManager implements SmartCacheManager {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(DefaultSmartCacheManager.class);
+
+    private final ConcurrentHashMap<String, CacheInstance<?>> caches = new 
ConcurrentHashMap<>();
+    private final SmartCacheConfig config;
+    private final AtomicLong totalRequests = new AtomicLong(0);
+
+    public DefaultSmartCacheManager(ShenyuConfig shenyuConfig) {
+        this.config = SmartCacheConfig.fromShenyuConfig(shenyuConfig);
+        initializePredefinedCaches();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <K, V> Mono<V> getOrLoad(String cacheType, K key, Mono<V> loader) {
+        totalRequests.incrementAndGet();
+
+        return Mono.fromCallable(() -> {
+            CacheInstance<V> cache = (CacheInstance<V>) 
getOrCreateCache(cacheType);
+            return cache.getOrLoad(key, loader);
+        }).flatMap(mono -> mono);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <K, V> Mono<Void> put(String cacheType, K key, V value, Duration 
ttl) {
+        return Mono.fromRunnable(() -> {
+            CacheInstance<V> cache = (CacheInstance<V>) 
getOrCreateCache(cacheType);
+            cache.put(key, value, ttl);
+        });
+    }
+
+    @Override
+    public <K> Mono<Void> invalidate(String cacheType, K key) {
+        return Mono.fromRunnable(() -> {
+            CacheInstance<?> cache = getOrCreateCache(cacheType);
+            cache.invalidate(key);
+        });
+    }
+
+    @Override
+    public Mono<Void> clear(String cacheType) {
+        return Mono.fromRunnable(() -> {
+            CacheInstance<?> cache = caches.get(cacheType);
+            if (cache != null) {
+                cache.clear();
+            }
+        });
+    }
+
+    @Override
+    public SmartCacheManager.CacheStats getStats(String cacheType) {
+        CacheInstance<?> cache = caches.get(cacheType);
+        return cache != null ? cache.getStats() : createEmptyStats();
+    }
+
+    @Override
+    public Mono<Void> adaptStrategy(String cacheType) {
+        return Mono.fromRunnable(() -> {
+            CacheInstance<?> cache = caches.get(cacheType);
+            if (cache instanceof AdaptiveCacheInstance) {
+                ((AdaptiveCacheInstance<?>) cache).adaptStrategy();
+            }
+        });
+    }
+
+    /**
+     * Get or create cache instance for the given type.
+     */
+    private CacheInstance<?> getOrCreateCache(String cacheType) {
+        return caches.computeIfAbsent(cacheType, type -> {
+            SmartCacheConfig.CacheConfig typeConfig = 
config.getCacheConfig(type);
+            return createCacheInstance(type, typeConfig);
+        });
+    }
+
+    /**
+     * Create appropriate cache instance based on configuration.
+     */
+    private CacheInstance<?> createCacheInstance(String cacheType, 
SmartCacheConfig.CacheConfig cacheConfig) {
+        switch (cacheConfig.getStrategy()) {
+            case LRU_ONLY:
+                return new LruCacheInstance<>(cacheConfig);
+            case TRIE_ONLY:
+                LOG.info("Creating Trie cache instance (Phase 1 basic 
implementation)");
+                return new LruCacheInstance<>(cacheConfig); // Use LRU for now
+            case HYBRID:
+                LOG.info("Creating Hybrid cache instance (Phase 1 basic 
implementation)");
+                return new LruCacheInstance<>(cacheConfig); // Use LRU for now
+            case ADAPTIVE:
+                return new AdaptiveCacheInstance<>(cacheConfig);
+            default:
+                LOG.warn("Unknown cache strategy: {}, falling back to LRU", 
cacheConfig.getStrategy());
+                return new LruCacheInstance<>(cacheConfig);
+        }
+    }
+
+    /**
+     * Initialize predefined cache instances.
+     */
+    private void initializePredefinedCaches() {
+        // Pre-create common cache types
+        getOrCreateCache(CacheTypes.SELECTOR);
+        getOrCreateCache(CacheTypes.RULE);
+        getOrCreateCache(CacheTypes.PLUGIN);
+
+        LOG.info("Smart cache manager initialized with strategy: {}", 
config.getDefaultStrategy());
+    }
+
+    private SmartCacheManager.CacheStats createEmptyStats() {
+        return new SmartCacheManager.CacheStats(0, 0, 0, 0, "NONE");
+    }
+
+    /**
+     * Base interface for cache instances.
+     */
+    private interface CacheInstance<V> {
+        <K> Mono<V> getOrLoad(K key, Mono<V> loader);
+        <K> void put(K key, V value, Duration ttl);
+        <K> void invalidate(K key);
+        void clear();
+        SmartCacheManager.CacheStats getStats();
+    }
+
+    /**
+     * LRU-only cache implementation using Caffeine.
+     */
+    private static class LruCacheInstance<V> implements CacheInstance<V> {
+        private final Cache<Object, V> cache;
+        private final SmartCacheConfig.CacheConfig config;
+
+        public LruCacheInstance(SmartCacheConfig.CacheConfig config) {
+            this.config = config;
+            this.cache = Caffeine.newBuilder()
+                    .initialCapacity(config.getInitialCapacity())
+                    .maximumSize(config.getMaximumSize())
+                    .expireAfterWrite(config.getExpireAfterWrite())
+                    .expireAfterAccess(config.getExpireAfterAccess())
+                    .recordStats()
+                    .build();
+        }
+
+        @Override
+        public <K> Mono<V> getOrLoad(K key, Mono<V> loader) {
+            V cachedValue = cache.getIfPresent(key);
+            if (cachedValue != null) {
+                return Mono.just(cachedValue);
+            }
+
+            return loader.doOnNext(value -> {
+                if (value != null) {
+                    cache.put(key, value);
+                }
+            });
+        }
+
+        @Override
+        public <K> void put(K key, V value, Duration ttl) {
+            cache.put(key, value);
+        }
+
+        @Override
+        public <K> void invalidate(K key) {
+            cache.invalidate(key);
+        }
+
+        @Override
+        public void clear() {
+            cache.invalidateAll();
+        }
+
+        @Override
+        public SmartCacheManager.CacheStats getStats() {
+            com.github.benmanes.caffeine.cache.stats.CacheStats caffeineStats 
= cache.stats();
+            return new SmartCacheManager.CacheStats(
+                    caffeineStats.hitCount(),
+                    caffeineStats.missCount(),
+                    (long) caffeineStats.averageLoadPenalty(),
+                    caffeineStats.evictionCount(),
+                    "LRU_ONLY"
+            );
+        }
+    }
+
+    /**
+     * Adaptive cache implementation that switches strategies based on 
performance.
+     */
+    private static class AdaptiveCacheInstance<V> implements CacheInstance<V> {
+        private volatile CacheInstance<V> activeCache;
+        private final SmartCacheConfig.CacheConfig config;
+        private final AtomicLong requestCount = new AtomicLong(0);
+        private final AtomicLong lastAdaptation = new 
AtomicLong(System.currentTimeMillis());
+
+        public AdaptiveCacheInstance(SmartCacheConfig.CacheConfig config) {
+            this.config = config;
+            this.activeCache = new LruCacheInstance<>(config); // Start with 
LRU
+        }
+
+        @Override
+        public <K> Mono<V> getOrLoad(K key, Mono<V> loader) {
+            long count = requestCount.incrementAndGet();
+
+            // Check if adaptation is needed
+            if (shouldAdapt(count)) {
+                adaptStrategy();
+            }
+
+            return activeCache.getOrLoad(key, loader);
+        }
+
+        @Override
+        public <K> void put(K key, V value, Duration ttl) {
+            activeCache.put(key, value, ttl);
+        }
+
+        @Override
+        public <K> void invalidate(K key) {
+            activeCache.invalidate(key);
+        }
+
+        @Override
+        public void clear() {
+            activeCache.clear();
+        }
+
+        @Override
+        public SmartCacheManager.CacheStats getStats() {
+            return activeCache.getStats();
+        }
+
+        /**
+         * Adapt caching strategy based on current performance metrics.
+         */
+        public void adaptStrategy() {
+            SmartCacheManager.CacheStats currentStats = getStats();
+
+            // Decision logic for strategy adaptation
+            if (currentStats.getHitRatio() < 
config.getAdaptiveConfig().getHitRatioThreshold()) {
+                if (requestCount.get() > 
config.getAdaptiveConfig().getSwitchThreshold()) {
+                    // Switch to Trie for better path matching
+                    switchToStrategy("TRIE");
+                } else {
+                    // Switch to Hybrid for balanced performance
+                    switchToStrategy("HYBRID");
+                }
+            }
+
+            lastAdaptation.set(System.currentTimeMillis());
+        }
+
+        private boolean shouldAdapt(long count) {
+            return count % 1000 == 0 && // Check every 1000 requests
+                    System.currentTimeMillis() - lastAdaptation.get() > 
60_000; // At most once per minute
+        }
+
+        private void switchToStrategy(String strategy) {
+            // TODO: Implement Trie and Hybrid cache instances
+            // For now, just log the intention but keep using LRU
+            LOG.info("Strategy adaptation requested to: {}, but implementation 
pending. Keeping LRU.", strategy);
+
+            // When Trie and Hybrid are implemented, uncomment:
+            /*
+            CacheInstance<V> newCache;
+            switch (strategy) {
+                case "TRIE":
+                    newCache = new TrieCacheInstance<>(config);
+                    break;
+                case "HYBRID":
+                    newCache = new HybridCacheInstance<>(config);
+                    break;
+                default:
+                    return; // No change
+            }
+            // TODO: Migrate existing cache entries
+            this.activeCache = newCache;
+            LOG.info("Cache strategy adapted to: {}", strategy);
+            */
+        }
+    }
+
+    // Additional cache implementations would be defined here...
+    // TrieCacheInstance, HybridCacheInstance, etc.
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/HybridCacheInstance.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/HybridCacheInstance.java
new file mode 100644
index 0000000000..51e9553b45
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/HybridCacheInstance.java
@@ -0,0 +1,106 @@
+package org.apache.shenyu.plugin.base.cache;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import reactor.core.publisher.Mono;
+
+import java.time.Duration;
+
+/**
+ * Hybrid cache implementation combining LRU (L1) and Trie (L2) caching.
+ *
+ * This implementation provides two-level caching:
+ * - L1: Fast LRU cache for frequently accessed items
+ * - L2: Trie-based cache for path pattern matching
+ *
+ * TODO: Full implementation planned for Phase 2
+ * Current status: L1 cache operational, L2 planned
+ */
+public class HybridCacheInstance<V> {
+
+    private final SmartCacheConfig.CacheConfig config;
+    private final Cache<Object, V> l1Cache; // Fast LRU cache
+    private final TrieCacheInstance<V> l2Cache; // Trie-based cache
+
+    public HybridCacheInstance(SmartCacheConfig.CacheConfig config) {
+        this.config = config;
+
+        // Initialize L1 cache (LRU)
+        this.l1Cache = Caffeine.newBuilder()
+                .initialCapacity(config.getInitialCapacity() / 10) // L1 is 
10% of total
+                .maximumSize(config.getMaximumSize() / 10)
+                .expireAfterWrite(config.getExpireAfterWrite())
+                .expireAfterAccess(config.getExpireAfterAccess())
+                .recordStats()
+                .build();
+
+        // Initialize L2 cache (Trie)
+        this.l2Cache = new TrieCacheInstance<>(config);
+    }
+
+    /**
+     * Get value from cache with L1/L2 lookup.
+     *
+     * Lookup order:
+     * 1. Check L1 cache (fast)
+     * 2. Check L2 cache (slower but more intelligent)
+     * 3. Load from source
+     */
+    public <K> Mono<V> getOrLoad(K key, Mono<V> loader) {
+        // Try L1 cache first
+        V l1Value = l1Cache.getIfPresent(key);
+        if (l1Value != null) {
+            return Mono.just(l1Value);
+        }
+
+        // Try L2 cache
+        return l2Cache.getOrLoad(key, loader)
+                .doOnNext(value -> {
+                    if (value != null) {
+                        // Promote to L1 cache on access
+                        l1Cache.put(key, value);
+                    }
+                });
+    }
+
+    /**
+     * Put value into both cache levels.
+     */
+    public <K> void put(K key, V value, Duration ttl) {
+        l1Cache.put(key, value);
+        l2Cache.put(key, value, ttl);
+    }
+
+    /**
+     * Invalidate from both cache levels.
+     */
+    public <K> void invalidate(K key) {
+        l1Cache.invalidate(key);
+        l2Cache.invalidate(key);
+    }
+
+    /**
+     * Clear both cache levels.
+     */
+    public void clear() {
+        l1Cache.invalidateAll();
+        l2Cache.clear();
+    }
+
+    /**
+     * Get combined cache statistics.
+     */
+    public SmartCacheManager.CacheStats getStats() {
+        com.github.benmanes.caffeine.cache.stats.CacheStats l1Stats = 
l1Cache.stats();
+        SmartCacheManager.CacheStats l2Stats = l2Cache.getStats();
+
+        // Combine statistics from both levels
+        return new SmartCacheManager.CacheStats(
+                l1Stats.hitCount() + l2Stats.getHitCount(),
+                l1Stats.missCount() + l2Stats.getMissCount(),
+                (long) l1Stats.averageLoadPenalty(),
+                l1Stats.evictionCount() + l2Stats.getEvictionCount(),
+                "HYBRID"
+        );
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/SmartCacheConfig.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/SmartCacheConfig.java
new file mode 100644
index 0000000000..1cb2c0d5e2
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/SmartCacheConfig.java
@@ -0,0 +1,189 @@
+package org.apache.shenyu.plugin.base.cache;
+
+import org.apache.shenyu.common.config.ShenyuConfig;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Smart cache configuration with adaptive strategies.
+ */
+public class SmartCacheConfig {
+
+    private CacheStrategy defaultStrategy = CacheStrategy.ADAPTIVE;
+    private Map<String, CacheConfig> cacheConfigs = new HashMap<>();
+    private AdaptiveConfig adaptiveConfig = new AdaptiveConfig();
+
+    /**
+     * Create configuration from existing ShenyuConfig.
+     */
+    public static SmartCacheConfig fromShenyuConfig(ShenyuConfig shenyuConfig) 
{
+        SmartCacheConfig config = new SmartCacheConfig();
+
+        // Extract selector cache config
+        if (shenyuConfig.getSelectorMatchCache() != null) {
+            CacheConfig selectorConfig = CacheConfig.fromLegacyConfig(
+                shenyuConfig.getSelectorMatchCache(), CacheStrategy.ADAPTIVE);
+            config.cacheConfigs.put("selector_cache", selectorConfig);
+        }
+
+        // Extract rule cache config
+        if (shenyuConfig.getRuleMatchCache() != null) {
+            CacheConfig ruleConfig = CacheConfig.fromLegacyRuleConfig(
+                shenyuConfig.getRuleMatchCache(), CacheStrategy.ADAPTIVE);
+            config.cacheConfigs.put("rule_cache", ruleConfig);
+        }
+
+        return config;
+    }
+
+    /**
+     * Get cache configuration for specific type.
+     */
+    public CacheConfig getCacheConfig(String cacheType) {
+        return cacheConfigs.getOrDefault(cacheType, createDefaultConfig());
+    }
+
+    private CacheConfig createDefaultConfig() {
+        return CacheConfig.builder()
+                .strategy(defaultStrategy)
+                .initialCapacity(10000)
+                .maximumSize(65536)
+                .expireAfterWrite(Duration.ofMinutes(30))
+                .expireAfterAccess(Duration.ofMinutes(10))
+                .build();
+    }
+
+    // Getters and setters
+    public CacheStrategy getDefaultStrategy() { return defaultStrategy; }
+    public AdaptiveConfig getAdaptiveConfig() { return adaptiveConfig; }
+
+    /**
+     * Cache strategy enumeration.
+     */
+    public enum CacheStrategy {
+        LRU_ONLY,    // Pure LRU cache
+        TRIE_ONLY,   // Pure Trie cache for path matching
+        HYBRID,      // L1 (LRU) + L2 (Trie)
+        ADAPTIVE     // Automatically adapt based on performance
+    }
+
+    /**
+     * Individual cache configuration.
+     */
+    public static class CacheConfig {
+        private CacheStrategy strategy;
+        private int initialCapacity;
+        private long maximumSize;
+        private Duration expireAfterWrite;
+        private Duration expireAfterAccess;
+        private AdaptiveConfig adaptiveConfig;
+
+        public static CacheConfig fromLegacyConfig(
+                ShenyuConfig.SelectorMatchCache legacyConfig,
+                CacheStrategy defaultStrategy) {
+
+            return CacheConfig.builder()
+                    .strategy(defaultStrategy)
+                    
.initialCapacity(legacyConfig.getCache().getInitialCapacity())
+                    .maximumSize(legacyConfig.getCache().getMaximumSize())
+                    .expireAfterWrite(Duration.ofMinutes(30))
+                    .expireAfterAccess(Duration.ofMinutes(10))
+                    .build();
+        }
+
+        public static CacheConfig fromLegacyRuleConfig(
+                ShenyuConfig.RuleMatchCache legacyConfig,
+                CacheStrategy defaultStrategy) {
+
+            return CacheConfig.builder()
+                    .strategy(defaultStrategy)
+                    
.initialCapacity(legacyConfig.getCache().getInitialCapacity())
+                    .maximumSize(legacyConfig.getCache().getMaximumSize())
+                    .expireAfterWrite(Duration.ofMinutes(30))
+                    .expireAfterAccess(Duration.ofMinutes(10))
+                    .build();
+        }
+
+        public static Builder builder() {
+            return new Builder();
+        }
+
+        // Builder pattern
+        public static class Builder {
+            private CacheStrategy strategy = CacheStrategy.ADAPTIVE;
+            private int initialCapacity = 10000;
+            private long maximumSize = 65536;
+            private Duration expireAfterWrite = Duration.ofMinutes(30);
+            private Duration expireAfterAccess = Duration.ofMinutes(10);
+
+            public Builder strategy(CacheStrategy strategy) {
+                this.strategy = strategy;
+                return this;
+            }
+
+            public Builder initialCapacity(int initialCapacity) {
+                this.initialCapacity = initialCapacity;
+                return this;
+            }
+
+            public Builder maximumSize(long maximumSize) {
+                this.maximumSize = maximumSize;
+                return this;
+            }
+
+            public Builder expireAfterWrite(Duration expireAfterWrite) {
+                this.expireAfterWrite = expireAfterWrite;
+                return this;
+            }
+
+            public Builder expireAfterAccess(Duration expireAfterAccess) {
+                this.expireAfterAccess = expireAfterAccess;
+                return this;
+            }
+
+            public CacheConfig build() {
+                CacheConfig config = new CacheConfig();
+                config.strategy = this.strategy;
+                config.initialCapacity = this.initialCapacity;
+                config.maximumSize = this.maximumSize;
+                config.expireAfterWrite = this.expireAfterWrite;
+                config.expireAfterAccess = this.expireAfterAccess;
+                config.adaptiveConfig = new AdaptiveConfig();
+                return config;
+            }
+        }
+
+        // Getters
+        public CacheStrategy getStrategy() { return strategy; }
+        public int getInitialCapacity() { return initialCapacity; }
+        public long getMaximumSize() { return maximumSize; }
+        public Duration getExpireAfterWrite() { return expireAfterWrite; }
+        public Duration getExpireAfterAccess() { return expireAfterAccess; }
+        public AdaptiveConfig getAdaptiveConfig() { return adaptiveConfig; }
+    }
+
+    /**
+     * Configuration for adaptive caching behavior.
+     */
+    public static class AdaptiveConfig {
+        private int switchThreshold = 1000;      // Switch to Trie after 1000 
entries
+        private double hitRatioThreshold = 0.8;  // Switch if hit ratio < 80%
+        private Duration evaluationInterval = Duration.ofMinutes(5); // 
Evaluate every 5 minutes
+        private boolean autoOptimization = true; // Enable automatic 
optimization
+
+        // Getters and setters
+        public int getSwitchThreshold() { return switchThreshold; }
+        public void setSwitchThreshold(int switchThreshold) { 
this.switchThreshold = switchThreshold; }
+
+        public double getHitRatioThreshold() { return hitRatioThreshold; }
+        public void setHitRatioThreshold(double hitRatioThreshold) { 
this.hitRatioThreshold = hitRatioThreshold; }
+
+        public Duration getEvaluationInterval() { return evaluationInterval; }
+        public void setEvaluationInterval(Duration evaluationInterval) { 
this.evaluationInterval = evaluationInterval; }
+
+        public boolean isAutoOptimization() { return autoOptimization; }
+        public void setAutoOptimization(boolean autoOptimization) { 
this.autoOptimization = autoOptimization; }
+    }
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/SmartCacheManager.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/SmartCacheManager.java
new file mode 100644
index 0000000000..fcc74bfe50
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/SmartCacheManager.java
@@ -0,0 +1,126 @@
+package org.apache.shenyu.plugin.base.cache;
+
+import reactor.core.publisher.Mono;
+
+import java.time.Duration;
+import java.util.Optional;
+
+/**
+ * Smart cache manager with adaptive strategies.
+ *
+ * This interface provides a unified caching abstraction that can automatically
+ * adapt between different caching strategies based on runtime characteristics.
+ *
+ * Key features:
+ * 1. Adaptive strategy selection (LRU, Trie, Hybrid)
+ * 2. Performance-based strategy switching
+ * 3. Unified interface for different cache types
+ * 4. Built-in metrics and monitoring
+ */
+public interface SmartCacheManager {
+
+    /**
+     * Get value from cache with adaptive strategy.
+     *
+     * @param key cache key
+     * @param loader fallback loader if cache miss
+     * @param <K> key type
+     * @param <V> value type
+     * @return cached or loaded value
+     */
+    <K, V> Mono<V> getOrLoad(String cacheType, K key, Mono<V> loader);
+
+    /**
+     * Put value into cache.
+     *
+     * @param cacheType cache type identifier
+     * @param key cache key
+     * @param value cache value
+     * @param ttl time to live
+     * @param <K> key type
+     * @param <V> value type
+     * @return completion signal
+     */
+    <K, V> Mono<Void> put(String cacheType, K key, V value, Duration ttl);
+
+    /**
+     * Invalidate cache entries.
+     *
+     * @param cacheType cache type identifier
+     * @param key cache key
+     * @param <K> key type
+     * @return completion signal
+     */
+    <K> Mono<Void> invalidate(String cacheType, K key);
+
+    /**
+     * Clear all cache entries for a specific type.
+     *
+     * @param cacheType cache type identifier
+     * @return completion signal
+     */
+    Mono<Void> clear(String cacheType);
+
+    /**
+     * Get cache statistics for monitoring.
+     *
+     * @param cacheType cache type identifier
+     * @return cache statistics
+     */
+    CacheStats getStats(String cacheType);
+
+    /**
+     * Manually trigger strategy adaptation based on current performance.
+     *
+     * @param cacheType cache type identifier
+     * @return completion signal
+     */
+    Mono<Void> adaptStrategy(String cacheType);
+
+    /**
+     * Cache type constants.
+     */
+    interface CacheTypes {
+        String SELECTOR = "selector_cache";
+        String RULE = "rule_cache";
+        String PLUGIN = "plugin_cache";
+        String UPSTREAM = "upstream_cache";
+    }
+
+    /**
+     * Cache statistics for monitoring and adaptation.
+     */
+    class CacheStats {
+        private final long hitCount;
+        private final long missCount;
+        private final long loadTime;
+        private final long evictionCount;
+        private final String strategy;
+        private final double hitRatio;
+
+        public CacheStats(long hitCount, long missCount, long loadTime,
+                         long evictionCount, String strategy) {
+            this.hitCount = hitCount;
+            this.missCount = missCount;
+            this.loadTime = loadTime;
+            this.evictionCount = evictionCount;
+            this.strategy = strategy;
+            this.hitRatio = hitCount + missCount > 0 ?
+                (double) hitCount / (hitCount + missCount) : 0.0;
+        }
+
+        // Getters
+        public long getHitCount() { return hitCount; }
+        public long getMissCount() { return missCount; }
+        public long getLoadTime() { return loadTime; }
+        public long getEvictionCount() { return evictionCount; }
+        public String getStrategy() { return strategy; }
+        public double getHitRatio() { return hitRatio; }
+
+        @Override
+        public String toString() {
+            return String.format("CacheStats{hits=%d, misses=%d, 
hitRatio=%.2f%%, strategy=%s}",
+                    hitCount, missCount, hitRatio * 100, strategy);
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/TrieCacheInstance.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/TrieCacheInstance.java
new file mode 100644
index 0000000000..aa415eb35e
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/TrieCacheInstance.java
@@ -0,0 +1,86 @@
+package org.apache.shenyu.plugin.base.cache;
+
+import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
+import reactor.core.publisher.Mono;
+
+import java.time.Duration;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Trie-based cache implementation for efficient path matching.
+ *
+ * This cache uses a Trie (prefix tree) data structure for fast path-based 
lookups,
+ * particularly useful for URL pattern matching in selectors and rules.
+ *
+ * TODO: Full implementation planned for Phase 2
+ * Current status: Basic implementation with fallback to map-based storage
+ */
+public class TrieCacheInstance<V> {
+
+    private final SmartCacheConfig.CacheConfig config;
+    private final ShenyuTrie trie;
+    private final ConcurrentHashMap<Object, V> fallbackMap;
+
+    public TrieCacheInstance(SmartCacheConfig.CacheConfig config) {
+        this.config = config;
+        this.trie = new ShenyuTrie(config.getMaximumSize(), "antPathMatch");
+        this.fallbackMap = new ConcurrentHashMap<>();
+    }
+
+    /**
+     * Get value from cache or load from provider.
+     *
+     * @param key cache key
+     * @param loader fallback loader
+     * @return cached or loaded value
+     */
+    public <K> Mono<V> getOrLoad(K key, Mono<V> loader) {
+        // TODO: Implement Trie-based lookup for path keys
+        // For now, use fallback map
+        V cachedValue = fallbackMap.get(key);
+        if (cachedValue != null) {
+            return Mono.just(cachedValue);
+        }
+
+        return loader.doOnNext(value -> {
+            if (value != null) {
+                fallbackMap.put(key, value);
+                // TODO: Insert into Trie if key is a path string
+            }
+        });
+    }
+
+    /**
+     * Put value into cache.
+     */
+    public <K> void put(K key, V value, Duration ttl) {
+        fallbackMap.put(key, value);
+        // TODO: Insert into Trie structure
+    }
+
+    /**
+     * Invalidate cache entry.
+     */
+    public <K> void invalidate(K key) {
+        fallbackMap.remove(key);
+        // TODO: Remove from Trie structure
+    }
+
+    /**
+     * Clear all cache entries.
+     */
+    public void clear() {
+        fallbackMap.clear();
+        // TODO: Clear Trie structure
+    }
+
+    /**
+     * Get cache statistics.
+     */
+    public SmartCacheManager.CacheStats getStats() {
+        // TODO: Implement proper statistics collection
+        return new SmartCacheManager.CacheStats(
+                0, 0, 0, 0, "TRIE_ONLY"
+        );
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/config/PluginBaseAutoConfiguration.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/config/PluginBaseAutoConfiguration.java
new file mode 100644
index 0000000000..bc27f431c7
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/config/PluginBaseAutoConfiguration.java
@@ -0,0 +1,104 @@
+package org.apache.shenyu.plugin.base.config;
+
+import org.apache.shenyu.common.config.ShenyuConfig;
+import org.apache.shenyu.plugin.base.cache.DefaultSmartCacheManager;
+import org.apache.shenyu.plugin.base.cache.SmartCacheManager;
+import org.apache.shenyu.plugin.base.metrics.MetricsHelper;
+import org.apache.shenyu.plugin.base.metrics.NoOpMetricsHelper;
+import org.apache.shenyu.plugin.base.route.DefaultRouteResolver;
+import org.apache.shenyu.plugin.base.route.RouteResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Configuration for enhanced plugin base components.
+ *
+ * This configuration registers all required beans for the
+ * enhanced plugin architecture.
+ */
+@Configuration
+public class PluginBaseAutoConfiguration {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(PluginBaseAutoConfiguration.class);
+
+    /**
+     * Create SmartCacheManager bean.
+     *
+     * @param shenyuConfig ShenYu configuration
+     * @return SmartCacheManager instance
+     */
+    @Bean
+    public SmartCacheManager smartCacheManager(ShenyuConfig shenyuConfig) {
+        LOG.info("Initializing SmartCacheManager with enhanced caching");
+        return new DefaultSmartCacheManager(shenyuConfig);
+    }
+
+    /**
+     * Create RouteResolver bean.
+     *
+     * @param cacheManager SmartCacheManager instance
+     * @return RouteResolver instance
+     */
+    @Bean
+    public RouteResolver routeResolver(SmartCacheManager cacheManager) {
+        LOG.info("Initializing DefaultRouteResolver with SmartCacheManager");
+        return new DefaultRouteResolver(cacheManager);
+    }
+
+    /**
+     * Create MetricsHelper bean (no-op implementation by default).
+     *
+     * Override this bean to provide custom metrics implementation.
+     *
+     * @return MetricsHelper instance
+     */
+    @Bean
+    public MetricsHelper metricsHelper() {
+        LOG.info("Initializing NoOpMetricsHelper (override to enable 
metrics)");
+        return new NoOpMetricsHelper();
+    }
+
+    /**
+     * Log cache configuration on startup.
+     */
+    @Bean
+    public CacheConfigLogger cacheConfigLogger(ShenyuConfig shenyuConfig) {
+        return new CacheConfigLogger(shenyuConfig);
+    }
+
+    /**
+     * Logger for cache configuration details.
+     */
+    static class CacheConfigLogger {
+
+        private static final Logger LOG = 
LoggerFactory.getLogger(CacheConfigLogger.class);
+
+        public CacheConfigLogger(ShenyuConfig shenyuConfig) {
+            logCacheConfiguration(shenyuConfig);
+        }
+
+        private void logCacheConfiguration(ShenyuConfig shenyuConfig) {
+            LOG.info("=== Enhanced Plugin Base Configuration ===");
+
+            if (shenyuConfig.getSelectorMatchCache() != null) {
+                LOG.info("Selector Cache:");
+                LOG.info("  - Initial Capacity: {}",
+                        
shenyuConfig.getSelectorMatchCache().getCache().getInitialCapacity());
+                LOG.info("  - Maximum Size: {}",
+                        
shenyuConfig.getSelectorMatchCache().getCache().getMaximumSize());
+            }
+
+            if (shenyuConfig.getRuleMatchCache() != null) {
+                LOG.info("Rule Cache:");
+                LOG.info("  - Initial Capacity: {}",
+                        
shenyuConfig.getRuleMatchCache().getCache().getInitialCapacity());
+                LOG.info("  - Maximum Size: {}",
+                        
shenyuConfig.getRuleMatchCache().getCache().getMaximumSize());
+            }
+
+            LOG.info("==========================================");
+        }
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/context/PluginExecutionContext.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/context/PluginExecutionContext.java
new file mode 100644
index 0000000000..417a159b41
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/context/PluginExecutionContext.java
@@ -0,0 +1,174 @@
+package org.apache.shenyu.plugin.base.context;
+
+import org.springframework.web.server.ServerWebExchange;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Plugin execution context containing all information needed for plugin 
execution.
+ *
+ * This class encapsulates request information and execution state to avoid
+ * repeated parsing and provide a clean interface for plugins.
+ */
+public final class PluginExecutionContext {
+
+    private final ServerWebExchange exchange;
+    private final String requestPath;
+    private final String method;
+    private final Map<String, String> headers;
+    private final Map<String, Object> attributes;
+    private final long startTime;
+
+    private PluginExecutionContext(Builder builder) {
+        this.exchange = builder.exchange;
+        this.requestPath = builder.requestPath;
+        this.method = builder.method;
+        this.headers = Map.copyOf(builder.headers);
+        this.attributes = new ConcurrentHashMap<>(builder.attributes);
+        this.startTime = System.currentTimeMillis();
+    }
+
+    /**
+     * Create context from ServerWebExchange.
+     */
+    public static PluginExecutionContext fromExchange(ServerWebExchange 
exchange) {
+        return builder()
+                .exchange(exchange)
+                .requestPath(extractPath(exchange))
+                .method(exchange.getRequest().getMethod().name())
+                .headers(extractHeaders(exchange))
+                .build();
+    }
+
+    /**
+     * Get the original ServerWebExchange.
+     */
+    public ServerWebExchange getExchange() {
+        return exchange;
+    }
+
+    /**
+     * Get the request path (URI raw path).
+     */
+    public String getRequestPath() {
+        return requestPath;
+    }
+
+    /**
+     * Get HTTP method.
+     */
+    public String getMethod() {
+        return method;
+    }
+
+    /**
+     * Get request headers.
+     */
+    public Map<String, String> getHeaders() {
+        return headers;
+    }
+
+    /**
+     * Get a specific header value.
+     */
+    public Optional<String> getHeader(String name) {
+        return Optional.ofNullable(headers.get(name.toLowerCase()));
+    }
+
+    /**
+     * Get context attributes.
+     */
+    public Map<String, Object> getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Set context attribute.
+     */
+    public void setAttribute(String key, Object value) {
+        attributes.put(key, value);
+    }
+
+    /**
+     * Get context attribute.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> Optional<T> getAttribute(String key) {
+        return Optional.ofNullable((T) attributes.get(key));
+    }
+
+    /**
+     * Get execution start time.
+     */
+    public long getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * Calculate elapsed time in milliseconds.
+     */
+    public long getElapsedTime() {
+        return System.currentTimeMillis() - startTime;
+    }
+
+    // Helper methods
+    private static String extractPath(ServerWebExchange exchange) {
+        URI uri = exchange.getRequest().getURI();
+        return uri.getRawPath();
+    }
+
+    private static Map<String, String> extractHeaders(ServerWebExchange 
exchange) {
+        Map<String, String> headerMap = new ConcurrentHashMap<>();
+        exchange.getRequest().getHeaders().forEach((name, values) -> {
+            if (!values.isEmpty()) {
+                headerMap.put(name.toLowerCase(), values.get(0));
+            }
+        });
+        return headerMap;
+    }
+
+    // Builder pattern
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static final class Builder {
+        private ServerWebExchange exchange;
+        private String requestPath;
+        private String method;
+        private Map<String, String> headers = new ConcurrentHashMap<>();
+        private Map<String, Object> attributes = new ConcurrentHashMap<>();
+
+        public Builder exchange(ServerWebExchange exchange) {
+            this.exchange = exchange;
+            return this;
+        }
+
+        public Builder requestPath(String requestPath) {
+            this.requestPath = requestPath;
+            return this;
+        }
+
+        public Builder method(String method) {
+            this.method = method;
+            return this;
+        }
+
+        public Builder headers(Map<String, String> headers) {
+            this.headers.putAll(headers);
+            return this;
+        }
+
+        public Builder attribute(String key, Object value) {
+            this.attributes.put(key, value);
+            return this;
+        }
+
+        public PluginExecutionContext build() {
+            return new PluginExecutionContext(this);
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/metrics/MetricsHelper.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/metrics/MetricsHelper.java
new file mode 100644
index 0000000000..738d4b53ec
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/metrics/MetricsHelper.java
@@ -0,0 +1,98 @@
+package org.apache.shenyu.plugin.base.metrics;
+
+import org.apache.shenyu.plugin.base.route.RouteResult;
+
+/**
+ * Metrics helper for collecting plugin execution statistics.
+ *
+ * This component provides a unified interface for collecting performance
+ * and operational metrics from plugin executions.
+ */
+public interface MetricsHelper {
+
+    /**
+     * Record plugin execution time.
+     *
+     * @param pluginName name of the plugin
+     * @param durationNanos execution time in nanoseconds
+     */
+    void recordExecutionTime(String pluginName, long durationNanos);
+
+    /**
+     * Record successful plugin execution.
+     *
+     * @param pluginName name of the plugin
+     */
+    void recordSuccess(String pluginName);
+
+    /**
+     * Record plugin execution error.
+     *
+     * @param pluginName name of the plugin
+     * @param error the error that occurred
+     */
+    void recordError(String pluginName, Throwable error);
+
+    /**
+     * Record route matching result.
+     *
+     * @param pluginName name of the plugin
+     * @param matchType type of match (cache hit, trie match, etc.)
+     */
+    void recordRouteMatch(String pluginName, RouteResult.MatchType matchType);
+
+    /**
+     * Record cache operation metrics.
+     *
+     * @param cacheType type of cache (selector, rule, etc.)
+     * @param operation operation type (hit, miss, put, etc.)
+     */
+    void recordCacheOperation(String cacheType, String operation);
+
+    /**
+     * Get current metrics snapshot for a plugin.
+     *
+     * @param pluginName name of the plugin
+     * @return metrics snapshot
+     */
+    PluginMetrics getPluginMetrics(String pluginName);
+
+    /**
+     * Plugin metrics data structure.
+     */
+    class PluginMetrics {
+        private final String pluginName;
+        private final long totalExecutions;
+        private final long successfulExecutions;
+        private final long failedExecutions;
+        private final double averageExecutionTime;
+        private final double successRate;
+
+        public PluginMetrics(String pluginName, long totalExecutions,
+                           long successfulExecutions, long failedExecutions,
+                           double averageExecutionTime) {
+            this.pluginName = pluginName;
+            this.totalExecutions = totalExecutions;
+            this.successfulExecutions = successfulExecutions;
+            this.failedExecutions = failedExecutions;
+            this.averageExecutionTime = averageExecutionTime;
+            this.successRate = totalExecutions > 0 ?
+                (double) successfulExecutions / totalExecutions : 0.0;
+        }
+
+        // Getters
+        public String getPluginName() { return pluginName; }
+        public long getTotalExecutions() { return totalExecutions; }
+        public long getSuccessfulExecutions() { return successfulExecutions; }
+        public long getFailedExecutions() { return failedExecutions; }
+        public double getAverageExecutionTime() { return averageExecutionTime; 
}
+        public double getSuccessRate() { return successRate; }
+
+        @Override
+        public String toString() {
+            return String.format("PluginMetrics{plugin=%s, executions=%d, " +
+                            "successRate=%.2f%%, avgTime=%.2fms}",
+                    pluginName, totalExecutions, successRate * 100, 
averageExecutionTime / 1_000_000.0);
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/metrics/NoOpMetricsHelper.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/metrics/NoOpMetricsHelper.java
new file mode 100644
index 0000000000..d083c67aac
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/metrics/NoOpMetricsHelper.java
@@ -0,0 +1,42 @@
+package org.apache.shenyu.plugin.base.metrics;
+
+import org.apache.shenyu.plugin.base.route.RouteResult;
+
+/**
+ * No-op implementation of MetricsHelper.
+ *
+ * This implementation is used when metrics collection is disabled.
+ * All methods are no-ops and have minimal overhead.
+ */
+public class NoOpMetricsHelper implements MetricsHelper {
+
+    @Override
+    public void recordExecutionTime(String pluginName, long durationNanos) {
+        // No-op
+    }
+
+    @Override
+    public void recordSuccess(String pluginName) {
+        // No-op
+    }
+
+    @Override
+    public void recordError(String pluginName, Throwable error) {
+        // No-op
+    }
+
+    @Override
+    public void recordRouteMatch(String pluginName, RouteResult.MatchType 
matchType) {
+        // No-op
+    }
+
+    @Override
+    public void recordCacheOperation(String cacheType, String operation) {
+        // No-op
+    }
+
+    @Override
+    public PluginMetrics getPluginMetrics(String pluginName) {
+        return new PluginMetrics(pluginName, 0, 0, 0, 0.0);
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/DefaultRouteResolver.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/DefaultRouteResolver.java
new file mode 100644
index 0000000000..06e67792e3
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/DefaultRouteResolver.java
@@ -0,0 +1,199 @@
+package org.apache.shenyu.plugin.base.route;
+
+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.SelectorTypeEnum;
+import org.apache.shenyu.plugin.base.cache.BaseDataCache;
+import org.apache.shenyu.plugin.base.cache.SmartCacheManager;
+import org.apache.shenyu.plugin.base.condition.strategy.MatchStrategyFactory;
+import org.apache.shenyu.plugin.base.context.PluginExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * Default implementation of RouteResolver.
+ *
+ * This implementation provides caching-aware route resolution with support 
for:
+ * - Smart caching of selector and rule matching results
+ * - Conditional matching based on request attributes
+ * - Full compatibility with existing ShenYu matching logic
+ */
+@Component
+public class DefaultRouteResolver implements RouteResolver {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(DefaultRouteResolver.class);
+
+    private final SmartCacheManager cacheManager;
+
+    public DefaultRouteResolver(SmartCacheManager cacheManager) {
+        this.cacheManager = cacheManager;
+    }
+
+    @Override
+    public Mono<Optional<SelectorData>> matchSelector(
+            PluginExecutionContext context,
+            List<SelectorData> selectors) {
+
+        if (selectors == null || selectors.isEmpty()) {
+            return Mono.just(Optional.empty());
+        }
+
+        // Try cache first
+        String cacheKey = buildSelectorCacheKey(context);
+
+        return cacheManager.getOrLoad(
+                SmartCacheManager.CacheTypes.SELECTOR,
+                cacheKey,
+                Mono.fromCallable(() -> performSelectorMatch(context, 
selectors))
+        ).map(Optional::ofNullable);
+    }
+
+    @Override
+    public Mono<Optional<RuleData>> matchRule(
+            PluginExecutionContext context,
+            SelectorData selector,
+            List<RuleData> rules) {
+
+        if (selector == null || rules == null || rules.isEmpty()) {
+            return Mono.just(Optional.empty());
+        }
+
+        // Try cache first
+        String cacheKey = buildRuleCacheKey(context, selector);
+
+        return cacheManager.getOrLoad(
+                SmartCacheManager.CacheTypes.RULE,
+                cacheKey,
+                Mono.fromCallable(() -> performRuleMatch(context, rules))
+        ).map(Optional::ofNullable);
+    }
+
+    @Override
+    public Mono<Boolean> isPluginApplicable(PluginExecutionContext context, 
String pluginName) {
+        return Mono.fromCallable(() -> {
+            PluginData pluginData = 
BaseDataCache.getInstance().obtainPluginData(pluginName);
+            return Objects.nonNull(pluginData) && pluginData.getEnabled();
+        });
+    }
+
+    @Override
+    public Mono<RouteResult> resolveRoute(PluginExecutionContext context, 
String pluginName) {
+        return isPluginApplicable(context, pluginName)
+                .filter(applicable -> applicable)
+                .flatMap(applicable -> {
+                    // Get selectors for this plugin
+                    List<SelectorData> selectors = BaseDataCache.getInstance()
+                            .obtainSelectorData(pluginName);
+
+                    return matchSelector(context, selectors)
+                            .flatMap(selectorOpt -> {
+                                if (!selectorOpt.isPresent()) {
+                                    return Mono.just(RouteResult.noMatch());
+                                }
+
+                                SelectorData selector = selectorOpt.get();
+
+                                // Check if selector continues to rules
+                                if (!selector.getContinued()) {
+                                    return Mono.just(RouteResult.selectorOnly(
+                                            selector, 
RouteResult.MatchType.CACHE_HIT));
+                                }
+
+                                // Get and match rules
+                                List<RuleData> rules = 
BaseDataCache.getInstance()
+                                        .obtainRuleData(selector.getId());
+
+                                return matchRule(context, selector, rules)
+                                        .map(ruleOpt -> {
+                                            if (ruleOpt.isPresent()) {
+                                                return RouteResult.success(
+                                                        selector,
+                                                        ruleOpt.get(),
+                                                        
RouteResult.MatchType.CACHE_HIT
+                                                );
+                                            }
+                                            return RouteResult.selectorOnly(
+                                                    selector, 
RouteResult.MatchType.CACHE_HIT);
+                                        });
+                            });
+                })
+                .defaultIfEmpty(RouteResult.noMatch());
+    }
+
+    /**
+     * Perform actual selector matching logic.
+     */
+    private SelectorData performSelectorMatch(PluginExecutionContext context, 
List<SelectorData> selectors) {
+        for (SelectorData selector : selectors) {
+            if (selector.getEnabled() && matchSelector(context, selector)) {
+                LOG.debug("Matched selector: {}", selector.getName());
+                return selector;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Perform actual rule matching logic.
+     */
+    private RuleData performRuleMatch(PluginExecutionContext context, 
List<RuleData> rules) {
+        for (RuleData rule : rules) {
+            if (rule.getEnabled() && matchRule(context, rule)) {
+                LOG.debug("Matched rule: {}", rule.getName());
+                return rule;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Match selector against context.
+     */
+    private boolean matchSelector(PluginExecutionContext context, SelectorData 
selector) {
+        if (selector.getConditionList() == null || 
selector.getConditionList().isEmpty()) {
+            return true;
+        }
+        return MatchStrategyFactory.match(
+                selector.getMatchMode(),
+                selector.getConditionList(),
+                context.getExchange()
+        );
+    }
+
+    /**
+     * Match rule against context.
+     */
+    private boolean matchRule(PluginExecutionContext context, RuleData rule) {
+        if (rule.getConditionDataList() == null || 
rule.getConditionDataList().isEmpty()) {
+            return true;
+        }
+        return MatchStrategyFactory.match(
+                rule.getMatchMode(),
+                rule.getConditionDataList(),
+                context.getExchange()
+        );
+    }
+
+    /**
+     * Build cache key for selector matching.
+     */
+    private String buildSelectorCacheKey(PluginExecutionContext context) {
+        return context.getRequestPath() + ":" + context.getMethod();
+    }
+
+    /**
+     * Build cache key for rule matching.
+     */
+    private String buildRuleCacheKey(PluginExecutionContext context, 
SelectorData selector) {
+        return selector.getId() + ":" + context.getRequestPath() + ":" + 
context.getMethod();
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/RouteResolver.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/RouteResolver.java
new file mode 100644
index 0000000000..064b35330a
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/RouteResolver.java
@@ -0,0 +1,66 @@
+package org.apache.shenyu.plugin.base.route;
+
+import org.apache.shenyu.common.dto.RuleData;
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.plugin.base.context.PluginExecutionContext;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Route resolver interface for selector and rule matching.
+ *
+ * This component is responsible for all routing logic that was previously
+ * embedded in AbstractShenyuPlugin.execute() method.
+ */
+public interface RouteResolver {
+
+    /**
+     * Match selector for the given context.
+     *
+     * @param context plugin execution context containing request information
+     * @param selectors available selectors for the plugin
+     * @return matched selector wrapped in Optional
+     */
+    Mono<Optional<SelectorData>> matchSelector(
+            PluginExecutionContext context,
+            List<SelectorData> selectors);
+
+    /**
+     * Match rule for the given context and selector.
+     *
+     * @param context plugin execution context
+     * @param selector matched selector
+     * @param rules available rules for the selector
+     * @return matched rule wrapped in Optional
+     */
+    Mono<Optional<RuleData>> matchRule(
+            PluginExecutionContext context,
+            SelectorData selector,
+            List<RuleData> rules);
+
+    /**
+     * Check if the plugin is applicable for the current request.
+     *
+     * @param context plugin execution context
+     * @param pluginName name of the plugin
+     * @return true if plugin should be executed
+     */
+    Mono<Boolean> isPluginApplicable(
+            PluginExecutionContext context,
+            String pluginName);
+
+    /**
+     * Resolve complete routing information for plugin execution.
+     *
+     * This method combines selector and rule matching logic.
+     *
+     * @param context plugin execution context
+     * @param pluginName name of the plugin
+     * @return routing result containing selector and rule data
+     */
+    Mono<RouteResult> resolveRoute(
+            PluginExecutionContext context,
+            String pluginName);
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/RouteResult.java
 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/RouteResult.java
new file mode 100644
index 0000000000..11d6fcbe55
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/route/RouteResult.java
@@ -0,0 +1,95 @@
+package org.apache.shenyu.plugin.base.route;
+
+import org.apache.shenyu.common.dto.RuleData;
+import org.apache.shenyu.common.dto.SelectorData;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Route resolution result containing matched selector and rule data.
+ */
+public final class RouteResult {
+
+    private final SelectorData selector;
+    private final RuleData rule;
+    private final boolean matched;
+    private final MatchType matchType;
+
+    private RouteResult(SelectorData selector, RuleData rule, boolean matched, 
MatchType matchType) {
+        this.selector = selector;
+        this.rule = rule;
+        this.matched = matched;
+        this.matchType = matchType;
+    }
+
+    /**
+     * Create a successful route result.
+     */
+    public static RouteResult success(SelectorData selector, RuleData rule, 
MatchType matchType) {
+        return new RouteResult(
+                Objects.requireNonNull(selector, "Selector cannot be null"),
+                Objects.requireNonNull(rule, "Rule cannot be null"),
+                true,
+                matchType);
+    }
+
+    /**
+     * Create a no-match route result.
+     */
+    public static RouteResult noMatch() {
+        return new RouteResult(null, null, false, MatchType.NONE);
+    }
+
+    /**
+     * Create a selector-only match result (for continued = false scenarios).
+     */
+    public static RouteResult selectorOnly(SelectorData selector, MatchType 
matchType) {
+        return new RouteResult(
+                Objects.requireNonNull(selector, "Selector cannot be null"),
+                null,
+                true,
+                matchType);
+    }
+
+    // Getters
+    public Optional<SelectorData> getSelector() {
+        return Optional.ofNullable(selector);
+    }
+
+    public Optional<RuleData> getRule() {
+        return Optional.ofNullable(rule);
+    }
+
+    public boolean isMatched() {
+        return matched;
+    }
+
+    public MatchType getMatchType() {
+        return matchType;
+    }
+
+    public boolean hasRule() {
+        return rule != null;
+    }
+
+    public boolean hasSelector() {
+        return selector != null;
+    }
+
+    /**
+     * Match type indicating how the route was resolved.
+     */
+    public enum MatchType {
+        CACHE_HIT,      // Matched from L1 cache
+        TRIE_MATCH,     // Matched from L2 Trie cache
+        DEFAULT_MATCH,  // Matched using default strategy
+        NONE           // No match found
+    }
+
+    @Override
+    public String toString() {
+        return String.format("RouteResult{matched=%s, matchType=%s, 
hasSelector=%s, hasRule=%s}",
+                matched, matchType, hasSelector(), hasRule());
+    }
+}
\ No newline at end of file
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/main/resources/META-INF/spring.factories 
b/shenyu-plugin/shenyu-plugin-base/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000000..f25f9e2fc2
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.shenyu.plugin.base.config.PluginBaseAutoConfiguration
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/context/PluginExecutionContextTest.java
 
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/context/PluginExecutionContextTest.java
new file mode 100644
index 0000000000..4094dd068f
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/context/PluginExecutionContextTest.java
@@ -0,0 +1,166 @@
+package org.apache.shenyu.plugin.base.context;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.server.ServerWebExchange;
+
+import java.net.URI;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test for PluginExecutionContext.
+ */
+@ExtendWith(MockitoExtension.class)
+class PluginExecutionContextTest {
+
+    @Mock
+    private ServerWebExchange exchange;
+
+    @Mock
+    private ServerHttpRequest request;
+
+    @BeforeEach
+    void setUp() {
+        when(exchange.getRequest()).thenReturn(request);
+    }
+
+    @Test
+    void testFromExchange() {
+        // Given
+        URI uri = URI.create("http://localhost:8080/api/users";);
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Content-Type", "application/json");
+        headers.add("Authorization", "Bearer token123");
+
+        when(request.getURI()).thenReturn(uri);
+        when(request.getMethod()).thenReturn(HttpMethod.POST);
+        when(request.getHeaders()).thenReturn(headers);
+
+        // When
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+
+        // Then
+        assertNotNull(context);
+        assertEquals("/api/users", context.getRequestPath());
+        assertEquals("POST", context.getMethod());
+        assertEquals(exchange, context.getExchange());
+    }
+
+    @Test
+    void testGetHeader() {
+        // Given
+        URI uri = URI.create("http://localhost:8080/api/users";);
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Content-Type", "application/json");
+        headers.add("X-Custom-Header", "custom-value");
+
+        when(request.getURI()).thenReturn(uri);
+        when(request.getMethod()).thenReturn(HttpMethod.GET);
+        when(request.getHeaders()).thenReturn(headers);
+
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+
+        // When & Then
+        assertTrue(context.getHeader("content-type").isPresent());
+        assertEquals("application/json", 
context.getHeader("content-type").get());
+
+        assertTrue(context.getHeader("x-custom-header").isPresent());
+        assertEquals("custom-value", 
context.getHeader("x-custom-header").get());
+
+        assertFalse(context.getHeader("non-existent").isPresent());
+    }
+
+    @Test
+    void testAttributes() {
+        // Given
+        URI uri = URI.create("http://localhost:8080/test";);
+        when(request.getURI()).thenReturn(uri);
+        when(request.getMethod()).thenReturn(HttpMethod.GET);
+        when(request.getHeaders()).thenReturn(new HttpHeaders());
+
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+
+        // When
+        context.setAttribute("key1", "value1");
+        context.setAttribute("key2", 123);
+
+        // Then
+        assertTrue(context.getAttribute("key1").isPresent());
+        assertEquals("value1", context.getAttribute("key1").get());
+
+        assertTrue(context.getAttribute("key2").isPresent());
+        assertEquals(123, context.getAttribute("key2").get());
+
+        assertFalse(context.getAttribute("non-existent").isPresent());
+    }
+
+    @Test
+    void testElapsedTime() throws InterruptedException {
+        // Given
+        URI uri = URI.create("http://localhost:8080/test";);
+        when(request.getURI()).thenReturn(uri);
+        when(request.getMethod()).thenReturn(HttpMethod.GET);
+        when(request.getHeaders()).thenReturn(new HttpHeaders());
+
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+
+        // When
+        Thread.sleep(10); // Wait a bit
+        long elapsed = context.getElapsedTime();
+
+        // Then
+        assertTrue(elapsed >= 10, "Elapsed time should be at least 10ms");
+        assertTrue(context.getStartTime() > 0);
+    }
+
+    @Test
+    void testBuilder() {
+        // Given
+        URI uri = URI.create("http://localhost:8080/api/test";);
+        when(request.getURI()).thenReturn(uri);
+        when(request.getMethod()).thenReturn(HttpMethod.PUT);
+        when(request.getHeaders()).thenReturn(new HttpHeaders());
+
+        // When
+        PluginExecutionContext context = PluginExecutionContext.builder()
+                .exchange(exchange)
+                .requestPath("/api/test")
+                .method("PUT")
+                .attribute("custom", "value")
+                .build();
+
+        // Then
+        assertNotNull(context);
+        assertEquals("/api/test", context.getRequestPath());
+        assertEquals("PUT", context.getMethod());
+        assertTrue(context.getAttribute("custom").isPresent());
+        assertEquals("value", context.getAttribute("custom").get());
+    }
+
+    @Test
+    void testHeadersAreCaseInsensitive() {
+        // Given
+        URI uri = URI.create("http://localhost:8080/test";);
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Content-Type", "application/json");
+
+        when(request.getURI()).thenReturn(uri);
+        when(request.getMethod()).thenReturn(HttpMethod.GET);
+        when(request.getHeaders()).thenReturn(headers);
+
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+
+        // When & Then - headers should be case-insensitive
+        assertTrue(context.getHeader("content-type").isPresent());
+        assertTrue(context.getHeader("Content-Type").isPresent());
+        assertTrue(context.getHeader("CONTENT-TYPE").isPresent());
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/route/DefaultRouteResolverTest.java
 
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/route/DefaultRouteResolverTest.java
new file mode 100644
index 0000000000..98ec0a2de3
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/route/DefaultRouteResolverTest.java
@@ -0,0 +1,226 @@
+package org.apache.shenyu.plugin.base.route;
+
+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.plugin.base.cache.BaseDataCache;
+import org.apache.shenyu.plugin.base.cache.SmartCacheManager;
+import org.apache.shenyu.plugin.base.context.PluginExecutionContext;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test for DefaultRouteResolver.
+ */
+@ExtendWith(MockitoExtension.class)
+class DefaultRouteResolverTest {
+
+    @Mock
+    private SmartCacheManager cacheManager;
+
+    @Mock
+    private ServerWebExchange exchange;
+
+    @Mock
+    private ServerHttpRequest request;
+
+    private DefaultRouteResolver routeResolver;
+
+    @BeforeEach
+    void setUp() {
+        routeResolver = new DefaultRouteResolver(cacheManager);
+
+        // Setup mock exchange
+        when(exchange.getRequest()).thenReturn(request);
+        
when(request.getURI()).thenReturn(URI.create("http://localhost:8080/api/users";));
+        when(request.getMethod()).thenReturn(HttpMethod.GET);
+    }
+
+    @Test
+    void testMatchSelectorFromCache() {
+        // Given
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+        SelectorData cachedSelector = createTestSelector("test-selector", 
true);
+
+        when(cacheManager.getOrLoad(
+                eq(SmartCacheManager.CacheTypes.SELECTOR),
+                anyString(),
+                any(Mono.class)
+        )).thenReturn(Mono.just(cachedSelector));
+
+        // When
+        Mono<Optional<SelectorData>> result = routeResolver.matchSelector(
+                context, Collections.singletonList(cachedSelector));
+
+        // Then
+        StepVerifier.create(result)
+                .assertNext(opt -> {
+                    assertTrue(opt.isPresent());
+                    assertEquals("test-selector", opt.get().getName());
+                })
+                .verifyComplete();
+    }
+
+    @Test
+    void testMatchSelectorNoMatch() {
+        // Given
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+
+        when(cacheManager.getOrLoad(
+                eq(SmartCacheManager.CacheTypes.SELECTOR),
+                anyString(),
+                any(Mono.class)
+        )).thenReturn(Mono.empty());
+
+        // When
+        Mono<Optional<SelectorData>> result = routeResolver.matchSelector(
+                context, Collections.emptyList());
+
+        // Then
+        StepVerifier.create(result)
+                .assertNext(opt -> assertFalse(opt.isPresent()))
+                .verifyComplete();
+    }
+
+    @Test
+    void testMatchRuleFromCache() {
+        // Given
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+        SelectorData selector = createTestSelector("test-selector", true);
+        RuleData cachedRule = createTestRule("test-rule", true);
+
+        when(cacheManager.getOrLoad(
+                eq(SmartCacheManager.CacheTypes.RULE),
+                anyString(),
+                any(Mono.class)
+        )).thenReturn(Mono.just(cachedRule));
+
+        // When
+        Mono<Optional<RuleData>> result = routeResolver.matchRule(
+                context, selector, Collections.singletonList(cachedRule));
+
+        // Then
+        StepVerifier.create(result)
+                .assertNext(opt -> {
+                    assertTrue(opt.isPresent());
+                    assertEquals("test-rule", opt.get().getName());
+                })
+                .verifyComplete();
+    }
+
+    @Test
+    void testResolveRouteSuccess() {
+        // Given
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+        String pluginName = "test-plugin";
+
+        SelectorData selector = createTestSelector("test-selector", true);
+        selector.setContinued(true);
+        RuleData rule = createTestRule("test-rule", true);
+
+        when(cacheManager.getOrLoad(
+                eq(SmartCacheManager.CacheTypes.SELECTOR),
+                anyString(),
+                any(Mono.class)
+        )).thenReturn(Mono.just(selector));
+
+        when(cacheManager.getOrLoad(
+                eq(SmartCacheManager.CacheTypes.RULE),
+                anyString(),
+                any(Mono.class)
+        )).thenReturn(Mono.just(rule));
+
+        // When
+        Mono<RouteResult> result = routeResolver.resolveRoute(context, 
pluginName);
+
+        // Then
+        StepVerifier.create(result)
+                .assertNext(routeResult -> {
+                    assertTrue(routeResult.isMatched());
+                    assertTrue(routeResult.hasSelector());
+                    assertTrue(routeResult.hasRule());
+                })
+                .verifyComplete();
+    }
+
+    @Test
+    void testResolveRouteNoMatch() {
+        // Given
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+        String pluginName = "test-plugin";
+
+        when(cacheManager.getOrLoad(
+                eq(SmartCacheManager.CacheTypes.SELECTOR),
+                anyString(),
+                any(Mono.class)
+        )).thenReturn(Mono.empty());
+
+        // When
+        Mono<RouteResult> result = routeResolver.resolveRoute(context, 
pluginName);
+
+        // Then
+        StepVerifier.create(result)
+                .assertNext(routeResult -> {
+                    assertFalse(routeResult.isMatched());
+                    assertEquals(RouteResult.MatchType.NONE, 
routeResult.getMatchType());
+                })
+                .verifyComplete();
+    }
+
+    @Test
+    void testIsPluginApplicable() {
+        // Given
+        PluginExecutionContext context = 
PluginExecutionContext.fromExchange(exchange);
+        String pluginName = "test-plugin";
+
+        // When & Then
+        Mono<Boolean> result = routeResolver.isPluginApplicable(context, 
pluginName);
+
+        StepVerifier.create(result)
+                .expectNext(false) // BaseDataCache will return null by default
+                .verifyComplete();
+    }
+
+    // Helper methods
+    private SelectorData createTestSelector(String name, boolean enabled) {
+        SelectorData selector = new SelectorData();
+        selector.setId("selector-id-1");
+        selector.setName(name);
+        selector.setEnabled(enabled);
+        selector.setPluginName("test-plugin");
+        selector.setMatchMode(0);
+        selector.setConditionList(new ArrayList<>());
+        selector.setContinued(false);
+        return selector;
+    }
+
+    private RuleData createTestRule(String name, boolean enabled) {
+        RuleData rule = new RuleData();
+        rule.setId("rule-id-1");
+        rule.setName(name);
+        rule.setEnabled(enabled);
+        rule.setPluginName("test-plugin");
+        rule.setMatchMode(0);
+        rule.setConditionDataList(new ArrayList<>());
+        return rule;
+    }
+}


Reply via email to