CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-alibaba-csp--sentinel-spring-cloud-gateway-adapter

Integration module providing flow control, traffic shaping, concurrency limiting, circuit breaking and system adaptive overload protection for Spring Cloud Gateway applications

Pending
Overview
Eval results
Files

api-management.mddocs/

API Definition Management

System for managing custom API definitions that extend beyond simple route-based resource identification, enabling fine-grained control over resource matching and traffic governance.

Capabilities

GatewayApiMatcherManager

Static manager for API definition matchers, providing access to registered API definitions and their corresponding matchers.

/**
 * Manager for API definition matchers
 * Provides static access to API matcher registry
 */
public final class GatewayApiMatcherManager {
    /**
     * Gets unmodifiable map of all API matchers
     * @return Map<String, WebExchangeApiMatcher> - API name to matcher mapping
     */
    public static Map<String, WebExchangeApiMatcher> getApiMatcherMap();
    
    /**
     * Gets specific API matcher by name
     * @param apiName - Name of API definition to retrieve
     * @return Optional<WebExchangeApiMatcher> - Matcher if found, empty otherwise
     */
    public static Optional<WebExchangeApiMatcher> getMatcher(String apiName);
    
    /**
     * Gets set of all registered API definitions
     * @return Set<ApiDefinition> - All registered API definitions
     */
    public static Set<ApiDefinition> getApiDefinitionSet();
    
    /**
     * Loads and registers API definitions (package-private, used internally)
     * @param definitions - Set of API definitions to load
     */
    static synchronized void loadApiDefinitions(Set<ApiDefinition> definitions);
}

WebExchangeApiMatcher

API matcher implementation for Spring WebFlux ServerWebExchange, extending abstract matcher functionality for reactive gateway environments.

/**
 * API matcher implementation for Spring WebFlux ServerWebExchange
 * Extends AbstractApiMatcher<ServerWebExchange> for reactive environments
 */
public class WebExchangeApiMatcher extends AbstractApiMatcher<ServerWebExchange> {
    /**
     * Constructor with API definition
     * @param apiDefinition - API definition to create matcher for
     */
    public WebExchangeApiMatcher(ApiDefinition apiDefinition);
    
    // Inherited from AbstractApiMatcher:
    /**
     * Tests if exchange matches the API definition
     * @param exchange - Server web exchange to test
     * @return boolean - true if exchange matches API definition
     */
    public boolean test(ServerWebExchange exchange);
    
    /**
     * Gets the API name from the definition
     * @return String - API name
     */
    public String getApiName();
    
    /**
     * Gets the underlying API definition
     * @return ApiDefinition - The API definition used by this matcher
     */
    public ApiDefinition getApiDefinition();
}

SpringCloudGatewayApiDefinitionChangeObserver

Observer for API definition changes, integrating with the common adapter's change notification system.

/**
 * Observer for API definition changes in Spring Cloud Gateway environment
 * Implements ApiDefinitionChangeObserver for change notifications
 */
public class SpringCloudGatewayApiDefinitionChangeObserver implements ApiDefinitionChangeObserver {
    /**
     * Default constructor
     */
    public SpringCloudGatewayApiDefinitionChangeObserver();
    
    /**
     * Handles API definition changes by updating matcher registry
     * @param apiDefinitions - New set of API definitions
     */
    public void onChange(Set<ApiDefinition> apiDefinitions);
}

Usage Patterns

API Definition Registration

import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;

@Configuration
public class ApiDefinitionConfiguration {
    
    @PostConstruct
    public void initializeApiDefinitions() {
        Set<ApiDefinition> definitions = new HashSet<>();
        
        // User management API
        ApiDefinition userApi = new ApiDefinition("user-api");
        userApi.setPredicateItems(new HashSet<ApiPathPredicateItem>() {{
            // Exact path match
            add(new ApiPathPredicateItem().setPattern("/api/users")
                .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT));
            // Prefix match for user operations
            add(new ApiPathPredicateItem().setPattern("/api/users/**")
                .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
        }});
        definitions.add(userApi);
        
        // Admin API with regex matching
        ApiDefinition adminApi = new ApiDefinition("admin-api");
        adminApi.setPredicateItems(new HashSet<ApiPathPredicateItem>() {{
            add(new ApiPathPredicateItem().setPattern("/admin/.*")
                .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_REGEX));
        }});
        definitions.add(adminApi);
        
        // Register definitions
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }
}

Custom API Matcher

public class CustomApiMatcher {
    
    public static boolean matchesUserApiWithAuth(ServerWebExchange exchange) {
        Optional<WebExchangeApiMatcher> matcher = GatewayApiMatcherManager.getMatcher("user-api");
        
        if (matcher.isPresent() && matcher.get().test(exchange)) {
            // Additional check for authentication
            String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
            return authHeader != null && authHeader.startsWith("Bearer ");
        }
        
        return false;
    }
    
