1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00

SentinelProtect rename to SentinelRestTemplate

This commit is contained in:
fangjian0423 2018-12-06 16:45:47 +08:00
parent e812515250
commit fb9e0f51f4
5 changed files with 227 additions and 219 deletions

View File

@ -2,7 +2,7 @@ package org.springframework.cloud.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect; import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -15,7 +15,7 @@ import com.alibaba.csp.sentinel.datasource.Converter;
public class ServiceApplication { public class ServiceApplication {
@Bean @Bean
@SentinelProtect(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class) @SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() { public RestTemplate restTemplate() {
return new RestTemplate(); return new RestTemplate();
} }

View File

@ -16,7 +16,11 @@
package org.springframework.cloud.alibaba.sentinel.annotation; package org.springframework.cloud.alibaba.sentinel.annotation;
import java.lang.annotation.*; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* @author fangjian * @author fangjian
@ -24,7 +28,7 @@ import java.lang.annotation.*;
@Target({ ElementType.METHOD }) @Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
public @interface SentinelProtect { public @interface SentinelRestTemplate {
String blockHandler() default ""; String blockHandler() default "";

View File

@ -25,87 +25,88 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect; import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.core.type.StandardMethodMetadata; import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
/** /**
* PostProcessor handle @SentinelProtect Annotation, add interceptor for RestTemplate * PostProcessor handle @SentinelRestTemplate Annotation, add interceptor for RestTemplate
* *
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a> * @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see SentinelProtect * @see SentinelRestTemplate
* @see SentinelProtectInterceptor * @see SentinelProtectInterceptor
*/ */
public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProcessor { public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
@Autowired @Autowired
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
private ConcurrentHashMap<String, SentinelProtect> cache = new ConcurrentHashMap<>(); private ConcurrentHashMap<String, SentinelRestTemplate> cache = new ConcurrentHashMap<>();
@Override @Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, String beanName) { Class<?> beanType, String beanName) {
if (checkSentinelProtect(beanDefinition, beanType)) { if (checkSentinelProtect(beanDefinition, beanType)) {
SentinelProtect sentinelProtect = ((StandardMethodMetadata) beanDefinition SentinelRestTemplate sentinelRestTemplate = ((StandardMethodMetadata) beanDefinition
.getSource()).getIntrospectedMethod() .getSource()).getIntrospectedMethod()
.getAnnotation(SentinelProtect.class); .getAnnotation(SentinelRestTemplate.class);
cache.put(beanName, sentinelProtect); cache.put(beanName, sentinelRestTemplate);
} }
} }
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition, private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
Class<?> beanType) { Class<?> beanType) {
return beanType == RestTemplate.class return beanType == RestTemplate.class
&& beanDefinition.getSource() instanceof StandardMethodMetadata && beanDefinition.getSource() instanceof StandardMethodMetadata
&& ((StandardMethodMetadata) beanDefinition.getSource()) && ((StandardMethodMetadata) beanDefinition.getSource())
.isAnnotated(SentinelProtect.class.getName()); .isAnnotated(SentinelRestTemplate.class.getName());
} }
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException { throws BeansException {
if (cache.containsKey(beanName)) { if (cache.containsKey(beanName)) {
// add interceptor for each RestTemplate with @SentinelProtect annotation // add interceptor for each RestTemplate with @SentinelRestTemplate annotation
StringBuilder interceptorBeanName = new StringBuilder(); StringBuilder interceptorBeanName = new StringBuilder();
SentinelProtect sentinelProtect = cache.get(beanName); SentinelRestTemplate sentinelRestTemplate = cache.get(beanName);
interceptorBeanName interceptorBeanName
.append(StringUtils.uncapitalize( .append(StringUtils.uncapitalize(
SentinelProtectInterceptor.class.getSimpleName())) SentinelProtectInterceptor.class.getSimpleName()))
.append("_") .append("_")
.append(sentinelProtect.blockHandlerClass().getSimpleName()) .append(sentinelRestTemplate.blockHandlerClass().getSimpleName())
.append(sentinelProtect.blockHandler()).append("_") .append(sentinelRestTemplate.blockHandler()).append("_")
.append(sentinelProtect.fallbackClass().getSimpleName()) .append(sentinelRestTemplate.fallbackClass().getSimpleName())
.append(sentinelProtect.fallback()); .append(sentinelRestTemplate.fallback());
RestTemplate restTemplate = (RestTemplate) bean; RestTemplate restTemplate = (RestTemplate) bean;
registerBean(interceptorBeanName.toString(), sentinelProtect); registerBean(interceptorBeanName.toString(), sentinelRestTemplate);
SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
.getBean(interceptorBeanName.toString(), .getBean(interceptorBeanName.toString(),
SentinelProtectInterceptor.class); SentinelProtectInterceptor.class);
restTemplate.getInterceptors().add(sentinelProtectInterceptor); restTemplate.getInterceptors().add(sentinelProtectInterceptor);
} }
return bean; return bean;
} }
private void registerBean(String interceptorBeanName, private void registerBean(String interceptorBeanName,
SentinelProtect sentinelProtect) { SentinelRestTemplate sentinelRestTemplate) {
// register SentinelProtectInterceptor bean // register SentinelProtectInterceptor bean
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
.getAutowireCapableBeanFactory(); .getAutowireCapableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(SentinelProtectInterceptor.class); .genericBeanDefinition(SentinelProtectInterceptor.class);
beanDefinitionBuilder.addConstructorArgValue(sentinelProtect); beanDefinitionBuilder.addConstructorArgValue(sentinelRestTemplate);
BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
.getRawBeanDefinition(); .getRawBeanDefinition();
beanFactory.registerBeanDefinition(interceptorBeanName, beanFactory.registerBeanDefinition(interceptorBeanName,
interceptorBeanDefinition); interceptorBeanDefinition);
} }
@Override @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { public Object postProcessBeforeInitialization(Object bean, String beanName)
return bean; throws BeansException {
} return bean;
}
} }

