mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
commit
2d842b6c98
@ -13,6 +13,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
|
||||
* **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。
|
||||
* **消息驱动能力**:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
|
||||
* **阿里云对象存储**:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
|
||||
* **分布式任务调度**:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。
|
||||
|
||||
|
||||
更多功能请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
|
||||
@ -29,6 +30,8 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
|
||||
|
||||
**[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
|
||||
|
||||
**[Alibaba Cloud SchedulerX](https://help.aliyun.com/document_detail/43136.html?spm=a2c4g.11186623.6.709.baef7da9QVICiD)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
|
||||
|
||||
更多组件请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
|
||||
|
||||
## 如何构建
|
||||
@ -96,6 +99,8 @@ Example 列表:
|
||||
|
||||
[Alibaba Cloud ACM Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/acm-example/acm-local-example/readme-zh.md)
|
||||
|
||||
[Alibaba Cloud SchedulerX Example](https://github.com/xiaolongzuo/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/readme-zh.md)
|
||||
|
||||
## 版本管理规范
|
||||
项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从0开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用0,即版本号为 0.x.x 的格式。
|
||||
|
||||
|
@ -185,7 +185,7 @@ Sentinel RestTemplate 限流的资源规则提供两种粒度:
|
||||
|
||||
* `schema://host:port`:协议、主机和端口
|
||||
|
||||
NOTE: 以 `https://www.taobao.com/test` 这个 url 为例。对应的资源名有两种粒度,分别是 `https://www.taobao.com:80` 以及 `https://www.taobao.com:80/test`
|
||||
NOTE: 以 `https://www.taobao.com/test` 这个 url 为例。对应的资源名有两种粒度,分别是 `https://www.taobao.com` 以及 `https://www.taobao.com/test`
|
||||
|
||||
### 动态数据源支持
|
||||
|
||||
|
@ -187,7 +187,7 @@ Sentinel RestTemplate provides two granularities for resource rate limiting:
|
||||
|
||||
* `schema://host:port`: Protocol, host and port
|
||||
|
||||
NOTE: Take `https://www.taobao.com/test` as an example. The corresponding resource names have two levels of granularities, `https://www.taobao.com:80` and `https://www.taobao.com:80/test`.
|
||||
NOTE: Take `https://www.taobao.com/test` as an example. The corresponding resource names have two levels of granularities, `https://www.taobao.com` and `https://www.taobao.com/test`.
|
||||
|
||||
### Dynamic Data Source Support
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[[spring-cloud-alibaba-reference]]
|
||||
= Spring Cloud Alibaba Reference Documentation
|
||||
xiaojing; xiaolongzuo; jim fang; bingting peng
|
||||
xiaojing; xiaolongzuo; jim fang; bingting peng; wangyuxin
|
||||
:doctype: book
|
||||
:toc:
|
||||
:toclevels: 4
|
||||
|
@ -122,28 +122,30 @@
|
||||
|
||||
## 自定义限流处理逻辑
|
||||
|
||||
1. URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。
|
||||
* 默认限流异常处理
|
||||
|
||||
URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。
|
||||
如果需要自定义处理逻辑,实现的方式如下:
|
||||
|
||||
```java
|
||||
public class CustomUrlBlockHandler implements UrlBlockHandler {
|
||||
@Override
|
||||
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
|
||||
// todo add your logic
|
||||
}
|
||||
}
|
||||
```java
|
||||
public class CustomUrlBlockHandler implements UrlBlockHandler {
|
||||
@Override
|
||||
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
|
||||
// todo add your logic
|
||||
}
|
||||
}
|
||||
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
```
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
```
|
||||
|
||||
2. 自定义限流触发后,默认的处理逻辑是抛出异常。
|
||||
* 使用 `@SentinelResource` 注解下的限流异常处理
|
||||
|
||||
如果需要自定义处理逻辑,填写 `@SentinelResource` 注解的 `blockHandler` 属性(针对所有类型的 `BlockException`,需自行判断)或 `fallback` 属性(针对熔断降级异常),注意**对应方法的签名和位置有限制**,详情见 [Sentinel 注解支持文档](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81#sentinelresource-%E6%B3%A8%E8%A7%A3)。示例实现如下:
|
||||
|
||||
```java
|
||||
public class TestService {
|
||||
|
||||
// blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制.
|
||||
// blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制.
|
||||
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
|
||||
public void test() {
|
||||
System.out.println("Test");
|
||||
@ -172,7 +174,7 @@ public final class ExceptionUtil {
|
||||
}
|
||||
```
|
||||
|
||||
一个简单的示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。
|
||||
一个简单的 `@SentinelResource` 示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。
|
||||
|
||||
## Endpoint 信息查看
|
||||
|
||||
|
@ -108,7 +108,9 @@ The screenshot belows shows invoke success:
|
||||
|
||||
## Customize Flow Control Logic
|
||||
|
||||
1. When a URL resource is blocked by Sentinel, the default logic is return HTTP response "Blocked by Sentinel (flow limiting)".
|
||||
* Flow control exception handle by default
|
||||
|
||||
When a URL resource is blocked by Sentinel, the default logic is return HTTP response "Blocked by Sentinel (flow limiting)".
|
||||
|
||||
If you want to customize your flow control logic, see the code below:
|
||||
|
||||
@ -123,7 +125,9 @@ The screenshot belows shows invoke success:
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
|
||||
|
||||
2. When a custom resource is blocked by Sentinel, the default logic is throw BlockException.
|
||||
* Flow control exception handle by using `@SentinelResource`
|
||||
|
||||
When a custom resource is blocked by Sentinel, the default logic is throw BlockException.
|
||||
|
||||
If you want to customize your flow control logic, implement interface `SentinelExceptionHandler`, set @SentinelResource's blockHandler() and blockHandlerClass(). See the code below:
|
||||
|
||||
|
@ -1,5 +1,9 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.cloud.alibaba.sentinel.rest.SentinelClientHttpResponse;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
/**
|
||||
@ -7,8 +11,10 @@ import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
public static void handleException(BlockException ex) {
|
||||
public static SentinelClientHttpResponse handleException(HttpRequest request,
|
||||
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
|
||||
System.out.println("Oops: " + ex.getClass().getCanonicalName());
|
||||
return new SentinelClientHttpResponse("custom block info");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,9 +16,9 @@
|
||||
"strategy": 0
|
||||
},
|
||||
{
|
||||
"resource": "abc",
|
||||
"resource": "http://www.taobao.com",
|
||||
"controlBehavior": 0,
|
||||
"count": 1,
|
||||
"count": 0,
|
||||
"grade": 1,
|
||||
"limitApp": "default",
|
||||
"strategy": 0
|
||||
|
@ -33,6 +33,7 @@ import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.Tracer;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
|
||||
@ -58,27 +59,41 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
URI uri = request.getURI();
|
||||
String hostResource = uri.getScheme() + "://" + uri.getHost() + ":"
|
||||
+ (uri.getPort() == -1 ? 80 : uri.getPort());
|
||||
String hostResource = uri.getScheme() + "://" + uri.getHost()
|
||||
+ (uri.getPort() == -1 ? "" : ":" + uri.getPort());
|
||||
String hostWithPathResource = hostResource + uri.getPath();
|
||||
boolean entryWithPath = true;
|
||||
if (hostResource.equals(hostWithPathResource)) {
|
||||
entryWithPath = false;
|
||||
}
|
||||
Entry hostEntry = null, hostWithPathEntry = null;
|
||||
ClientHttpResponse response;
|
||||
try {
|
||||
ContextUtil.enter(hostWithPathResource);
|
||||
hostWithPathEntry = SphU.entry(hostWithPathResource);
|
||||
if (entryWithPath) {
|
||||
hostWithPathEntry = SphU.entry(hostWithPathResource);
|
||||
}
|
||||
hostEntry = SphU.entry(hostResource);
|
||||
response = execution.execute(request, body);
|
||||
}
|
||||
catch (BlockException e) {
|
||||
try {
|
||||
return handleBlockException(request, body, execution, e);
|
||||
catch (Throwable e) {
|
||||
if (!BlockException.isBlockException(e)) {
|
||||
Tracer.trace(e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof IllegalStateException) {
|
||||
throw (IllegalStateException) ex;
|
||||
else {
|
||||
try {
|
||||
return handleBlockException(request, body, execution,
|
||||
(BlockException) e);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof IllegalStateException) {
|
||||
throw (IllegalStateException) ex;
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"sentinel handle BlockException error: " + ex.getMessage(),
|
||||
ex);
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"sentinel handle BlockException error: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -25,11 +25,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository;
|
||||
import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource;
|
||||
import org.springframework.cloud.alicloud.context.acm.AcmIntegrationProperties;
|
||||
import org.springframework.cloud.context.refresh.ContextRefresher;
|
||||
import org.springframework.cloud.endpoint.event.RefreshEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ -43,7 +46,8 @@ import com.alibaba.edas.acm.listener.ConfigChangeListener;
|
||||
*
|
||||
* @author juven.xuxb, 5/13/16.
|
||||
*/
|
||||
public class AcmContextRefresher implements ApplicationListener<ApplicationReadyEvent> {
|
||||
public class AcmContextRefresher
|
||||
implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(AcmContextRefresher.class);
|
||||
|
||||
@ -53,6 +57,8 @@ public class AcmContextRefresher implements ApplicationListener<ApplicationReady
|
||||
|
||||
private final AcmRefreshHistory refreshHistory;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private final AcmPropertySourceRepository acmPropertySourceRepository;
|
||||
|
||||
private Map<String, ConfigChangeListener> listenerMap = new ConcurrentHashMap<>(16);
|
||||
@ -74,19 +80,10 @@ public class AcmContextRefresher implements ApplicationListener<ApplicationReady
|
||||
|
||||
private void registerDiamondListenersForApplications() {
|
||||
if (acmIntegrationProperties.getAcmProperties().isRefreshEnabled()) {
|
||||
for (AcmPropertySource acmPropertySource : acmPropertySourceRepository
|
||||
.getAll()) {
|
||||
if (acmPropertySource.isGroupLevel()) {
|
||||
continue;
|
||||
}
|
||||
String dataId = acmPropertySource.getDataId();
|
||||
for (String dataId : acmIntegrationProperties
|
||||
.getApplicationConfigurationDataIds()) {
|
||||
registerDiamondListener(dataId);
|
||||
}
|
||||
if (acmPropertySourceRepository.getAll().isEmpty()) {
|
||||
|
||||
registerDiamondListener(acmIntegrationProperties
|
||||
.getApplicationConfigurationDataIdWithoutGroup());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,11 +107,17 @@ public class AcmContextRefresher implements ApplicationListener<ApplicationReady
|
||||
}
|
||||
}
|
||||
refreshHistory.add(dataId, md5);
|
||||
contextRefresher.refresh();
|
||||
applicationContext.publishEvent(new RefreshEvent(this, md5,
|
||||
"ACM Refresh, dataId=" + dataId));
|
||||
}
|
||||
});
|
||||
ConfigService.addListener(dataId,
|
||||
acmIntegrationProperties.getAcmProperties().getGroup(), listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user