Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造 RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。

需要注意的是目前的版本spring-cloud-starter-alibaba-sentinel.0.2.1.RELEASE在配置RestTemplate的时候有个Bug,需要将配置放在Spring Boot的启动类中,也就是@SpringBootApplication注解所在的类。

如果单独放在@Configuration标记的类中目前是有问题的,当然后续版本中会进行修复,对应的问题描述:https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/227

@Bean
@SentinelRestTemplate(fallback = "fallback", fallbackClass = ExceptionUtil.class, blockHandler="handleException",blockHandlerClass=ExceptionUtil.class)
public RestTemplate restTemplate() {
return new RestTemplate();
}
  • blockHandler

    限流后处理的方法
  • blockHandlerClass

    限流后处理的类
  • fallback

    熔断后处理的方法
  • fallbackClass

    熔断后处理的类

异常处理类定义需要注意的是该方法的参数跟返回值跟 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中参数多出了一个 BlockException 参数用于获取 Sentinel 捕获的异常。

public class ExceptionUtil {
public static SentinelClientHttpResponse handleException(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
System.err.println("Oops: " + ex.getClass().getCanonicalName());
return new SentinelClientHttpResponse("custom block info");
} public static SentinelClientHttpResponse fallback(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
System.err.println("fallback: " + ex.getClass().getCanonicalName());
return new SentinelClientHttpResponse("custom fallback info");
}
}

原理剖析

核心代码在org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor中,实现了MergedBeanDefinitionPostProcessor接口,MergedBeanDefinitionPostProcessor接口实现了BeanPostProcessor接口。

核心方法就是重写的postProcessMergedBeanDefinition和postProcessAfterInitialization。

postProcessMergedBeanDefinition

private ConcurrentHashMap<String, SentinelRestTemplate> cache = new ConcurrentHashMap<>();

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, String beanName) {
if (checkSentinelProtect(beanDefinition, beanType)) {
SentinelRestTemplate sentinelRestTemplate = ((StandardMethodMetadata) beanDefinition
.getSource()).getIntrospectedMethod()
.getAnnotation(SentinelRestTemplate.class);
// 获取SentinelRestTemplate注解对象存储起来
cache.put(beanName, sentinelRestTemplate);
}
}
// 判断bean是否加了SentinelRestTemplate注解并且是RestTemplate
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
Class<?> beanType) {
return beanType == RestTemplate.class
&& beanDefinition.getSource() instanceof StandardMethodMetadata
&& ((StandardMethodMetadata) beanDefinition.getSource())
.isAnnotated(SentinelRestTemplate.class.getName());
}

postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (cache.containsKey(beanName)) {
// add interceptor for each RestTemplate with @SentinelRestTemplate annotation
StringBuilder interceptorBeanName = new StringBuilder();
// 缓存中得到注解对象
SentinelRestTemplate sentinelRestTemplate = cache.get(beanName);
// 生成interceptorBeanName SentinelProtectInterceptor名称
interceptorBeanName
.append(StringUtils.uncapitalize(
SentinelProtectInterceptor.class.getSimpleName()))
.append("_")
.append(sentinelRestTemplate.blockHandlerClass().getSimpleName())
.append(sentinelRestTemplate.blockHandler()).append("_")
.append(sentinelRestTemplate.fallbackClass().getSimpleName())
.append(sentinelRestTemplate.fallback());
RestTemplate restTemplate = (RestTemplate) bean;
// 注册SentinelProtectInterceptor
registerBean(interceptorBeanName.toString(), sentinelRestTemplate);
// 获取SentinelProtectInterceptor
SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
.getBean(interceptorBeanName.toString(),
SentinelProtectInterceptor.class);
// 给restTemplate添加拦截器
restTemplate.getInterceptors().add(sentinelProtectInterceptor);
}
return bean;
}
// 注册SentinelProtectInterceptor类
private void registerBean(String interceptorBeanName,
SentinelRestTemplate sentinelRestTemplate) {
// register SentinelProtectInterceptor bean
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
.getAutowireCapableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(SentinelProtectInterceptor.class);
beanDefinitionBuilder.addConstructorArgValue(sentinelRestTemplate);
BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
.getRawBeanDefinition();
beanFactory.registerBeanDefinition(interceptorBeanName,
interceptorBeanDefinition);
}

看到这边大家就明白了,其实就是给restTemplate添加拦截器来处理。跟Ribbon中的@LoadBalanced原理是一样的。

SentinelProtectInterceptor

Sentinel RestTemplate 限流的资源规则提供两种粒度:

  • schema://host:port/path:协议、主机、端口和路径
  • schema://host:port:协议、主机和端口

这两种粒度从org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor.intercept(HttpRequest, byte[], ClientHttpRequestExecution)方法中可以看的出来

URI uri = request.getURI();
String hostResource = uri.getScheme() + "://" + uri.getHost()
+ (uri.getPort() == -1 ? "" : ":" + uri.getPort());
String hostWithPathResource = hostResource + uri.getPath();

下面就是根据hostResource和hostWithPathResource进行限流

ContextUtil.enter(hostWithPathResource);
if (entryWithPath) {
hostWithPathEntry = SphU.entry(hostWithPathResource);
}
hostEntry = SphU.entry(hostResource);
// 执行Http调用
response = execution.execute(request, body);

