diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml
index 7639ee0bf..ed51123ab 100644
--- a/spring-cloud-alibaba-dependencies/pom.xml
+++ b/spring-cloud-alibaba-dependencies/pom.xml
@@ -16,7 +16,7 @@
Spring Cloud Alibaba Dependencies
- 0.1.0
+ 0.1.1
@@ -41,6 +41,16 @@
sentinel-transport-simple-http
${sentinel.version}
+
+ com.alibaba.csp
+ sentinel-annotation-aspectj
+ ${sentinel.version}
+
+
+ com.alibaba.csp
+ sentinel-dubbo-adapter
+ ${sentinel.version}
+
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/pom.xml b/spring-cloud-alibaba-sentinel-autoconfigure/pom.xml
index 25c0ef217..7b10ee91d 100644
--- a/spring-cloud-alibaba-sentinel-autoconfigure/pom.xml
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/pom.xml
@@ -25,6 +25,16 @@
sentinel-transport-simple-http
+
+ com.alibaba.csp
+ sentinel-annotation-aspectj
+
+
+
+ com.alibaba.csp
+ sentinel-dubbo-adapter
+
+
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java
index 73795218a..0f4fb4fee 100644
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java
@@ -16,11 +16,12 @@
package org.springframework.cloud.alibaba.sentinel;
-import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import java.util.ArrayList;
import java.util.List;
-import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+import javax.annotation.PostConstruct;
+import javax.servlet.Filter;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,14 +34,13 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
-import javax.annotation.PostConstruct;
-import javax.servlet.Filter;
+import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
/**
* @author xiaojing
*/
@Configuration
-@ConditionalOnWebApplication
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelWebAutoConfiguration {
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelCustomAspectAutoConfiguration.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelProtect.java
similarity index 61%
rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelCustomAspectAutoConfiguration.java
rename to spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelProtect.java
index 77cde741c..6586c8d31 100644
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelCustomAspectAutoConfiguration.java
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelProtect.java
@@ -14,17 +14,24 @@
* limitations under the License.
*/
-package org.springframework.cloud.alibaba.sentinel.custom;
+package org.springframework.cloud.alibaba.sentinel.annotation;
-import org.springframework.context.annotation.Bean;
+import java.lang.annotation.*;
/**
- * @author xiaojing
+ * @author fangjian
*/
-public class SentinelCustomAspectAutoConfiguration {
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SentinelProtect {
+
+ String blockHandler() default "";
+
+ Class> blockHandlerClass() default void.class;
+
+ String fallback() default "";
+
+ Class> fallbackClass() default void.class;
- @Bean
- public SentinelAspect sentinelAspect() {
- return new SentinelAspect();
- }
}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/BlockClassRegistry.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/BlockClassRegistry.java
new file mode 100644
index 000000000..42eeca3cf
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/BlockClassRegistry.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.sentinel.custom;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+/**
+ * @author fangjian
+ */
+final class BlockClassRegistry {
+
+ private static final Map FALLBACK_MAP = new ConcurrentHashMap<>();
+ private static final Map BLOCK_HANDLER_MAP = new ConcurrentHashMap<>();
+
+ static Method lookupFallback(Class> clazz, String name) {
+ return FALLBACK_MAP.get(getKey(clazz, name));
+ }
+
+ static Method lookupBlockHandler(Class> clazz, String name) {
+ return BLOCK_HANDLER_MAP.get(getKey(clazz, name));
+ }
+
+ static void updateFallbackFor(Class> clazz, String name, Method method) {
+ if (clazz == null || StringUtil.isBlank(name)) {
+ throw new IllegalArgumentException("Bad argument");
+ }
+ FALLBACK_MAP.put(getKey(clazz, name), method);
+ }
+
+ static void updateBlockHandlerFor(Class> clazz, String name, Method method) {
+ if (clazz == null || StringUtil.isBlank(name)) {
+ throw new IllegalArgumentException("Bad argument");
+ }
+ BLOCK_HANDLER_MAP.put(getKey(clazz, name), method);
+ }
+
+ private static String getKey(Class> clazz, String name) {
+ return String.format("%s:%s", clazz.getCanonicalName(), name);
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/EnableSentinel.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/EnableSentinel.java
deleted file mode 100644
index c85bb274c..000000000
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/EnableSentinel.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.alibaba.sentinel.custom;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation to add Sentinel to custom method
- * @author xiaojing
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface EnableSentinel {
-
- /**
- * @return sentinel resource value
- */
- String value();
-
- /**
- * @return Sentinel BlockException Handler name
- */
- String handler() default "";
-}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/HandlerUtil.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/HandlerUtil.java
deleted file mode 100644
index 167af1917..000000000
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/HandlerUtil.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2018 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.alibaba.sentinel.custom;
-
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * @author xiaojing
- */
-public class HandlerUtil {
-
- private static final ConcurrentHashMap map = new ConcurrentHashMap<>(
- 16);
-
- /**
- * you should add your custom handler before use it
- * @param name see {@link EnableSentinel#handler()}
- * @param handler you custom handler
- */
- public static void addHandler(String name, SentinelBlockHandler handler) {
- map.put(name, handler);
- }
-
- public static SentinelBlockHandler getHandler(String name) {
- SentinelBlockHandler handler = map.get(name);
- if (null == handler) {
- throw new RuntimeException("cannot find handler name=<" + name
- + ",> did you forgot to invoke HandlerUtil.addHandler(name, handler) ?");
- }
- return handler;
- }
-}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAspect.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAspect.java
deleted file mode 100644
index fb923c5d5..000000000
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAspect.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2018 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.alibaba.sentinel.custom;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
-import com.alibaba.csp.sentinel.Entry;
-import com.alibaba.csp.sentinel.SphU;
-import com.alibaba.csp.sentinel.context.ContextUtil;
-import com.alibaba.csp.sentinel.slots.block.BlockException;
-
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @author xiaojing
- */
-@Aspect
-public class SentinelAspect {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(SentinelAspect.class);
-
- @Around("@annotation(org.springframework.cloud.alibaba.sentinel.custom.EnableSentinel)")
- public Object customBlock(ProceedingJoinPoint pjp) throws Throwable {
- SentinelEntry sentinelEntry = new SentinelEntry();
- try {
- beforeProceed(sentinelEntry, pjp);
- return pjp.proceed();
- }
- catch (BlockException e) {
- LOGGER.error(e.getMessage(), e);
- if (null != sentinelEntry.getHandler()
- && sentinelEntry.getHandler().length() > 0) {
- return HandlerUtil.getHandler(sentinelEntry.getHandler()).handler(e);
- }
- else {
- throw e;
- }
- }
- finally {
- releaseContextResources(sentinelEntry);
- }
- }
-
- private void beforeProceed(SentinelEntry sentinelEntry, ProceedingJoinPoint pjp)
- throws BlockException {
- Method method = getMethod(pjp);
-
- int modifiers = method.getModifiers();
-
- if (!Modifier.isPublic(modifiers) || "toString".equals(method.getName())
- || "hashCode".equals(method.getName())
- || "equals".equals(method.getName())
- || "finalize".equals(method.getName())) {
- return;
- }
-
- Annotation[] annotations = method.getDeclaredAnnotations();
- for (Annotation annotation : annotations) {
- if (annotation instanceof EnableSentinel) {
- sentinelEntry.setKey(((EnableSentinel) annotation).value());
- sentinelEntry.setHandler(((EnableSentinel) annotation).handler());
- }
- }
- if (null == sentinelEntry.getKey() || sentinelEntry.getKey().length() == 0) {
- return;
- }
-
- ContextUtil.enter(sentinelEntry.getKey());
- sentinelEntry.setEntry(SphU.entry(sentinelEntry.getKey()));
- }
-
- private void releaseContextResources(SentinelEntry sentinelEntry) {
-
- if (null == sentinelEntry.getEntry()) {
- return;
- }
-
- Entry entry = sentinelEntry.getEntry();
- entry.exit();
- ContextUtil.exit();
- }
-
- private Method getMethod(ProceedingJoinPoint joinPoint) {
- MethodSignature signature = (MethodSignature) joinPoint.getSignature();
- return signature.getMethod();
- }
-
-}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java
new file mode 100644
index 000000000..7d2a2e10a
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.sentinel.custom;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
+
+/**
+ * @author xiaojing
+ */
+@Configuration
+public class SentinelAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SentinelResourceAspect sentinelResourceAspect() {
+ return new SentinelResourceAspect();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnClass(value = RestTemplate.class)
+ public SentinelBeanPostProcessor sentinelBeanPostProcessor() {
+ return new SentinelBeanPostProcessor();
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java
new file mode 100644
index 000000000..2d95c06c4
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.sentinel.custom;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.type.StandardMethodMetadata;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * PostProcessor handle @SentinelProtect Annotation, add interceptor for RestTemplate
+ *
+ * @author fangjian
+ * @see SentinelProtect
+ * @see SentinelProtectInterceptor
+ */
+public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ private ConcurrentHashMap cache = new ConcurrentHashMap<>();
+
+ @Override
+ public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
+ Class> beanType, String beanName) {
+ if (checkSentinelProtect(beanDefinition, beanType)) {
+ SentinelProtect sentinelProtect = ((StandardMethodMetadata) beanDefinition
+ .getSource()).getIntrospectedMethod()
+ .getAnnotation(SentinelProtect.class);
+ cache.put(beanName, sentinelProtect);
+ }
+ }
+
+ private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
+ Class> beanType) {
+ return beanType == RestTemplate.class
+ && beanDefinition.getSource() instanceof StandardMethodMetadata
+ && ((StandardMethodMetadata) beanDefinition.getSource())
+ .isAnnotated(SentinelProtect.class.getName());
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ if (cache.containsKey(beanName)) {
+ // add interceptor for each RestTemplate with @SentinelProtect annotation
+ StringBuilder interceptorBeanName = new StringBuilder();
+ SentinelProtect sentinelProtect = cache.get(beanName);
+ interceptorBeanName
+ .append(StringUtils.uncapitalize(
+ SentinelProtectInterceptor.class.getSimpleName()))
+ .append("_")
+ .append(sentinelProtect.blockHandlerClass().getSimpleName())
+ .append(sentinelProtect.blockHandler()).append("_")
+ .append(sentinelProtect.fallbackClass().getSimpleName())
+ .append(sentinelProtect.fallback());
+ RestTemplate restTemplate = (RestTemplate) bean;
+ registerBean(interceptorBeanName.toString(), sentinelProtect);
+ SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
+ .getBean(interceptorBeanName.toString(),
+ SentinelProtectInterceptor.class);
+ restTemplate.getInterceptors().add(sentinelProtectInterceptor);
+ }
+ return bean;
+ }
+
+ private void registerBean(String interceptorBeanName,
+ SentinelProtect sentinelProtect) {
+ // register SentinelProtectInterceptor bean
+ DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
+ .getAutowireCapableBeanFactory();
+ BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(SentinelProtectInterceptor.class);
+ beanDefinitionBuilder.addConstructorArgValue(sentinelProtect);
+ BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
+ .getRawBeanDefinition();
+ beanFactory.registerBeanDefinition(interceptorBeanName,
+ interceptorBeanDefinition);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBlockHandler.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBlockHandler.java
deleted file mode 100644
index 3b7201fed..000000000
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBlockHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2018 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.alibaba.sentinel.custom;
-
-import com.alibaba.csp.sentinel.slots.block.BlockException;
-
-/**
- * Sentinel Block Handler
- * @author xiaojing
- */
-public interface SentinelBlockHandler {
-
- /**
- * custom method to process BlockException
- * @param e block exception when blocked by sentinel
- * @return Object result processed by the handler
- */
- Object handler(BlockException e);
-
-}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelEntry.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelEntry.java
deleted file mode 100644
index fdc4f3bf6..000000000
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelEntry.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.alibaba.sentinel.custom;
-
-import com.alibaba.csp.sentinel.Entry;
-
-/**
- * @author xiaojing
- */
-public class SentinelEntry {
-
- private String key;
- private String handler;
-
- private Entry entry;
-
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public String getHandler() {
- return handler;
- }
-
- public void setHandler(String handler) {
- this.handler = handler;
- }
-
- public Entry getEntry() {
- return entry;
- }
-
- public void setEntry(Entry entry) {
- this.entry = entry;
- }
-}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java
new file mode 100644
index 000000000..2d2c9ba45
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.sentinel.custom;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.URI;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.util.ClassUtils;
+
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.SphU;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+/**
+ * Interceptor using by SentinelProtect and SentinelProtectInterceptor
+ *
+ * @author fangjian
+ */
+public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
+
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(SentinelProtectInterceptor.class);
+
+ private SentinelProtect sentinelProtect;
+
+ public SentinelProtectInterceptor(SentinelProtect sentinelProtect) {
+ this.sentinelProtect = sentinelProtect;
+ }
+
+ @Override
+ 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 hostWithPathResource = hostResource + uri.getPath();
+ Entry hostEntry = null, hostWithPathEntry = null;
+ ClientHttpResponse response = null;
+ try {
+ ContextUtil.enter(hostWithPathResource);
+ hostWithPathEntry = SphU.entry(hostWithPathResource);
+ hostEntry = SphU.entry(hostResource);
+ response = execution.execute(request, body);
+ }
+ catch (BlockException e) {
+ LOGGER.error("RestTemplate block", e);
+ try {
+ handleBlockException(e);
+ }
+ catch (Exception ex) {
+ LOGGER.error("sentinel handle BlockException error.", e);
+ }
+ }
+ finally {
+ if (hostEntry != null) {
+ hostEntry.exit();
+ }
+ if (hostWithPathEntry != null) {
+ hostWithPathEntry.exit();
+ }
+ ContextUtil.exit();
+ }
+ return response;
+ }
+
+ private void handleBlockException(BlockException ex) throws Exception {
+ Object[] args = new Object[] { ex };
+ // handle degrade
+ if (isDegradeFailure(ex)) {
+ Method method = extractFallbackMethod(sentinelProtect.fallback(),
+ sentinelProtect.fallbackClass());
+ if (method != null) {
+ method.invoke(null, args);
+ }
+ }
+ // handle block
+ Method blockHandler = extractBlockHandlerMethod(sentinelProtect.blockHandler(),
+ sentinelProtect.blockHandlerClass());
+ if (blockHandler != null) {
+ blockHandler.invoke(null, args);
+ }
+ }
+
+ private Method extractFallbackMethod(String fallback, Class> fallbackClass) {
+ if (StringUtil.isBlank(fallback) || fallbackClass == void.class) {
+ return null;
+ }
+ Method cachedMethod = BlockClassRegistry.lookupFallback(fallbackClass, fallback);
+ if (cachedMethod == null) {
+ cachedMethod = ClassUtils.getStaticMethod(fallbackClass, fallback,
+ BlockException.class);
+ BlockClassRegistry.updateFallbackFor(fallbackClass, fallback, cachedMethod);
+ }
+ return cachedMethod;
+ }
+
+ private Method extractBlockHandlerMethod(String block, Class> blockClass) {
+ if (StringUtil.isBlank(block) || blockClass == void.class) {
+ return null;
+ }
+ Method cachedMethod = BlockClassRegistry.lookupBlockHandler(blockClass, block);
+ if (cachedMethod == null) {
+ cachedMethod = ClassUtils.getStaticMethod(blockClass, block,
+ BlockException.class);
+ BlockClassRegistry.updateBlockHandlerFor(blockClass, block, cachedMethod);
+ }
+ return cachedMethod;
+ }
+
+ private boolean isDegradeFailure(BlockException ex) {
+ return ex instanceof DegradeException;
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/spring.factories
index f9b510b64..ae146be44 100644
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.sentinel.SentinelWebAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
-org.springframework.cloud.alibaba.sentinel.custom.SentinelCustomAspectAutoConfiguration
+org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration
diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java b/spring-cloud-alibaba-sentinel-autoconfigure/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java
index 10608c535..29fbc8ee2 100644
--- a/spring-cloud-alibaba-sentinel-autoconfigure/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java
+++ b/spring-cloud-alibaba-sentinel-autoconfigure/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java
@@ -16,51 +16,98 @@
package org.springframework.cloud.alibaba.sentinel;
+import static org.assertj.core.api.Assertions.assertThat;
+
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.cloud.alibaba.sentinel.custom.SentinelAspect;
-import org.springframework.cloud.alibaba.sentinel.custom.SentinelCustomAspectAutoConfiguration;
-
-import static org.assertj.core.api.Assertions.assertThat;
+import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect;
+import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration;
+import org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor;
+import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
/**
* @author fangjian
*/
public class SentinelAutoConfigurationTests {
- private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
- .withConfiguration(
- AutoConfigurations.of(SentinelCustomAspectAutoConfiguration.class, SentinelWebAutoConfiguration.class))
- .withPropertyValues("spring.cloud.sentinel.port=8888")
- .withPropertyValues("spring.cloud.sentinel.filter.order=123")
- .withPropertyValues("spring.cloud.sentinel.filter.urlPatterns=/*,/test");
-
- @Test
- public void testSentinelAspect() {
- this.contextRunner.run(context -> assertThat(context).hasSingleBean(SentinelAspect.class));
- }
-
- @Test
- public void testFilter() {
- this.contextRunner.run(context -> {
- assertThat(context.getBean(
- "servletRequestListener").getClass() == FilterRegistrationBean.class).isTrue();
- });
- }
-
- @Test
- public void testProperties() {
- this.contextRunner.run(context -> {
- SentinelProperties sentinelProperties = context.getBean(SentinelProperties.class);
- assertThat(sentinelProperties.getPort()).isEqualTo("8888");
- assertThat(sentinelProperties.getFilter().getUrlPatterns().size()).isEqualTo(2);
- assertThat(sentinelProperties.getFilter().getUrlPatterns().get(0)).isEqualTo("/*");
- assertThat(sentinelProperties.getFilter().getUrlPatterns().get(1)).isEqualTo("/test");
- });
- }
+ private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
+ .withConfiguration(AutoConfigurations.of(SentinelAutoConfiguration.class,
+ SentinelWebAutoConfiguration.class, SentinelTestConfiguration.class))
+ .withPropertyValues("spring.cloud.sentinel.port=8888")
+ .withPropertyValues("spring.cloud.sentinel.filter.order=123")
+ .withPropertyValues("spring.cloud.sentinel.filter.urlPatterns=/*,/test");
+
+ @Test
+ public void testFilter() {
+ this.contextRunner.run(context -> {
+ assertThat(context.getBean("servletRequestListener")
+ .getClass() == FilterRegistrationBean.class).isTrue();
+ });
+ }
+
+ @Test
+ public void testBeanPostProcessor() {
+ this.contextRunner.run(context -> {
+ assertThat(context.getBean("sentinelBeanPostProcessor")
+ .getClass() == SentinelBeanPostProcessor.class).isTrue();
+ });
+ }
+
+ @Test
+ public void testProperties() {
+ this.contextRunner.run(context -> {
+ SentinelProperties sentinelProperties = context
+ .getBean(SentinelProperties.class);
+ assertThat(sentinelProperties.getPort()).isEqualTo("8888");
+ assertThat(sentinelProperties.getFilter().getUrlPatterns().size())
+ .isEqualTo(2);
+ assertThat(sentinelProperties.getFilter().getUrlPatterns().get(0))
+ .isEqualTo("/*");
+ assertThat(sentinelProperties.getFilter().getUrlPatterns().get(1))
+ .isEqualTo("/test");
+ });
+ }
+
+ @Test
+ public void testRestTemplate() {
+ this.contextRunner.run(context -> {
+ assertThat(context.getBeansOfType(RestTemplate.class).size()).isEqualTo(2);
+ RestTemplate restTemplate = context.getBean("restTemplateWithBlockClass",
+ RestTemplate.class);
+ assertThat(restTemplate.getInterceptors().size()).isEqualTo(1);
+ assertThat(restTemplate.getInterceptors().get(0).getClass())
+ .isEqualTo(SentinelProtectInterceptor.class);
+ });
+ }
+
+ @Configuration
+ static class SentinelTestConfiguration {
+
+ @Bean
+ @SentinelProtect
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ @Bean
+ @SentinelProtect(blockHandlerClass = ExceptionUtil.class, blockHandler = "handleException")
+ RestTemplate restTemplateWithBlockClass() {
+ return new RestTemplate();
+ }
+
+ }
+ static class ExceptionUtil {
+ public static void handleException(BlockException ex) {
+ System.out.println("Oops: " + ex.getClass().getCanonicalName());
+ }
+ }
}