View File

@ -22,7 +22,7 @@ import java.net.URI;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect; import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
@ -37,103 +37,104 @@ import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
/** /**
* Interceptor using by SentinelProtect and SentinelProtectInterceptor * Interceptor using by SentinelRestTemplate and SentinelProtectInterceptor
* *
* @author fangjian * @author fangjian
*/ */
public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor { public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory private static final Logger logger = LoggerFactory
.getLogger(SentinelProtectInterceptor.class); .getLogger(SentinelProtectInterceptor.class);
private SentinelProtect sentinelProtect; private SentinelRestTemplate sentinelRestTemplate;
public SentinelProtectInterceptor(SentinelProtect sentinelProtect) { public SentinelProtectInterceptor(SentinelRestTemplate sentinelRestTemplate) {
this.sentinelProtect = sentinelProtect; this.sentinelRestTemplate = sentinelRestTemplate;
} }
@Override @Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException { ClientHttpRequestExecution execution) throws IOException {
URI uri = request.getURI(); URI uri = request.getURI();
String hostResource = uri.getScheme() + "://" + uri.getHost() + ":" String hostResource = uri.getScheme() + "://" + uri.getHost() + ":"
+ (uri.getPort() == -1 ? 80 : uri.getPort()); + (uri.getPort() == -1 ? 80 : uri.getPort());
String hostWithPathResource = hostResource + uri.getPath(); String hostWithPathResource = hostResource + uri.getPath();
Entry hostEntry = null, hostWithPathEntry = null; Entry hostEntry = null, hostWithPathEntry = null;
ClientHttpResponse response = null; ClientHttpResponse response = null;
try { try {
ContextUtil.enter(hostWithPathResource); ContextUtil.enter(hostWithPathResource);
hostWithPathEntry = SphU.entry(hostWithPathResource); hostWithPathEntry = SphU.entry(hostWithPathResource);
hostEntry = SphU.entry(hostResource); hostEntry = SphU.entry(hostResource);
response = execution.execute(request, body); response = execution.execute(request, body);
} }
catch (BlockException e) { catch (BlockException e) {
logger.error("RestTemplate block", e); logger.error("RestTemplate block", e);
try { try {
handleBlockException(e); handleBlockException(e);
} }
catch (Exception ex) { catch (Exception ex) {
logger.error("sentinel handle BlockException error.", e); logger.error("sentinel handle BlockException error.", e);
} }
} }
finally { finally {
if (hostEntry != null) { if (hostEntry != null) {
hostEntry.exit(); hostEntry.exit();
} }
if (hostWithPathEntry != null) { if (hostWithPathEntry != null) {
hostWithPathEntry.exit(); hostWithPathEntry.exit();
} }
ContextUtil.exit(); ContextUtil.exit();
} }
return response; return response;
} }
private void handleBlockException(BlockException ex) throws Exception { private void handleBlockException(BlockException ex) throws Exception {
Object[] args = new Object[] { ex }; Object[] args = new Object[] { ex };
// handle degrade // handle degrade
if (isDegradeFailure(ex)) { if (isDegradeFailure(ex)) {
Method method = extractFallbackMethod(sentinelProtect.fallback(), Method method = extractFallbackMethod(sentinelRestTemplate.fallback(),
sentinelProtect.fallbackClass()); sentinelRestTemplate.fallbackClass());
if (method != null) { if (method != null) {
method.invoke(null, args); method.invoke(null, args);
} }
} }
// handle block // handle block
Method blockHandler = extractBlockHandlerMethod(sentinelProtect.blockHandler(), Method blockHandler = extractBlockHandlerMethod(
sentinelProtect.blockHandlerClass()); sentinelRestTemplate.blockHandler(),
if (blockHandler != null) { sentinelRestTemplate.blockHandlerClass());
blockHandler.invoke(null, args); if (blockHandler != null) {
} blockHandler.invoke(null, args);
} }
}
private Method extractFallbackMethod(String fallback, Class<?> fallbackClass) { private Method extractFallbackMethod(String fallback, Class<?> fallbackClass) {
if (StringUtil.isBlank(fallback) || fallbackClass == void.class) { if (StringUtil.isBlank(fallback) || fallbackClass == void.class) {
return null; return null;
} }
Method cachedMethod = BlockClassRegistry.lookupFallback(fallbackClass, fallback); Method cachedMethod = BlockClassRegistry.lookupFallback(fallbackClass, fallback);
if (cachedMethod == null) { if (cachedMethod == null) {
cachedMethod = ClassUtils.getStaticMethod(fallbackClass, fallback, cachedMethod = ClassUtils.getStaticMethod(fallbackClass, fallback,
BlockException.class); BlockException.class);
BlockClassRegistry.updateFallbackFor(fallbackClass, fallback, cachedMethod); BlockClassRegistry.updateFallbackFor(fallbackClass, fallback, cachedMethod);
} }
return cachedMethod; return cachedMethod;
} }
private Method extractBlockHandlerMethod(String block, Class<?> blockClass) { private Method extractBlockHandlerMethod(String block, Class<?> blockClass) {
if (StringUtil.isBlank(block) || blockClass == void.class) { if (StringUtil.isBlank(block) || blockClass == void.class) {
return null; return null;
} }
Method cachedMethod = BlockClassRegistry.lookupBlockHandler(blockClass, block); Method cachedMethod = BlockClassRegistry.lookupBlockHandler(blockClass, block);
if (cachedMethod == null) { if (cachedMethod == null) {
cachedMethod = ClassUtils.getStaticMethod(blockClass, block, cachedMethod = ClassUtils.getStaticMethod(blockClass, block,
BlockException.class); BlockException.class);
BlockClassRegistry.updateBlockHandlerFor(blockClass, block, cachedMethod); BlockClassRegistry.updateBlockHandlerFor(blockClass, block, cachedMethod);
} }
return cachedMethod; return cachedMethod;
} }
private boolean isDegradeFailure(BlockException ex) { private boolean isDegradeFailure(BlockException ex) {
return ex instanceof DegradeException; return ex instanceof DegradeException;
} }
} }

