Integration module providing flow control, traffic shaping, concurrency limiting, circuit breaking and system adaptive overload protection for Spring Cloud Gateway applications
—
System for managing custom API definitions that extend beyond simple route-based resource identification, enabling fine-grained control over resource matching and traffic governance.
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);
}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();
}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);
}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);
}
}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());
}
}@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");
}
}
}
}@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
}
}// 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);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;
}@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);
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-alibaba-csp--sentinel-spring-cloud-gateway-adapter