1. @Bean
2. @SentinelRestTemplate(fallback = "fallback", fallbackClass = ExceptionUtil.class, blockHandler="handleException",blockHandlerClass=ExceptionUtil.class)
3. public RestTemplate restTemplate() {
4. return new RestTemplate();
5. }
? blockHandler 限流后处理的方法
? blockHandlerClass 限流后处理的类
? fallback 熔断后处理的方法
? fallbackClass 熔断后处理的类
异常处理类定义需要注意的是该方法的参数跟返回值跟org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中参数多出了一个 BlockException 参数用于获取 Sentinel 捕获的异常。
1. public class ExceptionUtil {
2. public static SentinelClientHttpResponse handleException(HttpRequest request,
3. byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
4. System.err.println("Oops: " + ex.getClass().getCanonicalName());
5. return new SentinelClientHttpResponse("custom block info");
6. }
7.
8. public static SentinelClientHttpResponse fallback(HttpRequest request,
9. byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
10. System.err.println("fallback: " + ex.getClass().getCanonicalName());
11. return new SentinelClientHttpResponse("custom fallback info");
12. }
13. }
原理剖析
核心代码在org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor中,实现了MergedBeanDefinitionPostProcessor接口,MergedBeanDefinitionPostProcessor接口实现了BeanPostProcessor接口。
核心方法就是重写的postProcessMergedBeanDefinition和postProcessAfterInitialization。
postProcessMergedBeanDefinition
1. private ConcurrentHashMap<String, SentinelRestTemplate> cache = new ConcurrentHashMap<>();
2.
3. @Override
4. public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
5. Class<?> beanType, String beanName) {
6. if (checkSentinelProtect(beanDefinition, beanType)) {
7. SentinelRestTemplate sentinelRestTemplate = ((StandardMethodMetadata) beanDefinition
8. .getSource()).getIntrospectedMethod()
9. .getAnnotation(SentinelRestTemplate.class);
10. // 获取SentinelRestTemplate注解对象存储起来
11. cache.put(beanName, sentinelRestTemplate);
12. }
13. }
14. // 判断bean是否加了SentinelRestTemplate注解并且是RestTemplate
15. private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
16. Class<?> beanType) {
17. return beanType == RestTemplate.class
18. && beanDefinition.getSource() instanceof StandardMethodMetadata
19. && ((StandardMethodMetadata) beanDefinition.getSource())
20. .isAnnotated(SentinelRestTemplate.class.getName());
21. }
postProcessAfterInitialization
1. @Override
2. public Object postProcessAfterInitialization(Object bean, String beanName)
3. throws BeansException {
4. if (cache.containsKey(beanName)) {
5. // add interceptor for each RestTemplate with @SentinelRestTemplate annotation
6. StringBuilder interceptorBeanName = new StringBuilder();
7. // 缓存中得到注解对象
8. SentinelRestTemplate sentinelRestTemplate = cache.get(beanName);
9. // 生成interceptorBeanName SentinelProtectInterceptor名称
10. interceptorBeanName
11. .append(StringUtils.uncapitalize(
12. SentinelProtectInterceptor.class.getSimpleName()))
13. .append("_")
14. .append(sentinelRestTemplate.blockHandlerClass().getSimpleName())
15. .append(sentinelRestTemplate.blockHandler()).append("_")
16. .append(sentinelRestTemplate.fallbackClass().getSimpleName())
17. .append(sentinelRestTemplate.fallback());
18. RestTemplate restTemplate = (RestTemplate) bean;
19. // 注册SentinelProtectInterceptor
20. registerBean(interceptorBeanName.toString(), sentinelRestTemplate);
21. // 获取SentinelProtectInterceptor
22. SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
23. .getBean(interceptorBeanName.toString(),
24. SentinelProtectInterceptor.class);
25. // 给restTemplate添加拦截器
26. restTemplate.getInterceptors().add(sentinelProtectInterceptor);
27. }
28. return bean;
29. }
30. // 注册SentinelProtectInterceptor类
31. private void registerBean(String interceptorBeanName,
32. SentinelRestTemplate sentinelRestTemplate) {
33. // register SentinelProtectInterceptor bean
34. DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
35. .getAutowireCapableBeanFactory();
36. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
37. .genericBeanDefinition(SentinelProtectInterceptor.class);
38. beanDefinitionBuilder.addConstructorArgValue(sentinelRestTemplate);
39. BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
40. .getRawBeanDefinition();
41. beanFactory.registerBeanDefinition(interceptorBeanName,
42. interceptorBeanDefinition);
43. }
看到这边大家就明白了,其实就是给restTemplate添加拦截器来处理。跟Ribbon中的@LoadBalanced原理是一样的。
SentinelProtectInterceptor
Sentinel RestTemplate 限流的资源规则提供两种粒度:
? schema://host:port/path:协议、主机、端口和路径
? schema://host:port:协议、主机和端口
这两种粒度从org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor.intercept(HttpRequest, byte[], ClientHttpRequestExecution)方法中可以看的出来
1. URI uri = request.getURI();
2. String hostResource = uri.getScheme() + "://" + uri.getHost()
3. + (uri.getPort() == -1 ? "" : ":" + uri.getPort());
4. String hostWithPathResource = hostResource + uri.getPath();
下面就是根据hostResource和hostWithPathResource进行限流
1. ContextUtil.enter(hostWithPathResource);
2. if (entryWithPath) {
3. hostWithPathEntry = SphU.entry(hostWithPathResource);
4. }
5. hostEntry = SphU.entry(hostResource);
6. // 执行Http调用
7. response = execution.execute(request, body);
在后面就是释放资源,异常处理等代码,大家自己去了解下。
加入星球特权
1、从前端到后端玩转Spring Cloud
2、实战分库分表中间件Sharding-JDBC
3、实战分布式任务调度框架Elastic Job
4、配置中心Apollo实战
5、高并发解决方案之缓存
6、更多课程等你来解锁,20+课程
尹吉欢
我不差钱啊
喜欢作者
Spring Cloud Alibaba Sentinel对RestTemplate的支持
原文:https://blog.51cto.com/14888386/2515789