View File

@ -16,14 +16,14 @@
package org.springframework.cloud.alibaba.sentinel; package org.springframework.cloud.alibaba.sentinel;
import com.alibaba.csp.sentinel.slots.block.BlockException; import static org.assertj.core.api.Assertions.assertThat;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect; import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration; import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor; import org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor; import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor;
@ -32,84 +32,86 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat; import com.alibaba.csp.sentinel.slots.block.BlockException;
/** /**
* @author fangjian * @author fangjian
*/ */
public class SentinelAutoConfigurationTests { public class SentinelAutoConfigurationTests {
private final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); private final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
@Before @Before
public void init() { public void init() {
context.register(SentinelAutoConfiguration.class, SentinelWebAutoConfiguration.class, context.register(SentinelAutoConfiguration.class,
SentinelTestConfiguration.class); SentinelWebAutoConfiguration.class, SentinelTestConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.cloud.sentinel.transport.port=8888", "spring.cloud.sentinel.transport.port=8888",
"spring.cloud.sentinel.filter.order=123", "spring.cloud.sentinel.filter.order=123",
"spring.cloud.sentinel.filter.urlPatterns=/*,/test"); "spring.cloud.sentinel.filter.urlPatterns=/*,/test");
this.context.refresh(); this.context.refresh();
} }
@After @After
public void closeContext() { public void closeContext() {
this.context.close(); this.context.close();
} }
@Test @Test
public void testFilter() { public void testFilter() {
assertThat(context.getBean( assertThat(context.getBean("servletRequestListener")
"servletRequestListener").getClass() == FilterRegistrationBean.class).isTrue(); .getClass() == FilterRegistrationBean.class).isTrue();
} }
@Test @Test
public void testBeanPostProcessor() { public void testBeanPostProcessor() {
assertThat(context.getBean("sentinelBeanPostProcessor") assertThat(context.getBean("sentinelBeanPostProcessor")
.getClass() == SentinelBeanPostProcessor.class).isTrue(); .getClass() == SentinelBeanPostProcessor.class).isTrue();
} }
@Test @Test
public void testProperties() { public void testProperties() {
SentinelProperties sentinelProperties = context.getBean(SentinelProperties.class); SentinelProperties sentinelProperties = context.getBean(SentinelProperties.class);
assertThat(sentinelProperties).isNotNull(); assertThat(sentinelProperties).isNotNull();
assertThat(sentinelProperties.getTransport().getPort()).isEqualTo("8888"); assertThat(sentinelProperties.getTransport().getPort()).isEqualTo("8888");
assertThat(sentinelProperties.getFilter().getUrlPatterns().size()).isEqualTo(2); assertThat(sentinelProperties.getFilter().getUrlPatterns().size()).isEqualTo(2);
assertThat(sentinelProperties.getFilter().getUrlPatterns().get(0)).isEqualTo("/*"); assertThat(sentinelProperties.getFilter().getUrlPatterns().get(0))
assertThat(sentinelProperties.getFilter().getUrlPatterns().get(1)).isEqualTo("/test"); .isEqualTo("/*");
} assertThat(sentinelProperties.getFilter().getUrlPatterns().get(1))
.isEqualTo("/test");
}
@Test @Test
public void testRestTemplate() { public void testRestTemplate() {
assertThat(context.getBeansOfType(RestTemplate.class).size()).isEqualTo(2); assertThat(context.getBeansOfType(RestTemplate.class).size()).isEqualTo(2);
RestTemplate restTemplate = context.getBean("restTemplateWithBlockClass", RestTemplate restTemplate = context.getBean("restTemplateWithBlockClass",
RestTemplate.class); RestTemplate.class);
assertThat(restTemplate.getInterceptors().size()).isEqualTo(1); assertThat(restTemplate.getInterceptors().size()).isEqualTo(1);
assertThat(restTemplate.getInterceptors().get(0).getClass()) assertThat(restTemplate.getInterceptors().get(0).getClass())
.isEqualTo(SentinelProtectInterceptor.class); .isEqualTo(SentinelProtectInterceptor.class);
} }
@Configuration @Configuration
static class SentinelTestConfiguration { static class SentinelTestConfiguration {
@Bean @Bean
@SentinelProtect @SentinelRestTemplate
RestTemplate restTemplate() { RestTemplate restTemplate() {
return new RestTemplate(); return new RestTemplate();
} }
@Bean @Bean
@SentinelProtect(blockHandlerClass = ExceptionUtil.class, blockHandler = "handleException") @SentinelRestTemplate(blockHandlerClass = ExceptionUtil.class, blockHandler = "handleException")
RestTemplate restTemplateWithBlockClass() { RestTemplate restTemplateWithBlockClass() {
return new RestTemplate(); return new RestTemplate();
} }
} }
static class ExceptionUtil { static class ExceptionUtil {
public static void handleException(BlockException ex) { public static void handleException(BlockException ex) {
System.out.println("Oops: " + ex.getClass().getCanonicalName()); System.out.println("Oops: " + ex.getClass().getCanonicalName());
} }
} }
} }