Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spring-cloud-alibaba-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<module>sentinel-example/sentinel-core-example</module>
<module>sentinel-example/sentinel-openfeign-example</module>
<module>sentinel-example/sentinel-resttemplate-example</module>
<module>sentinel-example/sentinel-restclient-example</module>
<module>sentinel-example/sentinel-circuitbreaker-example</module>
<module>sentinel-example/sentinel-webflux-example</module>
<module>sentinel-example/sentinel-spring-cloud-gateway-example</module>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>


<artifactId>sentinel-restclient-example</artifactId>
<name>Spring Cloud Starter Alibaba Sentinel x RestClient - Example</name>
<description>Example demonstrating how to use sentinel with RestClient</description>
<packaging>jar</packaging>


<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* Demo application for Sentinel RestClient integration.
*
* @author QHT
*/
@SpringBootApplication
public class RestClientApplication {

public static void main(String[] args) {
SpringApplication.run(RestClientApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2013-present the author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples.configuration;

import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;

/**
* Block handler, fallback and url cleaner for RestClient.
*
* @author uuuyuqi
*/
public class RestClientBlockHandler {

private static final Logger log = LoggerFactory.getLogger(RestClientBlockHandler.class);

/**
* Block handler for flow-control.
* When a request is rate-limited, this handler returns a custom response.
*/
public static ClientHttpResponse handleBlock(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution, BlockException ex) {
log.warn("[Customized-RestClientBlockHandler] RestClient blocked by flow control: uri={}, rule={}",
request.getURI(), ex.getRule());
return new SentinelClientHttpResponse(
"[Customized-RestClientBlockHandler] Blocked by flow control: " + ex.getClass().getSimpleName());
}

/**
* Fallback for circuit-breaking (degrade).
* When a downstream service is degraded, this handler returns a fallback response.
*/
public static ClientHttpResponse handleFallback(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution, BlockException ex) {
log.warn("[Customized-RestClientBlockHandler] RestClient degraded (circuit open): uri={}, rule={}",
request.getURI(), ex.getRule());
return new SentinelClientHttpResponse("[Customized-RestClientBlockHandler] Service degraded, please try again later");
}

/**
* URL cleaner to normalize RESTful URLs.
* Prevents resource name explosion for parameterized paths.
*/
public static String cleanUrl(String url) {
// Example: normalize /users/123 to /users/{id}
// In this demo, we return the URL as-is since httpbin.org paths are fixed
return url;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples.configuration;

import com.alibaba.cloud.sentinel.annotation.SentinelRestClient;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;


@Configuration
public class RestClientConfiguration {

@Bean
@SentinelRestClient(
blockHandler = "handleBlock",
blockHandlerClass = RestClientBlockHandler.class,
fallback = "handleFallback",
fallbackClass = RestClientBlockHandler.class,
urlCleaner = "cleanUrl",
urlCleanerClass = RestClientBlockHandler.class
)
public RestClient.Builder restClientBuilder() {
return RestClient.builder();
}

@Bean
public RestClient restClient(@Qualifier("restClientBuilder") RestClient.Builder builder) {
// Use the auto-injected Builder so that the Sentinel interceptor takes effect
return builder.build();
}



@Bean
public RestClient.Builder anotherRestClientBuilder() {
return RestClient.builder();
}

@Bean
public RestClient anotherRestClient(@Qualifier("anotherRestClientBuilder") RestClient.Builder builder) {
// Use the auto-injected Builder so that the Sentinel interceptor takes effect
return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples.configuration;

import java.util.Arrays;

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.Configuration;

/**
* Programmatic Sentinel rule configuration for the RestClient demo.
*
* @author QHT
*/
@Configuration
public class SentinelRulesConfiguration {

private static final Logger log = LoggerFactory.getLogger(SentinelRulesConfiguration.class);

@PostConstruct
public void init() {
log.info("Loading Sentinel rules...");

// Flow rules
FlowRule getRule = new FlowRule("GET:https://httpbin.org/get");
getRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
getRule.setCount(1);
getRule.setLimitApp("default");

FlowRule expRule = new FlowRule("GET:https://httpbin.org/status/500");
expRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
expRule.setCount(1000);
expRule.setLimitApp("default");

FlowRule rtRule = new FlowRule("GET:https://httpbin.org/delay/3");
rtRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rtRule.setCount(1000);
rtRule.setLimitApp("default");

FlowRuleManager.loadRules(Arrays.asList(getRule, expRule, rtRule));

// Degrade rules
DegradeRule degradeRule1 = new DegradeRule("GET:https://httpbin.org/status/500");
degradeRule1.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
degradeRule1.setCount(0.99); // value "1" is not supported now, see: https://github.com/alibaba/Sentinel/pull/1857
degradeRule1.setMinRequestAmount(1);
degradeRule1.setStatIntervalMs(10 * 1000);
degradeRule1.setTimeWindow(30);
degradeRule1.setLimitApp("default");

DegradeRule degradeRule2 = new DegradeRule("GET:https://httpbin.org/delay/3");
degradeRule2.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule2.setCount(2000);
degradeRule1.setStatIntervalMs(10 * 1000);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

degradeRule2.setSlowRatioThreshold(0.1);
degradeRule2.setMinRequestAmount(1);
degradeRule2.setTimeWindow(30);
degradeRule2.setLimitApp("default");

DegradeRuleManager.loadRules(Arrays.asList(degradeRule1, degradeRule2));

log.info("Sentinel rules loaded successfully.");
}

}
Loading
Loading