mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
Merge pull request #864 from Rivers-Shall/fix-#762
Fix #762 SentinelRestTemplate enhancement
This commit is contained in:
commit
b9d13cc254
@ -26,6 +26,7 @@ public class ConsumerApplication {
|
|||||||
|
|
||||||
@LoadBalanced
|
@LoadBalanced
|
||||||
@Bean
|
@Bean
|
||||||
|
@SentinelRestTemplate(urlCleanerClass = UrlCleaner.class, urlCleaner = "clean")
|
||||||
public RestTemplate restTemplate() {
|
public RestTemplate restTemplate() {
|
||||||
return new RestTemplate();
|
return new RestTemplate();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.alibaba.cloud.examples;
|
||||||
|
|
||||||
|
public class UrlCleaner {
|
||||||
|
public static String clean(String url) {
|
||||||
|
System.out.println("enter urlCleaner");
|
||||||
|
if (url.matches(".*/echo/.*")) {
|
||||||
|
System.out.println("change url");
|
||||||
|
url = url.replaceAll("/echo/.*", "/echo/{str}");
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ public interface SentinelConstants {
|
|||||||
|
|
||||||
String BLOCK_TYPE = "block";
|
String BLOCK_TYPE = "block";
|
||||||
String FALLBACK_TYPE = "fallback";
|
String FALLBACK_TYPE = "fallback";
|
||||||
|
String URLCLEANER_TYPE = "urlCleaner";
|
||||||
|
|
||||||
// commercialization
|
// commercialization
|
||||||
|
|
||||||
|
@ -38,4 +38,7 @@ public @interface SentinelRestTemplate {
|
|||||||
|
|
||||||
Class<?> fallbackClass() default void.class;
|
Class<?> fallbackClass() default void.class;
|
||||||
|
|
||||||
|
String urlCleaner() default "";
|
||||||
|
|
||||||
|
Class<?> urlCleanerClass() default void.class;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author fangjian
|
* @author fangjian
|
||||||
@ -29,6 +30,7 @@ final class BlockClassRegistry {
|
|||||||
|
|
||||||
private static final Map<String, Method> FALLBACK_MAP = new ConcurrentHashMap<>();
|
private static final Map<String, Method> FALLBACK_MAP = new ConcurrentHashMap<>();
|
||||||
private static final Map<String, Method> BLOCK_HANDLER_MAP = new ConcurrentHashMap<>();
|
private static final Map<String, Method> BLOCK_HANDLER_MAP = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<String, Method> URL_CLEANER_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
static Method lookupFallback(Class<?> clazz, String name) {
|
static Method lookupFallback(Class<?> clazz, String name) {
|
||||||
return FALLBACK_MAP.get(getKey(clazz, name));
|
return FALLBACK_MAP.get(getKey(clazz, name));
|
||||||
@ -38,6 +40,10 @@ final class BlockClassRegistry {
|
|||||||
return BLOCK_HANDLER_MAP.get(getKey(clazz, name));
|
return BLOCK_HANDLER_MAP.get(getKey(clazz, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Method lookupUrlCleaner(Class<?> clazz, String name) {
|
||||||
|
return URL_CLEANER_MAP.get(getKey(clazz, name));
|
||||||
|
}
|
||||||
|
|
||||||
static void updateFallbackFor(Class<?> clazz, String name, Method method) {
|
static void updateFallbackFor(Class<?> clazz, String name, Method method) {
|
||||||
if (clazz == null || StringUtil.isBlank(name)) {
|
if (clazz == null || StringUtil.isBlank(name)) {
|
||||||
throw new IllegalArgumentException("Bad argument");
|
throw new IllegalArgumentException("Bad argument");
|
||||||
@ -52,6 +58,13 @@ final class BlockClassRegistry {
|
|||||||
BLOCK_HANDLER_MAP.put(getKey(clazz, name), method);
|
BLOCK_HANDLER_MAP.put(getKey(clazz, name), method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void updateUrlCleanerFor(Class<?> clazz, String name, Method method) {
|
||||||
|
if (clazz == null || StringUtil.isBlank(name)) {
|
||||||
|
throw new IllegalArgumentException("Bad argument");
|
||||||
|
}
|
||||||
|
URL_CLEANER_MAP.put(getKey(clazz, name), method);
|
||||||
|
}
|
||||||
|
|
||||||
private static String getKey(Class<?> clazz, String name) {
|
private static String getKey(Class<?> clazz, String name) {
|
||||||
return String.format("%s:%s", clazz.getCanonicalName(), name);
|
return String.format("%s:%s", clazz.getCanonicalName(), name);
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,9 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
|
|||||||
checkBlock4RestTemplate(sentinelRestTemplate.fallbackClass(),
|
checkBlock4RestTemplate(sentinelRestTemplate.fallbackClass(),
|
||||||
sentinelRestTemplate.fallback(), beanName,
|
sentinelRestTemplate.fallback(), beanName,
|
||||||
SentinelConstants.FALLBACK_TYPE);
|
SentinelConstants.FALLBACK_TYPE);
|
||||||
|
checkBlock4RestTemplate(sentinelRestTemplate.urlCleanerClass(),
|
||||||
|
sentinelRestTemplate.urlCleaner(), beanName,
|
||||||
|
SentinelConstants.URLCLEANER_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkBlock4RestTemplate(Class<?> blockClass, String blockMethod,
|
private void checkBlock4RestTemplate(Class<?> blockClass, String blockMethod,
|
||||||
@ -111,8 +114,14 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
|
|||||||
throw new IllegalArgumentException(type + " method attribute exists but "
|
throw new IllegalArgumentException(type + " method attribute exists but "
|
||||||
+ type + " class attribute is not exists in bean[" + beanName + "]");
|
+ type + " class attribute is not exists in bean[" + beanName + "]");
|
||||||
}
|
}
|
||||||
Class[] args = new Class[] { HttpRequest.class, byte[].class,
|
Class[] args;
|
||||||
|
if (type.equals(SentinelConstants.URLCLEANER_TYPE)) {
|
||||||
|
args = new Class[] { String.class };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
args = new Class[] { HttpRequest.class, byte[].class,
|
||||||
ClientHttpRequestExecution.class, BlockException.class };
|
ClientHttpRequestExecution.class, BlockException.class };
|
||||||
|
}
|
||||||
String argsStr = Arrays.toString(
|
String argsStr = Arrays.toString(
|
||||||
Arrays.stream(args).map(clazz -> clazz.getSimpleName()).toArray());
|
Arrays.stream(args).map(clazz -> clazz.getSimpleName()).toArray());
|
||||||
Method foundMethod = ClassUtils.getStaticMethod(blockClass, blockMethod, args);
|
Method foundMethod = ClassUtils.getStaticMethod(blockClass, blockMethod, args);
|
||||||
@ -127,21 +136,32 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
|
|||||||
+ ", please check your class name, method name and arguments");
|
+ ", please check your class name, method name and arguments");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ClientHttpResponse.class.isAssignableFrom(foundMethod.getReturnType())) {
|
Class<?> standardReturnType;
|
||||||
log.error(
|
if (type.equals(SentinelConstants.URLCLEANER_TYPE)) {
|
||||||
"{} method return value in bean[{}] is not ClientHttpResponse: {}#{}{}",
|
standardReturnType = String.class;
|
||||||
type, beanName, blockClass.getName(), blockMethod, argsStr);
|
}
|
||||||
|
else {
|
||||||
|
standardReturnType = ClientHttpResponse.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!standardReturnType.isAssignableFrom(foundMethod.getReturnType())) {
|
||||||
|
log.error("{} method return value in bean[{}] is not {}: {}#{}{}", type,
|
||||||
|
beanName, standardReturnType.getName(), blockClass.getName(),
|
||||||
|
blockMethod, argsStr);
|
||||||
throw new IllegalArgumentException(type + " method return value in bean["
|
throw new IllegalArgumentException(type + " method return value in bean["
|
||||||
+ beanName + "] is not ClientHttpResponse: " + blockClass.getName()
|
+ beanName + "] is not " + standardReturnType.getName() + ": "
|
||||||
+ "#" + blockMethod + argsStr);
|
+ blockClass.getName() + "#" + blockMethod + argsStr);
|
||||||
}
|
}
|
||||||
if (type.equals(SentinelConstants.BLOCK_TYPE)) {
|
if (type.equals(SentinelConstants.BLOCK_TYPE)) {
|
||||||
BlockClassRegistry.updateBlockHandlerFor(blockClass, blockMethod,
|
BlockClassRegistry.updateBlockHandlerFor(blockClass, blockMethod,
|
||||||
foundMethod);
|
foundMethod);
|
||||||
}
|
}
|
||||||
else {
|
else if (type.equals(SentinelConstants.FALLBACK_TYPE)) {
|
||||||
BlockClassRegistry.updateFallbackFor(blockClass, blockMethod, foundMethod);
|
BlockClassRegistry.updateFallbackFor(blockClass, blockMethod, foundMethod);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
BlockClassRegistry.updateUrlCleanerFor(blockClass, blockMethod, foundMethod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
|
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
|
||||||
@ -177,7 +197,9 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
|
|||||||
.append(sentinelRestTemplate.blockHandlerClass().getSimpleName())
|
.append(sentinelRestTemplate.blockHandlerClass().getSimpleName())
|
||||||
.append(sentinelRestTemplate.blockHandler()).append("_")
|
.append(sentinelRestTemplate.blockHandler()).append("_")
|
||||||
.append(sentinelRestTemplate.fallbackClass().getSimpleName())
|
.append(sentinelRestTemplate.fallbackClass().getSimpleName())
|
||||||
.append(sentinelRestTemplate.fallback());
|
.append(sentinelRestTemplate.fallback()).append("_")
|
||||||
|
.append(sentinelRestTemplate.urlCleanerClass().getSimpleName())
|
||||||
|
.append(sentinelRestTemplate.urlCleaner());
|
||||||
RestTemplate restTemplate = (RestTemplate) bean;
|
RestTemplate restTemplate = (RestTemplate) bean;
|
||||||
String interceptorBeanName = interceptorBeanNamePrefix + "@"
|
String interceptorBeanName = interceptorBeanNamePrefix + "@"
|
||||||
+ bean.toString();
|
+ bean.toString();
|
||||||
|
@ -65,6 +65,14 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
|
|||||||
if (hostResource.equals(hostWithPathResource)) {
|
if (hostResource.equals(hostWithPathResource)) {
|
||||||
entryWithPath = false;
|
entryWithPath = false;
|
||||||
}
|
}
|
||||||
|
Method urlCleanerMethod = BlockClassRegistry.lookupUrlCleaner(
|
||||||
|
sentinelRestTemplate.urlCleanerClass(),
|
||||||
|
sentinelRestTemplate.urlCleaner());
|
||||||
|
if (urlCleanerMethod != null) {
|
||||||
|
hostWithPathResource = (String) methodInvoke(urlCleanerMethod,
|
||||||
|
hostWithPathResource);
|
||||||
|
}
|
||||||
|
|
||||||
Entry hostEntry = null, hostWithPathEntry = null;
|
Entry hostEntry = null, hostWithPathEntry = null;
|
||||||
ClientHttpResponse response = null;
|
ClientHttpResponse response = null;
|
||||||
try {
|
try {
|
||||||
@ -105,7 +113,7 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
|
|||||||
Method fallbackMethod = extractFallbackMethod(sentinelRestTemplate.fallback(),
|
Method fallbackMethod = extractFallbackMethod(sentinelRestTemplate.fallback(),
|
||||||
sentinelRestTemplate.fallbackClass());
|
sentinelRestTemplate.fallbackClass());
|
||||||
if (fallbackMethod != null) {
|
if (fallbackMethod != null) {
|
||||||
return methodInvoke(fallbackMethod, args);
|
return (ClientHttpResponse) methodInvoke(fallbackMethod, args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new SentinelClientHttpResponse();
|
return new SentinelClientHttpResponse();
|
||||||
@ -116,16 +124,16 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
|
|||||||
sentinelRestTemplate.blockHandler(),
|
sentinelRestTemplate.blockHandler(),
|
||||||
sentinelRestTemplate.blockHandlerClass());
|
sentinelRestTemplate.blockHandlerClass());
|
||||||
if (blockHandler != null) {
|
if (blockHandler != null) {
|
||||||
return methodInvoke(blockHandler, args);
|
return (ClientHttpResponse) methodInvoke(blockHandler, args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new SentinelClientHttpResponse();
|
return new SentinelClientHttpResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientHttpResponse methodInvoke(Method method, Object... args) {
|
private Object methodInvoke(Method method, Object... args) {
|
||||||
try {
|
try {
|
||||||
return (ClientHttpResponse) method.invoke(null, args);
|
return method.invoke(null, args);
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e) {
|
catch (IllegalAccessException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -91,6 +91,26 @@ public class SentinelRestTemplateTests {
|
|||||||
new AnnotationConfigApplicationContext(TestConfig10.class);
|
new AnnotationConfigApplicationContext(TestConfig10.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = BeanCreationException.class)
|
||||||
|
public void testUrlClnMethod() {
|
||||||
|
new AnnotationConfigApplicationContext(TestConfig11.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = BeanCreationException.class)
|
||||||
|
public void testUrlClnClass() {
|
||||||
|
new AnnotationConfigApplicationContext(TestConfig12.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = BeanCreationException.class)
|
||||||
|
public void testUrlClnMethodExists() {
|
||||||
|
new AnnotationConfigApplicationContext(TestConfig13.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = BeanCreationException.class)
|
||||||
|
public void testUrlClnReturnValue() {
|
||||||
|
new AnnotationConfigApplicationContext(TestConfig14.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public static class TestConfig1 {
|
public static class TestConfig1 {
|
||||||
@Bean
|
@Bean
|
||||||
@ -160,7 +180,7 @@ public class SentinelRestTemplateTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@SentinelRestTemplate(blockHandlerClass = SentinelRestTemplateTests.ExceptionUtil.class, blockHandler = "handleException", fallbackClass = SentinelRestTemplateTests.ExceptionUtil.class, fallback = "fallbackException")
|
@SentinelRestTemplate(blockHandlerClass = SentinelRestTemplateTests.ExceptionUtil.class, blockHandler = "handleException", fallbackClass = SentinelRestTemplateTests.ExceptionUtil.class, fallback = "fallbackException", urlCleanerClass = SentinelRestTemplateTests.UrlCleanUtil.class, urlCleaner = "clean")
|
||||||
RestTemplate restTemplate() {
|
RestTemplate restTemplate() {
|
||||||
return new RestTemplate();
|
return new RestTemplate();
|
||||||
}
|
}
|
||||||
@ -247,6 +267,66 @@ public class SentinelRestTemplateTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static class TestConfig11 {
|
||||||
|
@Bean
|
||||||
|
SentinelBeanPostProcessor sentinelBeanPostProcessor(
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
|
return new SentinelBeanPostProcessor(applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SentinelRestTemplate(urlCleaner = "cln")
|
||||||
|
RestTemplate restTemplate() {
|
||||||
|
return new RestTemplate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static class TestConfig12 {
|
||||||
|
@Bean
|
||||||
|
SentinelBeanPostProcessor sentinelBeanPostProcessor(
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
|
return new SentinelBeanPostProcessor(applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SentinelRestTemplate(urlCleanerClass = UrlCleanUtil.class)
|
||||||
|
RestTemplate restTemplate() {
|
||||||
|
return new RestTemplate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static class TestConfig13 {
|
||||||
|
@Bean
|
||||||
|
SentinelBeanPostProcessor sentinelBeanPostProcessor(
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
|
return new SentinelBeanPostProcessor(applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SentinelRestTemplate(urlCleanerClass = SentinelRestTemplateTests.UrlCleanUtil.class, urlCleaner = "clean1")
|
||||||
|
RestTemplate restTemplate() {
|
||||||
|
return new RestTemplate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static class TestConfig14 {
|
||||||
|
@Bean
|
||||||
|
SentinelBeanPostProcessor sentinelBeanPostProcessor(
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
|
return new SentinelBeanPostProcessor(applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SentinelRestTemplate(urlCleanerClass = SentinelRestTemplateTests.UrlCleanUtil.class, urlCleaner = "clean2")
|
||||||
|
RestTemplate restTemplate() {
|
||||||
|
return new RestTemplate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class ExceptionUtil {
|
public static class ExceptionUtil {
|
||||||
public static SentinelClientHttpResponse handleException(HttpRequest request,
|
public static SentinelClientHttpResponse handleException(HttpRequest request,
|
||||||
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
|
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
|
||||||
@ -271,4 +351,13 @@ public class SentinelRestTemplateTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class UrlCleanUtil {
|
||||||
|
public static String clean(String url) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clean2(String url) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user