在后面就是释放资源,异常处理等代码,大家自己去了解下。

欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)

PS:目前星球中正在星主的带领下组队学习Sentinel,等你哦!

Spring Cloud Alibaba Sentinel对RestTemplate的支持的更多相关文章

  1. Spring Cloud Alibaba Sentinel对Feign的支持

    Spring Cloud Alibaba Sentinel 除了对 RestTemplate 做了支持,同样对于 Feign 也做了支持,如果我们要从 Hystrix 切换到 Sentinel 是非常 ...

  2. Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战

    Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战 在阅读本文前,建议先阅读<Spring Cloud Alibaba | Sentinel:分布式系 ...

  3. Spring Cloud Alibaba | Sentinel: 分布式系统的流量防卫兵初探

    目录 Spring Cloud Alibaba | Sentinel: 分布式系统的流量防卫兵初探 1. Sentinel 是什么? 2. Sentinel 的特征: 3. Sentinel 的开源生 ...

  4. Spring Cloud Alibaba | Sentinel: 服务限流基础篇

    目录 Spring Cloud Alibaba | Sentinel: 服务限流基础篇 1. 简介 2. 定义资源 2.1 主流框架的默认适配 2.2 抛出异常的方式定义资源 2.3 返回布尔值方式定 ...

  5. Spring Cloud Alibaba | Sentinel: 服务限流高级篇

    目录 Spring Cloud Alibaba | Sentinel: 服务限流高级篇 1. 熔断降级 1.1 降级策略 2. 热点参数限流 2.1 项目依赖 2.2 热点参数规则 3. 系统自适应限 ...

  6. Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战

    Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战 Springboot: 2.1.8.RELEASE SpringCloud: Greenwich.SR2 ...

  7. Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵动态限流规则

    Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵动态限流规则 前面几篇文章较为详细的介绍了Sentinel的使用姿势,还没看过的小伙伴可以访问以下链接查看: &l ...

  8. 0.9.0.RELEASE版本的spring cloud alibaba sentinel实例

    sentinel即哨兵,相比hystrix断路器而言,它的功能更丰富.hystrix仅支持熔断,当服务消费方调用提供方发现异常后,进入熔断:sentinel不仅支持异常熔断,也支持响应超时熔断,另外还 ...

  9. 0.9.0.RELEASE版本的spring cloud alibaba sentinel+feign降级处理实例

    既然用到了feign,那么主要是针对服务消费方的降级处理.我们基于0.9.0.RELEASE版本的spring cloud alibaba nacos+feign实例添油加醋,把sentinel功能加 ...

随机推荐

  1. IT兄弟连 Java语法教程 注释与编码规范

    在程序代码中适当地添加注释可以提高程序的可读性和可维护性.好的编码规范可以使程序更易阅读和理解.下面将介绍Java中的集中代码注释以及应该注意的编码规范. 代码注释 通过在程序代码中添加注释可提高程序 ...

  2. Python extend函数解读

    num = [1,2] print('将1迭代2次') num.extend([1]*2) print(num) print('将2迭代3次') num.extend([2] * 3) print(n ...

  3. python多项式求解

    例如:p(x) = x3 - 3x+5 可以使用向量P=[1,0,-3,5]表示,向量长度减一表示多项式最高项次数. 从右到左分别是变量x的0次幂.1次幂.2次幂……n次幂. 这里可以使用numpy的 ...

  4. keras RAdam优化器使用教程, keras加载模型包含自定义优化器报错 如何解决?

    本文首发于个人博客https://kezunlin.me/post/c691f02b/,欢迎阅读最新内容! python keras RAdam tutorial and load custom op ...

  5. 记一次Python与C#的AES加密对接

    前言 这几天做自动化测试的同事找到我,说是帮她看看有个AES加密的问题要怎么处理. 大概就是文档中贴了一段C#的AES加密代码,然后她要翻译成python的版本,去做一些测试相关的工作. 在我印象中, ...

  6. Python巧用法

    #for 与 else 搭配使用(使用break跳过else) a=[1,2,3,4,5] for i in a: print(i) else: print(i, 'I am else!') for ...

  7. PlayJava Day007

    今日所学: /* 2019.08.19开始学习,此为补档. */ 1.String类 实例化:①String name1 = "张三" ; ②String name2 = new ...

  8. node开发基础概念

    1.以严格模式运行一个js文件 node --use_strict xxx.js 2.退出node交互模式 连续按两次Ctrl+C. 3,node.js的模块不支持ES6的export.import规 ...

  9. C++ 手把手教你实现可变长的数组

    01 实现自定义的可变长数组类型 假设我们要实现一个会自动扩展的数组,要实现什么函数呢?先从下面的main函数给出的实现,看看有什么函数是需要我们实现的. int main() { MyArray a ...

  10. CSS3 2D变形 transform---移动 translate(x, y), 缩放 scale(x, y), 旋转 rotate(deg), transform-origin, 倾斜 skew(deg, deg)

    transform是CSS3中具有颠覆性的特征之一,可以实现元素的位移.旋转.倾斜.缩放,甚至支持矩阵方式,配合过渡和即将学习的动画知识,可以取代大量之前只能靠Flash才可以实现的效果. 变形转换 ...