    public static Set<String> getAllMatchingApis(ServerWebExchange exchange) {
        return GatewayApiMatcherManager.getApiMatcherMap().entrySet().stream()
            .filter(entry -> entry.getValue().test(exchange))
            .map(Map.Entry::getKey)
            .collect(Collectors.toSet());
    }
}

Dynamic API Definition Updates

@Service
public class DynamicApiDefinitionService {
    
    private final SpringCloudGatewayApiDefinitionChangeObserver observer = 
        new SpringCloudGatewayApiDefinitionChangeObserver();
    
    public void updateApiDefinitions(Set<ApiDefinition> newDefinitions) {
        // Validate definitions
        validateApiDefinitions(newDefinitions);
        
        // Update through observer (this updates the matcher registry)
        observer.onChange(newDefinitions);
        
        // Also update the common manager
        GatewayApiDefinitionManager.loadApiDefinitions(newDefinitions);
    }
    
    private void validateApiDefinitions(Set<ApiDefinition> definitions) {
        for (ApiDefinition definition : definitions) {
            if (StringUtil.isBlank(definition.getApiName())) {
                throw new IllegalArgumentException("API name cannot be blank");
            }
            if (definition.getPredicateItems() == null || definition.getPredicateItems().isEmpty()) {
                throw new IllegalArgumentException("API definition must have predicate items");
            }
        }
    }
}

Monitoring API Matches

@Component
public class ApiMatchingMonitor {
    
    public void logApiMatches(ServerWebExchange exchange) {
        String path = exchange.getRequest().getPath().value();
        
        Map<String, WebExchangeApiMatcher> matchers = GatewayApiMatcherManager.getApiMatcherMap();
        
        List<String> matchingApis = matchers.entrySet().stream()
            .filter(entry -> entry.getValue().test(exchange))
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
        
        if (!matchingApis.isEmpty()) {
            log.info("Path {} matched APIs: {}", path, String.join(", ", matchingApis));
        } else {
            log.debug("Path {} matched no custom APIs", path);
        }
    }
    
    public Map<String, Integer> getApiMatchStatistics() {
        // Return statistics about API matching frequency
        return GatewayApiMatcherManager.getApiDefinitionSet().stream()
            .collect(Collectors.toMap(
                ApiDefinition::getApiName,
                def -> getMatchCountForApi(def.getApiName())
            ));
    }
    
    private int getMatchCountForApi(String apiName) {
        // Implementation would track match counts
        return 0; // Placeholder
    }
}

API Definition Patterns

Path-Based API Definitions

// Exact path matching
ApiPathPredicateItem exactPath = new ApiPathPredicateItem()
    .setPattern("/api/health")
    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT);

// Prefix matching (Ant-style)
ApiPathPredicateItem prefixPath = new ApiPathPredicateItem()
    .setPattern("/api/users/**")
    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX);

// Regex matching
ApiPathPredicateItem regexPath = new ApiPathPredicateItem()
    .setPattern("/api/v[0-9]+/.*")
    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_REGEX);

Composite API Definitions

public ApiDefinition createCompositeApiDefinition() {
    ApiDefinition apiDef = new ApiDefinition("composite-api");
    
    Set<ApiPathPredicateItem> predicates = new HashSet<>();
    
    // Multiple path patterns for the same API
    predicates.add(new ApiPathPredicateItem()
        .setPattern("/api/orders/**")
        .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
    
    predicates.add(new ApiPathPredicateItem()
        .setPattern("/api/payments/**")
        .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
    
    predicates.add(new ApiPathPredicateItem()
        .setPattern("/api/checkout")
        .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT));
    
    apiDef.setPredicateItems(predicates);
    return apiDef;
}

Integration with Flow Control

API-Based Flow Rules

@Configuration
public class ApiFlowRuleConfiguration {
    
    @PostConstruct
    public void configureApiFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        
        // Rule for user-api
        FlowRule userApiRule = new FlowRule();
        userApiRule.setResource("user-api");
        userApiRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        userApiRule.setCount(100); // 100 QPS limit
        rules.add(userApiRule);
        
        // Rule for admin-api with stricter limits
        FlowRule adminApiRule = new FlowRule();
        adminApiRule.setResource("admin-api");
        adminApiRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        adminApiRule.setCount(10); // 10 QPS limit
        rules.add(adminApiRule);
        
        FlowRuleManager.loadRules(rules);
    }
}

Error Handling

Matcher Validation

  • API definitions are validated when loaded
  • Invalid patterns or empty API names are rejected
  • Matcher creation failures are logged and skipped

Runtime Safety

  • All matcher operations are null-safe
  • Missing matchers return empty Optional or empty collections
  • Exchange testing handles malformed requests gracefully

Install with Tessl CLI

npx tessl i tessl/maven-com-alibaba-csp--sentinel-spring-cloud-gateway-adapter

docs

api-management.md

block-handling.md

core-integration.md

index.md

request-processing.md

route-matching.md

tile.json