cache = new ConcurrentHashMap<>();
@@ -60,10 +75,74 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
sentinelRestTemplate = beanDefinition.getResolvedFactoryMethod()
.getAnnotation(SentinelRestTemplate.class);
}
+ // check class and method validation
+ checkSentinelRestTemplate(sentinelRestTemplate, beanName);
cache.put(beanName, sentinelRestTemplate);
}
}
+ private void checkSentinelRestTemplate(SentinelRestTemplate sentinelRestTemplate,
+ String beanName) {
+ checkBlock4RestTemplate(sentinelRestTemplate.blockHandlerClass(),
+ sentinelRestTemplate.blockHandler(), beanName,
+ SentinelConstants.BLOCK_TYPE);
+ checkBlock4RestTemplate(sentinelRestTemplate.fallbackClass(),
+ sentinelRestTemplate.fallback(), beanName,
+ SentinelConstants.FALLBACK_TYPE);
+ }
+
+ private void checkBlock4RestTemplate(Class> blockClass, String blockMethod,
+ String beanName, String type) {
+ if (blockClass == void.class && StringUtils.isEmpty(blockMethod)) {
+ return;
+ }
+ if (blockClass != void.class && StringUtils.isEmpty(blockMethod)) {
+ logger.error(
+ "{} class attribute exists but {} method attribute is not exists in bean[{}]",
+ type, type, beanName);
+ throw new IllegalArgumentException(type + " class attribute exists but "
+ + type + " method attribute is not exists in bean[" + beanName + "]");
+ }
+ else if (blockClass == void.class && !StringUtils.isEmpty(blockMethod)) {
+ logger.error(
+ "{} method attribute exists but {} class attribute is not exists in bean[{}]",
+ type, type, beanName);
+ throw new IllegalArgumentException(type + " method attribute exists but "
+ + type + " class attribute is not exists in bean[" + beanName + "]");
+ }
+ Class[] args = new Class[] { HttpRequest.class, byte[].class,
+ ClientHttpRequestExecution.class, BlockException.class };
+ String argsStr = Arrays.toString(
+ Arrays.stream(args).map(clazz -> clazz.getSimpleName()).toArray());
+ Method foundMethod = ClassUtils.getStaticMethod(blockClass, blockMethod, args);
+ if (foundMethod == null) {
+ logger.error(
+ "{} static method can not be found in bean[{}]. The right method signature is {}#{}{}, please check your class name, method name and arguments",
+ type, beanName, blockClass.getName(), blockMethod, argsStr);
+ throw new IllegalArgumentException(type
+ + " static method can not be found in bean[" + beanName
+ + "]. The right method signature is " + blockClass.getName() + "#"
+ + blockMethod + argsStr
+ + ", please check your class name, method name and arguments");
+ }
+
+ if (!ClientHttpResponse.class.isAssignableFrom(foundMethod.getReturnType())) {
+ logger.error(
+ "{} method return value in bean[{}] is not ClientHttpResponse: {}#{}{}",
+ type, beanName, blockClass.getName(), blockMethod, argsStr);
+ throw new IllegalArgumentException(type + " method return value in bean["
+ + beanName + "] is not ClientHttpResponse: " + blockClass.getName()
+ + "#" + blockMethod + argsStr);
+ }
+ if (type.equals(SentinelConstants.BLOCK_TYPE)) {
+ BlockClassRegistry.updateBlockHandlerFor(blockClass, blockMethod,
+ foundMethod);
+ }
+ else {
+ BlockClassRegistry.updateFallbackFor(blockClass, blockMethod, foundMethod);
+ }
+ }
+
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
Class> beanType) {
return beanType == RestTemplate.class
@@ -103,7 +182,7 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
.getBean(interceptorBeanName.toString(),
SentinelProtectInterceptor.class);
- restTemplate.getInterceptors().add(sentinelProtectInterceptor);
+ restTemplate.getInterceptors().add(0, sentinelProtectInterceptor);
}
return bean;
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelCircuitBreakerConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelCircuitBreakerConfiguration.java
new file mode 100644
index 00000000..f8d61034
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelCircuitBreakerConfiguration.java
@@ -0,0 +1,12 @@
+package org.springframework.cloud.alibaba.sentinel.custom;
+
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author lengleng
+ *
+ * support @EnableCircuitBreaker ,Do nothing
+ */
+@Configuration
+public class SentinelCircuitBreakerConfiguration {
+}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java
index f9776d27..6b3e6e8b 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java
@@ -1,21 +1,16 @@
package org.springframework.cloud.alibaba.sentinel.custom;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.TreeMap;
-
+import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
+import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
+import com.alibaba.csp.sentinel.slots.block.AbstractRule;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.cloud.alibaba.sentinel.SentinelConstants;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants;
@@ -24,16 +19,17 @@ import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePr
import org.springframework.cloud.alibaba.sentinel.datasource.config.NacosDataSourceProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
-import org.springframework.context.event.EventListener;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
-import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
-import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
-import com.alibaba.csp.sentinel.slots.block.AbstractRule;
-import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
-import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
/**
* Sentinel {@link ReadableDataSource} Handler Handle the configurations of
@@ -44,29 +40,28 @@ import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
* @see JsonConverter
* @see XmlConverter
*/
-public class SentinelDataSourceHandler {
+public class SentinelDataSourceHandler implements SmartInitializingSingleton {
private static final Logger logger = LoggerFactory
.getLogger(SentinelDataSourceHandler.class);
private List dataTypeList = Arrays.asList("json", "xml");
- private List dataSourceBeanNameList = Collections
- .synchronizedList(new ArrayList<>());
+ private final String DATA_TYPE_FIELD = "dataType";
+ private final String CUSTOM_DATA_TYPE = "custom";
+ private final String CONVERTER_CLASS_FIELD = "converterClass";
- private final String DATATYPE_FIELD = "dataType";
- private final String CUSTOM_DATATYPE = "custom";
- private final String CONVERTERCLASS_FIELD = "converterClass";
+ private final DefaultListableBeanFactory beanFactory;
+
+ public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
@Autowired
private SentinelProperties sentinelProperties;
- @EventListener(classes = ApplicationStartedEvent.class)
- public void buildDataSource(ApplicationStartedEvent event) throws Exception {
-
- DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) event
- .getApplicationContext().getAutowireCapableBeanFactory();
-
+ @Override
+ public void afterSingletonsInstantiated() {
// commercialization
if (!StringUtils.isEmpty(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) {
@@ -101,9 +96,8 @@ public class SentinelDataSourceHandler {
AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties
.getValidDataSourceProperties();
abstractDataSourceProperties.preCheck(dataSourceName);
- registerBean(beanFactory, abstractDataSourceProperties,
- dataSourceName + "-sentinel-" + validFields.get(0)
- + "-datasource");
+ registerBean(abstractDataSourceProperties, dataSourceName
+ + "-sentinel-" + validFields.get(0) + "-datasource");
}
catch (Exception e) {
logger.error("[Sentinel Starter] DataSource " + dataSourceName
@@ -112,8 +106,7 @@ public class SentinelDataSourceHandler {
});
}
- private void registerBean(DefaultListableBeanFactory beanFactory,
- final AbstractDataSourceProperties dataSourceProperties,
+ private void registerBean(final AbstractDataSourceProperties dataSourceProperties,
String dataSourceName) {
Map propertyMap = Arrays
@@ -132,8 +125,8 @@ public class SentinelDataSourceHandler {
e);
}
}, HashMap::putAll);
- propertyMap.put(CONVERTERCLASS_FIELD, dataSourceProperties.getConverterClass());
- propertyMap.put(DATATYPE_FIELD, dataSourceProperties.getDataType());
+ propertyMap.put(CONVERTER_CLASS_FIELD, dataSourceProperties.getConverterClass());
+ propertyMap.put(DATA_TYPE_FIELD, dataSourceProperties.getDataType());
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(dataSourceProperties.getFactoryBeanName());
@@ -141,81 +134,78 @@ public class SentinelDataSourceHandler {
propertyMap.forEach((propertyName, propertyValue) -> {
Field field = ReflectionUtils.findField(dataSourceProperties.getClass(),
propertyName);
- if (field != null) {
- if (DATATYPE_FIELD.equals(propertyName)) {
- String dataType = StringUtils
- .trimAllWhitespace(propertyValue.toString());
- if (CUSTOM_DATATYPE.equals(dataType)) {
- try {
- if (StringUtils
- .isEmpty(dataSourceProperties.getConverterClass())) {
- throw new RuntimeException(
- "[Sentinel Starter] DataSource " + dataSourceName
- + "dataType is custom, please set converter-class "
- + "property");
- }
- // construct custom Converter with 'converterClass'
- // configuration and register
- String customConvertBeanName = "sentinel-"
- + dataSourceProperties.getConverterClass();
- if (!beanFactory.containsBean(customConvertBeanName)) {
- beanFactory.registerBeanDefinition(customConvertBeanName,
- BeanDefinitionBuilder
- .genericBeanDefinition(
- Class.forName(dataSourceProperties
- .getConverterClass()))
- .getBeanDefinition());
- }
- builder.addPropertyReference("converter",
- customConvertBeanName);
- }
- catch (ClassNotFoundException e) {
- logger.error("[Sentinel Starter] DataSource " + dataSourceName
- + " handle "
- + dataSourceProperties.getClass().getSimpleName()
- + " error, class name: "
- + dataSourceProperties.getConverterClass());
- throw new RuntimeException(
- "[Sentinel Starter] DataSource " + dataSourceName
- + " handle "
- + dataSourceProperties.getClass()
- .getSimpleName()
- + " error, class name: "
- + dataSourceProperties.getConverterClass(),
- e);
- }
- }
- else {
- if (!dataTypeList.contains(StringUtils
- .trimAllWhitespace(propertyValue.toString()))) {
+ if (null == field) {
+ return;
+ }
+ if (DATA_TYPE_FIELD.equals(propertyName)) {
+ String dataType = StringUtils.trimAllWhitespace(propertyValue.toString());
+ if (CUSTOM_DATA_TYPE.equals(dataType)) {
+ try {
+ if (StringUtils
+ .isEmpty(dataSourceProperties.getConverterClass())) {
throw new RuntimeException("[Sentinel Starter] DataSource "
- + dataSourceName + " dataType: " + propertyValue
- + " is not support now. please using these types: "
- + dataTypeList.toString());
+ + dataSourceName
+ + "dataType is custom, please set converter-class "
+ + "property");
}
- // converter type now support xml or json.
- // The bean name of these converters wrapped by
- // 'sentinel-{converterType}-{ruleType}-converter'
- builder.addPropertyReference("converter",
- "sentinel-" + propertyValue.toString() + "-"
- + dataSourceProperties.getRuleType().getName()
- + "-converter");
+ // construct custom Converter with 'converterClass'
+ // configuration and register
+ String customConvertBeanName = "sentinel-"
+ + dataSourceProperties.getConverterClass();
+ if (!this.beanFactory.containsBean(customConvertBeanName)) {
+ this.beanFactory.registerBeanDefinition(customConvertBeanName,
+ BeanDefinitionBuilder
+ .genericBeanDefinition(
+ Class.forName(dataSourceProperties
+ .getConverterClass()))
+ .getBeanDefinition());
+ }
+ builder.addPropertyReference("converter", customConvertBeanName);
+ }
+ catch (ClassNotFoundException e) {
+ logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ + " handle "
+ + dataSourceProperties.getClass().getSimpleName()
+ + " error, class name: "
+ + dataSourceProperties.getConverterClass());
+ throw new RuntimeException("[Sentinel Starter] DataSource "
+ + dataSourceName + " handle "
+ + dataSourceProperties.getClass().getSimpleName()
+ + " error, class name: "
+ + dataSourceProperties.getConverterClass(), e);
}
- }
- else if (CONVERTERCLASS_FIELD.equals(propertyName)) {
- return;
}
else {
- // wired properties
- Optional.ofNullable(propertyValue)
- .ifPresent(v -> builder.addPropertyValue(propertyName, v));
+ if (!dataTypeList.contains(
+ StringUtils.trimAllWhitespace(propertyValue.toString()))) {
+ throw new RuntimeException("[Sentinel Starter] DataSource "
+ + dataSourceName + " dataType: " + propertyValue
+ + " is not support now. please using these types: "
+ + dataTypeList.toString());
+ }
+ // converter type now support xml or json.
+ // The bean name of these converters wrapped by
+ // 'sentinel-{converterType}-{ruleType}-converter'
+ builder.addPropertyReference("converter",
+ "sentinel-" + propertyValue.toString() + "-"
+ + dataSourceProperties.getRuleType().getName()
+ + "-converter");
}
}
+ else if (CONVERTER_CLASS_FIELD.equals(propertyName)) {
+ return;
+ }
+ else {
+ // wired properties
+ Optional.ofNullable(propertyValue)
+ .ifPresent(v -> builder.addPropertyValue(propertyName, v));
+ }
});
- beanFactory.registerBeanDefinition(dataSourceName, builder.getBeanDefinition());
+ this.beanFactory.registerBeanDefinition(dataSourceName,
+ builder.getBeanDefinition());
// init in Spring
- AbstractDataSource newDataSource = (AbstractDataSource) beanFactory
+ AbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory
.getBean(dataSourceName);
logAndCheckRuleType(newDataSource, dataSourceName,
@@ -234,7 +224,6 @@ public class SentinelDataSourceHandler {
DegradeRuleManager.register2Property(newDataSource.getProperty());
}
}
- dataSourceBeanNameList.add(dataSourceName);
}
private void logAndCheckRuleType(AbstractDataSource dataSource, String dataSourceName,
@@ -282,9 +271,4 @@ public class SentinelDataSourceHandler {
+ ruleClass.getSimpleName() + ">. Class: " + ruleConfig.getClass());
}
}
-
- public List getDataSourceBeanNameList() {
- return dataSourceBeanNameList;
- }
-
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java
index a1ab9e22..a6dcb3c0 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java
@@ -16,11 +16,12 @@
package org.springframework.cloud.alibaba.sentinel.custom;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.util.Arrays;
-
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.SphU;
+import com.alibaba.csp.sentinel.Tracer;
+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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
@@ -29,27 +30,23 @@ 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.Tracer;
-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;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
/**
* Interceptor using by SentinelRestTemplate
*
- * @author fangjian
+ * @author Jim
*/
public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory
.getLogger(SentinelProtectInterceptor.class);
- private SentinelRestTemplate sentinelRestTemplate;
+ private final SentinelRestTemplate sentinelRestTemplate;
public SentinelProtectInterceptor(SentinelRestTemplate sentinelRestTemplate) {
this.sentinelRestTemplate = sentinelRestTemplate;
@@ -82,18 +79,7 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
throw new IllegalStateException(e);
}
else {
- try {
- return handleBlockException(request, body, execution,
- (BlockException) e);
- }
- catch (Exception ex) {
- if (ex instanceof IllegalStateException) {
- throw (IllegalStateException) ex;
- }
- throw new IllegalStateException(
- "sentinel handle BlockException error: " + ex.getMessage(),
- ex);
- }
+ return handleBlockException(request, body, execution, (BlockException) e);
}
}
finally {
@@ -109,84 +95,49 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
}
private ClientHttpResponse handleBlockException(HttpRequest request, byte[] body,
- ClientHttpRequestExecution execution, BlockException ex) throws Exception {
+ ClientHttpRequestExecution execution, BlockException ex) {
Object[] args = new Object[] { request, body, execution, ex };
// handle degrade
if (isDegradeFailure(ex)) {
- Method method = extractFallbackMethod(sentinelRestTemplate.fallback(),
+ Method fallbackMethod = extractFallbackMethod(sentinelRestTemplate.fallback(),
sentinelRestTemplate.fallbackClass());
- if (method != null) {
- return (ClientHttpResponse) method.invoke(null, args);
+ if (fallbackMethod != null) {
+ return methodInvoke(fallbackMethod, args);
}
else {
return new SentinelClientHttpResponse();
}
}
- // handle block
+ // handle flow
Method blockHandler = extractBlockHandlerMethod(
sentinelRestTemplate.blockHandler(),
sentinelRestTemplate.blockHandlerClass());
if (blockHandler != null) {
- return (ClientHttpResponse) blockHandler.invoke(null, args);
+ return methodInvoke(blockHandler, args);
}
else {
return new SentinelClientHttpResponse();
}
}
+ private ClientHttpResponse methodInvoke(Method method, Object... args) {
+ try {
+ return (ClientHttpResponse) method.invoke(null, args);
+ }
+ catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private Method extractFallbackMethod(String fallback, Class> fallbackClass) {
- if (StringUtil.isBlank(fallback) || fallbackClass == void.class) {
- return null;
- }
- Method cachedMethod = BlockClassRegistry.lookupFallback(fallbackClass, fallback);
- Class[] args = new Class[] { HttpRequest.class, byte[].class,
- ClientHttpRequestExecution.class, BlockException.class };
- if (cachedMethod == null) {
- cachedMethod = ClassUtils.getStaticMethod(fallbackClass, fallback, args);
- if (cachedMethod != null) {
- if (!ClientHttpResponse.class
- .isAssignableFrom(cachedMethod.getReturnType())) {
- throw new IllegalStateException(String.format(
- "the return type of method [%s] in class [%s] is not ClientHttpResponse in degrade",
- cachedMethod.getName(), fallbackClass.getCanonicalName()));
- }
- BlockClassRegistry.updateFallbackFor(fallbackClass, fallback,
- cachedMethod);
- }
- else {
- throw new IllegalStateException(String.format(
- "Cannot find method [%s] in class [%s] with parameters %s in degrade",
- fallback, fallbackClass.getCanonicalName(), Arrays.asList(args)));
- }
- }
- return cachedMethod;
+ return BlockClassRegistry.lookupFallback(fallbackClass, fallback);
}
private Method extractBlockHandlerMethod(String block, Class> blockClass) {
- if (StringUtil.isBlank(block) || blockClass == void.class) {
- return null;
- }
- Method cachedMethod = BlockClassRegistry.lookupBlockHandler(blockClass, block);
- Class[] args = new Class[] { HttpRequest.class, byte[].class,
- ClientHttpRequestExecution.class, BlockException.class };
- if (cachedMethod == null) {
- cachedMethod = ClassUtils.getStaticMethod(blockClass, block, args);
- if (cachedMethod != null) {
- if (!ClientHttpResponse.class
- .isAssignableFrom(cachedMethod.getReturnType())) {
- throw new IllegalStateException(String.format(
- "the return type of method [%s] in class [%s] is not ClientHttpResponse in flow control",
- cachedMethod.getName(), blockClass.getCanonicalName()));
- }
- BlockClassRegistry.updateBlockHandlerFor(blockClass, block, cachedMethod);
- }
- else {
- throw new IllegalStateException(String.format(
- "Cannot find method [%s] in class [%s] with parameters %s in flow control",
- block, blockClass.getCanonicalName(), Arrays.asList(args)));
- }
- }
- return cachedMethod;
+ return BlockClassRegistry.lookupBlockHandler(blockClass, block);
}
private boolean isDegradeFailure(BlockException ex) {
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java
index 03b6c0f8..f42898bc 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java
@@ -16,26 +16,21 @@
package org.springframework.cloud.alibaba.sentinel.endpoint;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.springframework.beans.factory.annotation.Autowired;
+import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.log.LogBase;
+import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
+import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
-import org.springframework.cloud.alibaba.sentinel.custom.SentinelDataSourceHandler;
-import org.springframework.context.ApplicationContext;
-import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
-import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
-import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
-import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
-import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
-import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
-import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
-import com.alibaba.csp.sentinel.slots.system.SystemRule;
-import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
+import java.util.HashMap;
+import java.util.Map;
/**
* Endpoint for Sentinel, contains ans properties and rules
@@ -44,43 +39,39 @@ import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
@Endpoint(id = "sentinel")
public class SentinelEndpoint {
- @Autowired
- private SentinelProperties sentinelProperties;
+ private final SentinelProperties sentinelProperties;
- @Autowired
- private SentinelDataSourceHandler dataSourceHandler;
-
- @Autowired
- private ApplicationContext applicationContext;
+ public SentinelEndpoint(SentinelProperties sentinelProperties) {
+ this.sentinelProperties = sentinelProperties;
+ }
@ReadOperation
public Map invoke() {
final Map result = new HashMap<>();
+ if (sentinelProperties.isEnabled()) {
- List flowRules = FlowRuleManager.getRules();
- List degradeRules = DegradeRuleManager.getRules();
- List systemRules = SystemRuleManager.getRules();
- List paramFlowRules = ParamFlowRuleManager.getRules();
- result.put("properties", sentinelProperties);
- result.put("FlowRules", flowRules);
- result.put("DegradeRules", degradeRules);
- result.put("SystemRules", systemRules);
- result.put("ParamFlowRule", paramFlowRules);
- result.put("datasources", new HashMap());
- dataSourceHandler.getDataSourceBeanNameList().forEach(dataSourceBeanName -> {
- ReadableDataSource dataSource = applicationContext.getBean(dataSourceBeanName,
- ReadableDataSource.class);
- try {
- ((HashMap) result.get("datasources")).put(dataSourceBeanName,
- dataSource.loadConfig());
- }
- catch (Exception e) {
- ((HashMap) result.get("datasources")).put(dataSourceBeanName,
- "load error: " + e.getMessage());
- }
-
- });
+ result.put("logDir", LogBase.getLogBaseDir());
+ result.put("logUsePid", LogBase.isLogNameUsePid());
+ result.put("blockPage", WebServletConfig.getBlockPage());
+ result.put("metricsFileSize", SentinelConfig.singleMetricFileSize());
+ result.put("metricsFileCharset", SentinelConfig.charset());
+ result.put("totalMetricsFileCount", SentinelConfig.totalMetricFileCount());
+ result.put("consoleServer", TransportConfig.getConsoleServer());
+ result.put("clientIp", TransportConfig.getHeartbeatClientIp());
+ result.put("heartbeatIntervalMs", TransportConfig.getHeartbeatIntervalMs());
+ result.put("clientPort", TransportConfig.getPort());
+ result.put("coldFactor", sentinelProperties.getFlow().getColdFactor());
+ result.put("filter", sentinelProperties.getFilter());
+ result.put("datasource", sentinelProperties.getDatasource());
+ final Map rules = new HashMap<>();
+ result.put("rules", rules);
+ rules.put("flowRules", FlowRuleManager.getRules());
+ rules.put("degradeRules", DegradeRuleManager.getRules());
+ rules.put("systemRules", SystemRuleManager.getRules());
+ rules.put("authorityRule", AuthorityRuleManager.getRules());
+ rules.put("paramFlowRule", ParamFlowRuleManager.getRules());
+ }
return result;
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
index 098822a2..7c9b5d1c 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
@@ -34,8 +34,8 @@ public class SentinelEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
- public SentinelEndpoint sentinelEndPoint() {
- return new SentinelEndpoint();
+ public SentinelEndpoint sentinelEndPoint(SentinelProperties sentinelProperties) {
+ return new SentinelEndpoint(sentinelProperties);
}
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index d05b0863..b445fc6a 100644
--- a/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -18,6 +18,11 @@
"defaultValue": "8719",
"description": "sentinel api port."
},
+ {
+ "name": "spring.cloud.sentinel.transport.clientIp",
+ "type": "java.lang.String",
+ "description": "sentinel client ip connect to dashboard."
+ },
{
"name": "spring.cloud.sentinel.transport.dashboard",
"type": "java.lang.String",
diff --git a/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/spring.factories
index 702bb5bb..d964e3b0 100644
--- a/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/spring.factories
@@ -3,3 +3,6 @@ org.springframework.cloud.alibaba.sentinel.SentinelWebAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.feign.SentinelFeignAutoConfiguration
+
+org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
+org.springframework.cloud.alibaba.sentinel.custom.SentinelCircuitBreakerConfiguration
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java
index 1ba2c170..138c6502 100644
--- a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java
@@ -16,76 +16,267 @@
package org.springframework.cloud.alibaba.sentinel;
-import static org.assertj.core.api.Assertions.assertThat;
-
+import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.log.LogBase;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.RuleConstant;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+import org.junit.Before;
import org.junit.Test;
-import org.springframework.boot.autoconfigure.AutoConfigurations;
-import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
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.cloud.alibaba.sentinel.endpoint.SentinelEndpoint;
+import org.springframework.cloud.alibaba.sentinel.rest.SentinelClientHttpResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
-import com.alibaba.csp.sentinel.slots.block.BlockException;
+import java.util.Arrays;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
- * @author fangjian
+ * @author Jim
* @author jiashuai.xie
*/
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = {
+ SentinelAutoConfigurationTests.TestConfig.class }, properties = {
+ "spring.cloud.sentinel.filter.order=123",
+ "spring.cloud.sentinel.filter.urlPatterns=/*,/test",
+ "spring.cloud.sentinel.metric.fileSingleSize=9999",
+ "spring.cloud.sentinel.metric.fileTotalCount=100",
+ "spring.cloud.sentinel.servlet.blockPage=/error",
+ "spring.cloud.sentinel.flow.coldFactor=3",
+ "spring.cloud.sentinel.eager=true",
+ "spring.cloud.sentinel.log.switchPid=true",
+ "spring.cloud.sentinel.transport.dashboard=http://localhost:8080",
+ "spring.cloud.sentinel.transport.port=9999",
+ "spring.cloud.sentinel.transport.clientIp=1.1.1.1",
+ "spring.cloud.sentinel.transport.heartbeatIntervalMs=20000" }, webEnvironment = RANDOM_PORT)
public class SentinelAutoConfigurationTests {
- private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(SentinelAutoConfiguration.class,
- SentinelWebAutoConfiguration.class, SentinelTestConfiguration.class))
- .withPropertyValues("spring.cloud.sentinel.transport.port=8888")
- .withPropertyValues("spring.cloud.sentinel.filter.order=123")
- .withPropertyValues("spring.cloud.sentinel.filter.urlPatterns=/*,/test");
+ @Autowired
+ private SentinelProperties sentinelProperties;
+
+ @Autowired
+ private FilterRegistrationBean filterRegistrationBean;
+
+ @Autowired
+ private SentinelBeanPostProcessor sentinelBeanPostProcessor;
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Autowired
+ private RestTemplate restTemplateWithBlockClass;
+
+ @Autowired
+ private RestTemplate restTemplateWithoutBlockClass;
+
+ @Autowired
+ private RestTemplate restTemplateWithFallbackClass;
+
+ @LocalServerPort
+ private int port;
+
+ private String url = "http://localhost:" + port;
+
+ @Before
+ public void setUp() {
+ FlowRule rule = new FlowRule();
+ rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
+ rule.setCount(0);
+ rule.setResource(url);
+ rule.setLimitApp("default");
+ rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
+ rule.setStrategy(RuleConstant.STRATEGY_DIRECT);
+ FlowRuleManager.loadRules(Arrays.asList(rule));
+
+ DegradeRule degradeRule = new DegradeRule();
+ degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
+ degradeRule.setResource(url + "/test");
+ degradeRule.setCount(0);
+ degradeRule.setTimeWindow(60);
+ DegradeRuleManager.loadRules(Arrays.asList(degradeRule));
+ }
+
+ @Test
+ public void contextLoads() throws Exception {
+ assertNotNull("FilterRegistrationBean was not created", filterRegistrationBean);
+ assertNotNull("SentinelProperties was not created", sentinelProperties);
+ assertNotNull("SentinelBeanPostProcessor was not created",
+ sentinelBeanPostProcessor);
+
+ checkSentinelLog();
+ checkSentinelEager();
+ checkSentinelTransport();
+ checkSentinelColdFactor();
+ checkSentinelMetric();
+ checkSentinelFilter();
+ checkEndpoint();
+ }
+
+ private void checkEndpoint() {
+ SentinelEndpoint sentinelEndpoint = new SentinelEndpoint(sentinelProperties);
+ Map map = sentinelEndpoint.invoke();
+ assertEquals("Endpoint Sentinel log pid was wrong", true, map.get("logUsePid"));
+ assertEquals("Endpoint Sentinel transport console server was wrong",
+ "http://localhost:8080", map.get("consoleServer"));
+ assertEquals("Endpoint Sentinel transport port was wrong", "9999",
+ map.get("clientPort"));
+ assertEquals("Endpoint Sentinel transport heartbeatIntervalMs was wrong", 20000l,
+ map.get("heartbeatIntervalMs"));
+ assertEquals("Endpoint Sentinel transport clientIp was wrong", "1.1.1.1",
+ map.get("clientIp"));
+ assertEquals("Endpoint Sentinel metric file size was wrong", 9999l,
+ map.get("metricsFileSize"));
+ assertEquals("Endpoint Sentinel metric file count was wrong", 100,
+ map.get("totalMetricsFileCount"));
+ assertEquals("Endpoint Sentinel metric file charset was wrong", "UTF-8",
+ map.get("metricsFileCharset"));
+ assertEquals("Endpoint Sentinel block page was wrong", "/error",
+ map.get("blockPage"));
+ }
+
+ private void checkSentinelFilter() {
+ assertEquals("SentinelProperties filter order was wrong", 123,
+ sentinelProperties.getFilter().getOrder());
+ assertEquals("SentinelProperties filter url pattern size was wrong", 2,
+ sentinelProperties.getFilter().getUrlPatterns().size());
+ assertEquals("SentinelProperties filter url pattern item was wrong", "/*",
+ sentinelProperties.getFilter().getUrlPatterns().get(0));
+ assertEquals("SentinelProperties filter url pattern item was wrong", "/test",
+ sentinelProperties.getFilter().getUrlPatterns().get(1));
+ }
+
+ private void checkSentinelMetric() {
+ assertEquals("SentinelProperties metric charset was wrong", "UTF-8",
+ sentinelProperties.getMetric().getCharset());
+ assertEquals("SentinelProperties metric file single size was wrong", "9999",
+ sentinelProperties.getMetric().getFileSingleSize());
+ assertEquals("SentinelProperties metric file total count was wrong", "100",
+ sentinelProperties.getMetric().getFileTotalCount());
+ }
+
+ private void checkSentinelColdFactor() {
+ assertEquals("SentinelProperties coldFactor was wrong", "3",
+ sentinelProperties.getFlow().getColdFactor());
+ }
+
+ private void checkSentinelTransport() {
+ assertEquals("SentinelProperties transport port was wrong", "9999",
+ sentinelProperties.getTransport().getPort());
+ assertEquals("SentinelProperties transport dashboard was wrong",
+ "http://localhost:8080",
+ sentinelProperties.getTransport().getDashboard());
+ assertEquals("SentinelProperties transport clientIp was wrong", "1.1.1.1",
+ sentinelProperties.getTransport().getClientIp());
+ assertEquals("SentinelProperties transport heartbeatIntervalMs was wrong",
+ "20000", sentinelProperties.getTransport().getHeartbeatIntervalMs());
+ }
+
+ private void checkSentinelEager() {
+ assertEquals("SentinelProperties eager was wrong", true,
+ sentinelProperties.isEager());
+ }
+
+ private void checkSentinelLog() {
+ assertEquals("SentinelProperties log file pid was wrong", true,
+ sentinelProperties.getLog().isSwitchPid());
+ }
@Test
public void testFilter() {
- this.contextRunner.run(context -> {
- assertThat(context.getBean("servletRequestListener")
- .getClass() == FilterRegistrationBean.class).isTrue();
+ assertEquals("Sentinel Filter order was wrong", filterRegistrationBean.getOrder(),
+ 123);
+ assertEquals("Sentinel Filter url-pattern was wrong",
+ filterRegistrationBean.getUrlPatterns().size(), 2);
+ }
+
+ @Test
+ public void testSentinelSystemProperties() {
+ assertEquals("Sentinel log pid was wrong", true, LogBase.isLogNameUsePid());
+ assertEquals("Sentinel transport console server was wrong",
+ "http://localhost:8080", TransportConfig.getConsoleServer());
+ assertEquals("Sentinel transport port was wrong", "9999",
+ TransportConfig.getPort());
+ assertEquals("Sentinel transport heartbeatIntervalMs was wrong", 20000l,
+ TransportConfig.getHeartbeatIntervalMs().longValue());
+ assertEquals("Sentinel transport clientIp was wrong", "1.1.1.1",
+ TransportConfig.getHeartbeatClientIp());
+ assertEquals("Sentinel metric file size was wrong", 9999,
+ SentinelConfig.singleMetricFileSize());
+ assertEquals("Sentinel metric file count was wrong", 100,
+ SentinelConfig.totalMetricFileCount());
+ assertEquals("Sentinel metric file charset was wrong", "UTF-8",
+ SentinelConfig.charset());
+ assertEquals("Sentinel block page was wrong", "/error",
+ WebServletConfig.getBlockPage());
+ }
+
+ @Test
+ public void testFlowRestTemplate() {
+ assertEquals("RestTemplate interceptors size was wrong", 2,
+ restTemplate.getInterceptors().size());
+ assertEquals("RestTemplateWithBlockClass interceptors size was wrong", 1,
+ restTemplateWithBlockClass.getInterceptors().size());
+ ResponseEntity responseEntityBlock = restTemplateWithBlockClass.getForEntity(url,
+ String.class);
+ assertEquals("RestTemplateWithBlockClass Sentinel Block Message was wrong",
+ "Oops", responseEntityBlock.getBody());
+ assertEquals(
+ "RestTemplateWithBlockClass Sentinel Block Http Status Code was wrong",
+ HttpStatus.OK, responseEntityBlock.getStatusCode());
+ ResponseEntity responseEntityRaw = restTemplate.getForEntity(url, String.class);
+ assertEquals("RestTemplate Sentinel Block Message was wrong",
+ "RestTemplate request block by sentinel", responseEntityRaw.getBody());
+ assertEquals("RestTemplate Sentinel Block Http Status Code was wrong",
+ HttpStatus.OK, responseEntityRaw.getStatusCode());
+ }
+
+ @Test
+ public void testNormalRestTemplate() {
+ assertEquals("RestTemplateWithoutBlockClass interceptors size was wrong", 0,
+ restTemplateWithoutBlockClass.getInterceptors().size());
+ assertThatExceptionOfType(RestClientException.class).isThrownBy(() -> {
+ restTemplateWithoutBlockClass.getForEntity(url, String.class);
});
}
@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.getTransport().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);
- });
+ public void testFallbackRestTemplate() {
+ ResponseEntity responseEntity = restTemplateWithFallbackClass
+ .getForEntity(url + "/test", String.class);
+ assertEquals("RestTemplateWithFallbackClass Sentinel Message was wrong",
+ "Oops fallback", responseEntity.getBody());
+ assertEquals("RestTemplateWithFallbackClass Sentinel Http Status Code was wrong",
+ HttpStatus.OK, responseEntity.getStatusCode());
}
@Configuration
@@ -94,7 +285,9 @@ public class SentinelAutoConfigurationTests {
@Bean
@SentinelRestTemplate
RestTemplate restTemplate() {
- return new RestTemplate();
+ RestTemplate restTemplate = new RestTemplate();
+ restTemplate.getInterceptors().add(mock(ClientHttpRequestInterceptor.class));
+ return restTemplate;
}
@Bean
@@ -103,12 +296,38 @@ public class SentinelAutoConfigurationTests {
return new RestTemplate();
}
+ @Bean
+ @SentinelRestTemplate(fallbackClass = ExceptionUtil.class, fallback = "fallbackException")
+ RestTemplate restTemplateWithFallbackClass() {
+ return new RestTemplate();
+ }
+
+ @Bean
+ RestTemplate restTemplateWithoutBlockClass() {
+ return new RestTemplate();
+ }
+
}
- static class ExceptionUtil {
- public static void handleException(BlockException ex) {
+ public static class ExceptionUtil {
+ public static SentinelClientHttpResponse handleException(HttpRequest request,
+ byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
System.out.println("Oops: " + ex.getClass().getCanonicalName());
+ return new SentinelClientHttpResponse("Oops");
+ }
+
+ public static SentinelClientHttpResponse fallbackException(HttpRequest request,
+ byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
+ System.out.println("Oops: " + ex.getClass().getCanonicalName());
+ return new SentinelClientHttpResponse("Oops fallback");
}
}
+ @Configuration
+ @EnableAutoConfiguration
+ @ImportAutoConfiguration({ SentinelAutoConfiguration.class,
+ SentinelWebAutoConfiguration.class, SentinelTestConfiguration.class })
+ public static class TestConfig {
+ }
+
}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelBeanAutowiredTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelBeanAutowiredTests.java
new file mode 100644
index 00000000..ed24c33f
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelBeanAutowiredTests.java
@@ -0,0 +1,132 @@
+/*
+ * 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;
+
+import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
+import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
+import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
+import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
+import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author Jim
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = { SentinelBeanAutowiredTests.TestConfig.class }, properties = {
+ "spring.cloud.sentinel.filter.order=111" })
+public class SentinelBeanAutowiredTests {
+
+ @Autowired
+ private UrlCleaner urlCleaner;
+
+ @Autowired
+ private UrlBlockHandler urlBlockHandler;
+
+ @Autowired
+ private RequestOriginParser requestOriginParser;
+
+ @Autowired
+ private SentinelProperties sentinelProperties;
+
+ @Test
+ public void contextLoads() throws Exception {
+ assertNotNull("UrlCleaner was not created", urlCleaner);
+ assertNotNull("UrlBlockHandler was not created", urlBlockHandler);
+ assertNotNull("RequestOriginParser was not created", requestOriginParser);
+ assertNotNull("SentinelProperties was not created", sentinelProperties);
+
+ checkUrlPattern();
+ }
+
+ private void checkUrlPattern() {
+ assertEquals("SentinelProperties filter order was wrong", 111,
+ sentinelProperties.getFilter().getOrder());
+ assertEquals("SentinelProperties filter url pattern size was wrong", 1,
+ sentinelProperties.getFilter().getUrlPatterns().size());
+ assertEquals("SentinelProperties filter url pattern was wrong", "/*",
+ sentinelProperties.getFilter().getUrlPatterns().get(0));
+ }
+
+ @Test
+ public void testBeanAutowired() {
+ assertEquals("UrlCleaner was not autowired", urlCleaner,
+ WebCallbackManager.getUrlCleaner());
+ assertEquals("UrlBlockHandler was not autowired", urlBlockHandler,
+ WebCallbackManager.getUrlBlockHandler());
+ assertEquals("RequestOriginParser was not autowired", requestOriginParser,
+ WebCallbackManager.getRequestOriginParser());
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ @ImportAutoConfiguration({ SentinelAutoConfiguration.class,
+ SentinelWebAutoConfiguration.class })
+ public static class TestConfig {
+
+ @Bean
+ public UrlCleaner urlCleaner() {
+ return new UrlCleaner() {
+ @Override
+ public String clean(String s) {
+ return s;
+ }
+ };
+ }
+
+ @Bean
+ public RequestOriginParser requestOriginParser() {
+ return new RequestOriginParser() {
+ @Override
+ public String parseOrigin(HttpServletRequest httpServletRequest) {
+ return httpServletRequest.getRemoteAddr();
+ }
+ };
+ }
+
+ @Bean
+ public UrlBlockHandler urlBlockHandler() {
+ return new UrlBlockHandler() {
+ @Override
+ public void blocked(HttpServletRequest httpServletRequest,
+ HttpServletResponse httpServletResponse, BlockException e)
+ throws IOException {
+ FilterUtil.blockRequest(httpServletRequest, httpServletResponse);
+ }
+ };
+ }
+
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelDataSourceTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelDataSourceTests.java
new file mode 100644
index 00000000..1c3be389
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelDataSourceTests.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;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration;
+import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * @author Jim
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = { SentinelDataSourceTests.TestConfig.class }, properties = {
+ "spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json",
+ "spring.cloud.sentinel.datasource.ds1.file.data-type=json",
+ "spring.cloud.sentinel.datasource.ds1.file.rule-type=flow",
+
+ "spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json",
+ "spring.cloud.sentinel.datasource.ds2.file.data-type=json",
+ "spring.cloud.sentinel.datasource.ds2.file.rule-type=degrade",
+
+ "spring.cloud.sentinel.datasource.ds3.file.file=classpath: authority.json",
+ "spring.cloud.sentinel.datasource.ds3.file.rule-type=authority",
+
+ "spring.cloud.sentinel.datasource.ds4.file.file=classpath: system.json",
+ "spring.cloud.sentinel.datasource.ds4.file.rule-type=system",
+
+ "spring.cloud.sentinel.datasource.ds5.file.file=classpath: param-flow.json",
+ "spring.cloud.sentinel.datasource.ds5.file.data-type=custom",
+ "spring.cloud.sentinel.datasource.ds5.file.converter-class=org.springframework.cloud.alibaba.sentinel.TestConverter",
+ "spring.cloud.sentinel.datasource.ds5.file.rule-type=param-flow" })
+public class SentinelDataSourceTests {
+
+ @Autowired
+ private SentinelProperties sentinelProperties;
+
+ @Test
+ public void contextLoads() throws Exception {
+ assertNotNull("SentinelProperties was not created", sentinelProperties);
+
+ checkUrlPattern();
+ }
+
+ private void checkUrlPattern() {
+ assertEquals("SentinelProperties filter order was wrong", Integer.MIN_VALUE,
+ sentinelProperties.getFilter().getOrder());
+ assertEquals("SentinelProperties filter url pattern size was wrong", 1,
+ sentinelProperties.getFilter().getUrlPatterns().size());
+ assertEquals("SentinelProperties filter url pattern was wrong", "/*",
+ sentinelProperties.getFilter().getUrlPatterns().get(0));
+ }
+
+ @Test
+ public void testDataSource() {
+ assertEquals("DataSource size was wrong", 5,
+ sentinelProperties.getDatasource().size());
+ assertNull("DataSource ds1 apollo is not null",
+ sentinelProperties.getDatasource().get("ds1").getApollo());
+ assertNull("DataSource ds1 nacos is not null",
+ sentinelProperties.getDatasource().get("ds1").getNacos());
+ assertNull("DataSource ds1 zk is not null",
+ sentinelProperties.getDatasource().get("ds1").getZk());
+ assertNotNull("DataSource ds1 file is null",
+ sentinelProperties.getDatasource().get("ds1").getFile());
+
+ assertEquals("DataSource ds1 file dataType was wrong", "json",
+ sentinelProperties.getDatasource().get("ds1").getFile().getDataType());
+ assertEquals("DataSource ds1 file ruleType was wrong", RuleType.FLOW,
+ sentinelProperties.getDatasource().get("ds1").getFile().getRuleType());
+
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ @ImportAutoConfiguration({ SentinelAutoConfiguration.class,
+ SentinelWebAutoConfiguration.class })
+ public static class TestConfig {
+
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelFeignTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelFeignTests.java
new file mode 100644
index 00000000..b7d03670
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelFeignTests.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+import com.alibaba.csp.sentinel.slots.block.RuleConstant;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.alibaba.sentinel.feign.SentinelFeignAutoConfiguration;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author Jim
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = { SentinelFeignTests.TestConfig.class }, properties = {
+ "feign.sentinel.enabled=true" })
+public class SentinelFeignTests {
+
+ @Autowired
+ private EchoService echoService;
+
+ @Autowired
+ private FooService fooService;
+
+ @Autowired
+ private BarService barService;
+
+ @Before
+ public void setUp() {
+ FlowRule rule1 = new FlowRule();
+ rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
+ rule1.setCount(0);
+ rule1.setResource("GET:http://test-service/echo/{str}");
+ rule1.setLimitApp("default");
+ rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
+ rule1.setStrategy(RuleConstant.STRATEGY_DIRECT);
+ FlowRule rule2 = new FlowRule();
+ rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
+ rule2.setCount(0);
+ rule2.setResource("GET:http://foo-service/echo/{str}");
+ rule2.setLimitApp("default");
+ rule2.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
+ rule2.setStrategy(RuleConstant.STRATEGY_DIRECT);
+ FlowRule rule3 = new FlowRule();
+ rule3.setGrade(RuleConstant.FLOW_GRADE_QPS);
+ rule3.setCount(0);
+ rule3.setResource("GET:http://bar-service/bar");
+ rule3.setLimitApp("default");
+ rule3.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
+ rule3.setStrategy(RuleConstant.STRATEGY_DIRECT);
+ FlowRuleManager.loadRules(Arrays.asList(rule1, rule2, rule3));
+ }
+
+ @Test
+ public void contextLoads() throws Exception {
+ assertNotNull("EchoService was not created", echoService);
+ assertNotNull("FooService was not created", fooService);
+ }
+
+ @Test
+ public void testFeignClient() {
+ assertEquals("Sentinel Feign Client fallback success", "echo fallback",
+ echoService.echo("test"));
+ assertEquals("Sentinel Feign Client fallbackFactory success", "foo fallback",
+ fooService.echo("test"));
+ assertThatExceptionOfType(Exception.class).isThrownBy(() -> {
+ barService.bar();
+ });
+
+ assertNotEquals("ToString method invoke was not in SentinelInvocationHandler",
+ echoService.toString(), fooService.toString());
+ assertNotEquals("HashCode method invoke was not in SentinelInvocationHandler",
+ echoService.hashCode(), fooService.hashCode());
+ assertFalse("Equals method invoke was not in SentinelInvocationHandler",
+ echoService.equals(fooService));
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ @ImportAutoConfiguration({ SentinelFeignAutoConfiguration.class })
+ @EnableFeignClients
+ public static class TestConfig {
+
+ @Bean
+ public EchoServiceFallback echoServiceFallback() {
+ return new EchoServiceFallback();
+ }
+
+ @Bean
+ public CustomFallbackFactory customFallbackFactory() {
+ return new CustomFallbackFactory();
+ }
+
+ }
+
+ @FeignClient(value = "test-service", fallback = EchoServiceFallback.class)
+ public interface EchoService {
+ @RequestMapping(path = "echo/{str}")
+ String echo(@RequestParam("str") String param);
+ }
+
+ @FeignClient(value = "foo-service", fallbackFactory = CustomFallbackFactory.class)
+ public interface FooService {
+ @RequestMapping(path = "echo/{str}")
+ String echo(@RequestParam("str") String param);
+ }
+
+ @FeignClient(value = "bar-service")
+ public interface BarService {
+ @RequestMapping(path = "bar")
+ String bar();
+ }
+
+ public static class EchoServiceFallback implements EchoService {
+
+ @Override
+ public String echo(@RequestParam("str") String param) {
+ return "echo fallback";
+ }
+
+ }
+
+ public static class FooServiceFallback implements FooService {
+
+ @Override
+ public String echo(@RequestParam("str") String param) {
+ return "foo fallback";
+ }
+ }
+
+ public static class CustomFallbackFactory
+ implements feign.hystrix.FallbackFactory {
+
+ private FooService fooService = new FooServiceFallback();
+
+ @Override
+ public FooService create(Throwable throwable) {
+ return fooService;
+ }
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelRestTemplateTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelRestTemplateTests.java
new file mode 100644
index 00000000..f95c4616
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelRestTemplateTests.java
@@ -0,0 +1,247 @@
+/*
+ * 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;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.junit.Test;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
+import org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor;
+import org.springframework.cloud.alibaba.sentinel.rest.SentinelClientHttpResponse;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.web.client.RestTemplate;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Jim
+ */
+public class SentinelRestTemplateTests {
+
+ @Test(expected = BeanCreationException.class)
+ public void testFbkMethod() {
+ new AnnotationConfigApplicationContext(TestConfig1.class);
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testFbkClass() {
+ new AnnotationConfigApplicationContext(TestConfig2.class);
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testblkMethod() {
+ new AnnotationConfigApplicationContext(TestConfig3.class);
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testblkClass() {
+ new AnnotationConfigApplicationContext(TestConfig4.class);
+ }
+
+ @Test
+ public void testNormal() {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
+ TestConfig5.class);
+ assertEquals("RestTemplate size was wrong", 1,
+ context.getBeansOfType(RestTemplate.class).size());
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testBlkMethodExists() {
+ new AnnotationConfigApplicationContext(TestConfig6.class);
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testFbkMethodExists() {
+ new AnnotationConfigApplicationContext(TestConfig7.class);
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testBlkReturnValue() {
+ new AnnotationConfigApplicationContext(TestConfig8.class);
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testFbkReturnValue() {
+ new AnnotationConfigApplicationContext(TestConfig9.class);
+ }
+
+ @Configuration
+ public static class TestConfig1 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(fallback = "fbk")
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig2 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(fallbackClass = ExceptionUtil.class)
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig3 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(blockHandler = "blk")
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig4 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(blockHandlerClass = ExceptionUtil.class)
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig5 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(blockHandlerClass = SentinelRestTemplateTests.ExceptionUtil.class, blockHandler = "handleException", fallbackClass = SentinelRestTemplateTests.ExceptionUtil.class, fallback = "fallbackException")
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig6 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(blockHandlerClass = SentinelRestTemplateTests.ExceptionUtil.class, blockHandler = "handleException1")
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig7 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(fallbackClass = SentinelRestTemplateTests.ExceptionUtil.class, fallback = "fallbackException1")
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig8 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(blockHandlerClass = SentinelRestTemplateTests.ExceptionUtil.class, blockHandler = "handleException2")
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ @Configuration
+ public static class TestConfig9 {
+ @Bean
+ SentinelBeanPostProcessor sentinelBeanPostProcessor(
+ ApplicationContext applicationContext) {
+ return new SentinelBeanPostProcessor(applicationContext);
+ }
+
+ @Bean
+ @SentinelRestTemplate(fallbackClass = SentinelRestTemplateTests.ExceptionUtil.class, fallback = "fallbackException2")
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+ }
+
+ public static class ExceptionUtil {
+ public static SentinelClientHttpResponse handleException(HttpRequest request,
+ byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
+ System.out.println("Oops: " + ex.getClass().getCanonicalName());
+ return new SentinelClientHttpResponse("Oops");
+ }
+
+ public static void handleException2(HttpRequest request, byte[] body,
+ ClientHttpRequestExecution execution, BlockException ex) {
+ System.out.println("Oops: " + ex.getClass().getCanonicalName());
+ }
+
+ public static SentinelClientHttpResponse fallbackException(HttpRequest request,
+ byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
+ System.out.println("Oops: " + ex.getClass().getCanonicalName());
+ return new SentinelClientHttpResponse("Oops fallback");
+ }
+
+ public static void fallbackException2(HttpRequest request, byte[] body,
+ ClientHttpRequestExecution execution, BlockException ex) {
+ System.out.println("Oops: " + ex.getClass().getCanonicalName());
+ }
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/TestConverter.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/TestConverter.java
new file mode 100644
index 00000000..43012442
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/TestConverter.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import com.alibaba.csp.sentinel.datasource.Converter;
+import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Jim
+ */
+public class TestConverter implements Converter> {
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ @Override
+ public List convert(String s) {
+ try {
+ return objectMapper.readValue(s, new TypeReference>() {
+ });
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/spring-cloud-alibaba-sentinel/src/test/resources/authority.json b/spring-cloud-alibaba-sentinel/src/test/resources/authority.json
new file mode 100644
index 00000000..3fb4b249
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/resources/authority.json
@@ -0,0 +1,17 @@
+[
+ {
+ "resource": "good",
+ "limitApp": "abc",
+ "strategy": 0
+ },
+ {
+ "resource": "bad",
+ "limitApp": "bcd",
+ "strategy": 1
+ },
+ {
+ "resource": "terrible",
+ "limitApp": "aaa",
+ "strategy": 1
+ }
+]
diff --git a/spring-cloud-alibaba-sentinel/src/test/resources/degraderule.json b/spring-cloud-alibaba-sentinel/src/test/resources/degraderule.json
new file mode 100644
index 00000000..5977c5fc
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/resources/degraderule.json
@@ -0,0 +1,16 @@
+[
+ {
+ "resource": "abc0",
+ "count": 20.0,
+ "grade": 0,
+ "passCount": 0,
+ "timeWindow": 10
+ },
+ {
+ "resource": "abc1",
+ "count": 15.0,
+ "grade": 0,
+ "passCount": 0,
+ "timeWindow": 10
+ }
+]
\ No newline at end of file
diff --git a/spring-cloud-alibaba-sentinel/src/test/resources/flowrule.json b/spring-cloud-alibaba-sentinel/src/test/resources/flowrule.json
new file mode 100644
index 00000000..d798f805
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/resources/flowrule.json
@@ -0,0 +1,26 @@
+[
+ {
+ "resource": "resource",
+ "controlBehavior": 0,
+ "count": 1,
+ "grade": 1,
+ "limitApp": "default",
+ "strategy": 0
+ },
+ {
+ "resource": "p",
+ "controlBehavior": 0,
+ "count": 1,
+ "grade": 1,
+ "limitApp": "default",
+ "strategy": 0
+ },
+ {
+ "resource": "http://www.taobao.com",
+ "controlBehavior": 0,
+ "count": 0,
+ "grade": 1,
+ "limitApp": "default",
+ "strategy": 0
+ }
+]
diff --git a/spring-cloud-alibaba-sentinel/src/test/resources/param-flow.json b/spring-cloud-alibaba-sentinel/src/test/resources/param-flow.json
new file mode 100644
index 00000000..72e1c2dc
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/resources/param-flow.json
@@ -0,0 +1,16 @@
+[
+ {
+ "resource": "hotResource",
+ "count": 0,
+ "grade": 1,
+ "limitApp": "default",
+ "paramIdx": 0,
+ "paramFlowItemList": [
+ {
+ "object": "2",
+ "classType": "int",
+ "count": 1
+ }
+ ]
+ }
+]
diff --git a/spring-cloud-alibaba-sentinel/src/test/resources/system.json b/spring-cloud-alibaba-sentinel/src/test/resources/system.json
new file mode 100644
index 00000000..7aa623a7
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/resources/system.json
@@ -0,0 +1,8 @@
+[
+ {
+ "highestSystemLoad": -1,
+ "qps": 100,
+ "avgRt": -1,
+ "maxThread": 10
+ }
+]
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java
index a14c6e12..d563632e 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java
@@ -21,12 +21,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass;
import org.springframework.cloud.alicloud.ans.registry.AnsAutoServiceRegistration;
import org.springframework.cloud.alicloud.ans.registry.AnsRegistration;
import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry;
+import org.springframework.cloud.alicloud.context.ans.AnsProperties;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/**
@@ -34,6 +38,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@EnableConfigurationProperties
+@Conditional(MigrateOnConditionMissingClass.class)
@ConditionalOnClass(name = "org.springframework.boot.web.context.WebServerInitializedEvent")
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@ConditionalOnAnsEnabled
@@ -49,8 +54,9 @@ public class AnsAutoConfiguration {
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
- public AnsRegistration ansRegistration() {
- return new AnsRegistration();
+ public AnsRegistration ansRegistration(AnsProperties ansProperties,
+ ApplicationContext applicationContext) {
+ return new AnsRegistration(ansProperties, applicationContext);
}
@Bean
@@ -63,4 +69,5 @@ public class AnsAutoConfiguration {
return new AnsAutoServiceRegistration(registry, autoServiceRegistrationProperties,
registration);
}
+
}
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java
index c95757b2..36c28c9f 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java
@@ -16,13 +16,17 @@
package org.springframework.cloud.alicloud.ans;
-import java.util.*;
-
+import com.alibaba.ans.core.NamingService;
+import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
-import com.alibaba.ans.core.NamingService;
-import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* @author xiaolongzuo
@@ -75,8 +79,9 @@ public class AnsDiscoveryClient implements DiscoveryClient {
@Override
public List getServices() {
-
+ Set publishers = NamingService.getPublishes();
Set doms = NamingService.getDomsSubscribed();
+ doms.addAll(publishers);
List result = new LinkedList<>();
for (String service : doms) {
result.add(service);
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java
index 7d286976..c19296f4 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java
@@ -19,15 +19,18 @@ package org.springframework.cloud.alicloud.ans;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaolongzuo
*/
@Configuration
+@Conditional(MigrateOnConditionMissingClass.class)
@ConditionalOnMissingBean(DiscoveryClient.class)
@EnableConfigurationProperties
@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class)
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java
index a8bc64c7..87cdcd59 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java
@@ -16,19 +16,18 @@
package org.springframework.cloud.alicloud.ans.endpoint;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.alibaba.ans.core.NamingService;
+import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
-import com.alibaba.ans.core.NamingService;
-import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* @author xiaolongzuo
@@ -36,7 +35,7 @@ import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
@Endpoint(id = "ans")
public class AnsEndpoint {
- private static final Logger LOGGER = LoggerFactory.getLogger(AnsEndpoint.class);
+ private static final Log log = LogFactory.getLog(AnsEndpoint.class);
private AnsProperties ansProperties;
@@ -50,7 +49,7 @@ public class AnsEndpoint {
@ReadOperation
public Map invoke() {
Map ansEndpoint = new HashMap<>();
- LOGGER.info("ANS endpoint invoke, ansProperties is {}", ansProperties);
+ log.info("ANS endpoint invoke, ansProperties is " + ansProperties);
ansEndpoint.put("ansProperties", ansProperties);
Map subscribes = new HashMap<>();
@@ -65,7 +64,7 @@ public class AnsEndpoint {
}
}
ansEndpoint.put("subscribes", subscribes);
- LOGGER.info("ANS endpoint invoke, subscribes is {}", subscribes);
+ log.info("ANS endpoint invoke, subscribes is " + subscribes);
return ansEndpoint;
}
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpoint.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpoint.java
new file mode 100644
index 00000000..16b99d7b
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpoint.java
@@ -0,0 +1,31 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+@Endpoint(id = "migrate")
+public class MigrateEndpoint {
+
+ private static final Log log = LogFactory.getLog(MigrateEndpoint.class);
+
+ public MigrateEndpoint() {
+ }
+
+ /**
+ * @return ans endpoint
+ */
+ @ReadOperation
+ public Map> invoke() {
+
+ Map> result = ServerListInvocationHandler
+ .getServerRegistry();
+
+ log.info("migrate server list :" + result);
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpointAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpointAutoConfiguration.java
new file mode 100644
index 00000000..385d5a5d
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpointAutoConfiguration.java
@@ -0,0 +1,18 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+
+@ConditionalOnWebApplication
+@ConditionalOnClass(value = Endpoint.class)
+@Conditional(MigrateOnConditionClass.class)
+public class MigrateEndpointAutoConfiguration {
+
+ @Bean
+ public MigrateEndpoint ansEndpoint() {
+ return new MigrateEndpoint();
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnCondition.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnCondition.java
new file mode 100644
index 00000000..96050181
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnCondition.java
@@ -0,0 +1,49 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.util.ClassUtils;
+
+/**
+ * @author pbting
+ */
+public abstract class MigrateOnCondition implements Condition, BeanClassLoaderAware {
+
+ final String[] conditionOnClass = new String[] {
+ "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistration",
+ "org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration" };
+
+ ClassLoader classLoader;
+
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public abstract boolean matches(ConditionContext context,
+ AnnotatedTypeMetadata metadata);
+
+ boolean isPresent(String className, ClassLoader classLoader) {
+ if (classLoader == null) {
+ classLoader = ClassUtils.getDefaultClassLoader();
+ }
+
+ try {
+ forName(className, classLoader);
+ return true;
+ }
+ catch (Throwable var3) {
+ return false;
+ }
+ }
+
+ Class> forName(String className, ClassLoader classLoader)
+ throws ClassNotFoundException {
+ return classLoader != null ? classLoader.loadClass(className)
+ : Class.forName(className);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionClass.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionClass.java
new file mode 100644
index 00000000..23c58036
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionClass.java
@@ -0,0 +1,22 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * @author pbting
+ */
+public class MigrateOnConditionClass extends MigrateOnCondition {
+
+ protected static final Log log = LogFactory.getLog(MigrateOnConditionClass.class);
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ boolean result = isPresent(conditionOnClass[0], classLoader)
+ || isPresent(conditionOnClass[1], classLoader);
+ log.info("the result of match is :" + result);
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionMissingClass.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionMissingClass.java
new file mode 100644
index 00000000..8501ed12
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionMissingClass.java
@@ -0,0 +1,23 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * @author pbting
+ */
+public class MigrateOnConditionMissingClass extends MigrateOnConditionClass {
+
+ protected static final Log log = LogFactory
+ .getLog(MigrateOnConditionMissingClass.class);
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ boolean result = !super.matches(context, metadata);
+ log.info("the result of match is :" + result);
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateProxyManager.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateProxyManager.java
new file mode 100644
index 00000000..23427941
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateProxyManager.java
@@ -0,0 +1,97 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import com.netflix.client.config.IClientConfig;
+import com.netflix.loadbalancer.ILoadBalancer;
+import com.netflix.loadbalancer.Server;
+import com.netflix.loadbalancer.ServerList;
+import org.aopalliance.aop.Advice;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.aop.AfterReturningAdvice;
+import org.springframework.aop.framework.ProxyFactory;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * @author pbting
+ */
+final class MigrateProxyManager {
+
+ private final static Log log = LogFactory.getLog(MigrateProxyManager.class);
+ private final static AtomicBoolean IS_PROXY = new AtomicBoolean(true);
+
+ private final static Set SERVICES_ID = new ConcurrentSkipListSet<>();
+
+ private static Object springProxyFactory(Object target, ClassLoader classLoader,
+ List adviceList, Class... interfaces) {
+ final ProxyFactory proxyFactory = new ProxyFactory(interfaces);
+ proxyFactory.setTarget(target);
+ adviceList.forEach(advice -> proxyFactory.addAdvice(advice));
+ return proxyFactory.getProxy(classLoader);
+ }
+
+ static Object newServerListProxy(Object bean, ClassLoader classLoader,
+ IClientConfig clientConfig) {
+ bean = springProxyFactory(bean, classLoader,
+ Arrays.asList(new ServerListInvocationHandler(clientConfig)),
+ new Class[] { ServerList.class });
+ log.info("[service id]" + clientConfig.getClientName()
+ + " new a ServerList proxy instance for spring cloud netflix to spring cloud alibaba ");
+ collectServiceId(clientConfig.getClientName());
+ return bean;
+ }
+
+ static Object newLoadBalancerProxy(Object bean, ClassLoader classLoader,
+ final IClientConfig clientConfig) {
+
+ bean = springProxyFactory(bean, classLoader,
+ Arrays.asList(new AfterReturningAdvice() {
+ private final IClientConfig iclientConfig = clientConfig;
+
+ @Override
+ public void afterReturning(Object returnValue, Method method,
+ Object[] args, Object target) {
+ String methodName = method.getName();
+ if ("chooseServer".equals(methodName)) {
+ String serviceId = iclientConfig.getClientName();
+ Server server = (Server) returnValue;
+ server = ServerListInvocationHandler
+ .checkAndGetServiceServer(serviceId, server);
+ ServerListInvocationHandler.incrementCallService(serviceId,
+ server);
+ }
+ }
+ }), new Class[] { ILoadBalancer.class });
+ log.info("[service id]" + clientConfig.getClientName()
+ + " new a ILoadBalancer proxy instance for spring cloud netflix to spring cloud alibaba ");
+ return bean;
+ }
+
+ static void migrateProxyClose() {
+ IS_PROXY.set(false);
+ }
+
+ static void migrateProxyUp() {
+ IS_PROXY.set(true);
+ }
+
+ static boolean isMigrateProxy() {
+
+ return IS_PROXY.get();
+ }
+
+ static void collectServiceId(String serviceId) {
+ SERVICES_ID.add(serviceId);
+ }
+
+ static Set getServicesId() {
+
+ return Collections.unmodifiableSet(SERVICES_ID);
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRefreshEventListener.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRefreshEventListener.java
new file mode 100644
index 00000000..70d12113
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRefreshEventListener.java
@@ -0,0 +1,78 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import com.netflix.loadbalancer.ILoadBalancer;
+import org.springframework.cloud.context.named.NamedContextFactory;
+import org.springframework.cloud.endpoint.event.RefreshEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author pbting
+ */
+@Component
+public class MigrateRefreshEventListener implements ApplicationListener {
+
+ private final static int CHECK_INTERVAL = 1;
+
+ private final static String MIGRATE_SWITCH = "spring.cloud.alicloud.migrate.ans.switch";
+
+ private volatile String lastScaMigrateAnsSwitchValue = "true";
+
+ private Environment environment;
+
+ private NamedContextFactory namedContextFactory;
+
+ public MigrateRefreshEventListener(Environment environment,
+ NamedContextFactory namedContextFactory) {
+ this.environment = environment;
+ this.namedContextFactory = namedContextFactory;
+ }
+
+ @PostConstruct
+ public void initTimerCheck() {
+ Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(
+ () -> onApplicationEvent(null), CHECK_INTERVAL, CHECK_INTERVAL,
+ TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void onApplicationEvent(RefreshEvent event) {
+ String value = environment.getProperty(MIGRATE_SWITCH, "true");
+ // check 1: check the value
+ if (value.equals(lastScaMigrateAnsSwitchValue)) {
+ return;
+ }
+
+ updateLastScaMigrateAnsResetValue(value);
+
+ // step 1: migrate up
+ if ("true".equals(value)) {
+ MigrateProxyManager.migrateProxyUp();
+ serviceIdContextInit();
+ return;
+ }
+
+ // step 2: migrate close
+ if ("false".equals(value)) {
+ MigrateProxyManager.migrateProxyClose();
+ serviceIdContextInit();
+ return;
+ }
+ }
+
+ private void serviceIdContextInit() {
+ namedContextFactory.destroy();
+ // initializer each spring context for service id
+ MigrateProxyManager.getServicesId().forEach(serviceId -> namedContextFactory
+ .getInstance(serviceId, ILoadBalancer.class));
+ }
+
+ private synchronized void updateLastScaMigrateAnsResetValue(String value) {
+ this.lastScaMigrateAnsSwitchValue = value;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRibbonBeanPostProcessor.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRibbonBeanPostProcessor.java
new file mode 100644
index 00000000..98fe851e
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRibbonBeanPostProcessor.java
@@ -0,0 +1,52 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import com.netflix.client.config.IClientConfig;
+import com.netflix.loadbalancer.ILoadBalancer;
+import com.netflix.loadbalancer.ServerList;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+public class MigrateRibbonBeanPostProcessor
+ implements BeanPostProcessor, BeanClassLoaderAware {
+
+ protected static final Log log = LogFactory.getLog(MigrateOnCondition.class);
+
+ private ClassLoader classLoader;
+ private IClientConfig clientConfig;
+
+ public MigrateRibbonBeanPostProcessor(IClientConfig clientConfig) {
+ this.clientConfig = clientConfig;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+
+ // step 1 : check the bean whether proxy or not
+ if (!MigrateProxyManager.isMigrateProxy()) {
+ log.info("Migrate proxy is Close.");
+ return bean;
+ }
+
+ // step 2 : proxy the designated bean
+ if (bean instanceof ServerList) {
+ bean = MigrateProxyManager.newServerListProxy(bean, classLoader,
+ clientConfig);
+ }
+
+ if (bean instanceof ILoadBalancer) {
+ bean = MigrateProxyManager.newLoadBalancerProxy(bean, classLoader,
+ clientConfig);
+ }
+ return bean;
+ }
+
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateServiceRegistry.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateServiceRegistry.java
new file mode 100644
index 00000000..5491e98d
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateServiceRegistry.java
@@ -0,0 +1,51 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.boot.web.context.WebServerInitializedEvent;
+import org.springframework.cloud.alicloud.ans.registry.AnsRegistration;
+import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry;
+import org.springframework.cloud.alicloud.context.ans.AnsProperties;
+import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * @author pbting
+ */
+@Component
+public class MigrateServiceRegistry {
+
+ private static final Log log = LogFactory.getLog(MigrateServiceRegistry.class);
+
+ private AtomicBoolean running = new AtomicBoolean(false);
+
+ private ServiceRegistry serviceRegistry;
+ private AnsRegistration ansRegistration;
+
+ public MigrateServiceRegistry(AnsProperties ansProperties,
+ ApplicationContext context) {
+ this.ansRegistration = new AnsRegistration(ansProperties, context);
+ this.ansRegistration.init();
+ this.serviceRegistry = new AnsServiceRegistry();
+ }
+
+ @EventListener(WebServerInitializedEvent.class)
+ public void onApplicationEvent(WebServerInitializedEvent event) {
+ int serverPort = event.getWebServer().getPort();
+ this.ansRegistration.setPort(serverPort);
+ log.info("[ Migrate ] change the port to " + serverPort);
+ if (!this.running.get()) {
+ long s = System.currentTimeMillis();
+ log.info("[Migrate] start to registry server to ANS");
+ this.serviceRegistry.register(this.ansRegistration);
+ log.info("[migrate] end to registry server to ANS cost time with "
+ + (System.currentTimeMillis() - s) + " ms.");
+ this.running.set(true);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrationAutoconfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrationAutoconfiguration.java
new file mode 100644
index 00000000..7564b4d7
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrationAutoconfiguration.java
@@ -0,0 +1,36 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.alicloud.ans.ConditionalOnAnsEnabled;
+import org.springframework.cloud.alicloud.context.ans.AnsProperties;
+import org.springframework.cloud.context.named.NamedContextFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+
+@Configuration
+@EnableConfigurationProperties
+@Conditional(MigrateOnConditionClass.class)
+@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
+@ConditionalOnAnsEnabled
+public class MigrationAutoconfiguration {
+
+ @Bean
+ public MigrateServiceRegistry migrationManger(AnsProperties ansProperties,
+ ApplicationContext applicationContext) {
+
+ return new MigrateServiceRegistry(ansProperties, applicationContext);
+ }
+
+ @Bean
+ public MigrateRefreshEventListener migrateRefreshEventListener(
+ Environment environment,
+ @Qualifier(value = "springClientFactory") NamedContextFactory namedContextFactory) {
+
+ return new MigrateRefreshEventListener(environment, namedContextFactory);
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerListInvocationHandler.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerListInvocationHandler.java
new file mode 100644
index 00000000..16a31147
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerListInvocationHandler.java
@@ -0,0 +1,169 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import com.netflix.client.config.IClientConfig;
+import com.netflix.loadbalancer.Server;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.cloud.alicloud.ans.ribbon.AnsServer;
+import org.springframework.cloud.alicloud.ans.ribbon.AnsServerList;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ *
+ */
+class ServerListInvocationHandler implements MethodInterceptor {
+
+ private final static Log log = LogFactory.getLog(ServerListInvocationHandler.class);
+
+ private final static ConcurrentMap SERVER_LIST_CONCURRENT_MAP = new ConcurrentHashMap<>();
+
+ private final static ConcurrentMap> CALL_SERVICE_COUNT = new ConcurrentHashMap<>();
+
+ private final static Set INTERCEPTOR_METHOD_NAME = new ConcurrentSkipListSet();
+
+ private IClientConfig clientConfig;
+ private AnsServerList ansServerList;
+ private AtomicBoolean isFirst = new AtomicBoolean(false);
+
+ static {
+ INTERCEPTOR_METHOD_NAME.add("getInitialListOfServers");
+ INTERCEPTOR_METHOD_NAME.add("getUpdatedListOfServers");
+ }
+
+ ServerListInvocationHandler(IClientConfig clientConfig) {
+ this.clientConfig = clientConfig;
+ this.ansServerList = new AnsServerList(clientConfig.getClientName());
+ SERVER_LIST_CONCURRENT_MAP.put(ansServerList.getDom(), ansServerList);
+ }
+
+ @Override
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ String methodName = invocation.getMethod().getName();
+ // step 1: check the method is not interceptor
+ if (!INTERCEPTOR_METHOD_NAME.contains(methodName)) {
+ return invocation.proceed();
+ }
+
+ // step 2: interceptor the method
+ List serverList = (List) invocation.proceed();
+ long s = System.currentTimeMillis();
+ log.info("[ START ] merage server list for " + clientConfig.getClientName());
+ serverList = mergeAnsServerList(serverList);
+ log.info("[ END ] merage server list for " + clientConfig.getClientName()
+ + ", cost time " + (System.currentTimeMillis() - s) + " ms .");
+ return serverList;
+ }
+
+ /**
+ * 后台线程 和 Eureka 两个注册中心进行 Merage 的时候,List 表中始终保持是有效的 Server. 即不考虑 ANS 客户端本地容灾的情况
+ */
+ private List mergeAnsServerList(final List source) {
+ if (isFirst.compareAndSet(false, true)) {
+ return source;
+ }
+
+ // step 1: get all of server list and filter the alive
+ List ansServerList = filterAliveAnsServer(
+ this.ansServerList.getInitialListOfServers());
+
+ if (ansServerList.isEmpty()) {
+ return source;
+ }
+
+ log.info("[" + this.clientConfig.getClientName() + "] Get Server List from ANS:"
+ + ansServerList + "; loadbalancer server list override before:" + source);
+
+ // step 2:remove servers of that have in load balancer list
+ final Iterator serverIterator = source.iterator();
+ while (serverIterator.hasNext()) {
+ final Server server = serverIterator.next();
+ ansServerList.forEach(ansServer -> {
+ if (server.getHostPort()
+ .equals(ansServer.getHealthService().toInetAddr())) {
+ // by: ZoneAffinityPredicate
+ serverIterator.remove();
+ log.info("Source Server is remove " + server.getHostPort()
+ + ", and from ANS Server is override:"
+ + ansServer.toString());
+ }
+ // fix bug: mast be set the zone, update server list,will filter
+ ansServer.setZone(server.getZone());
+ ansServer.setSchemea(server.getScheme());
+ ansServer.setId(ansServer.getHealthService().toInetAddr());
+ ansServer.setReadyToServe(true);
+ });
+ }
+
+ ansServerList.forEach(ansServer -> source.add(ansServer));
+ log.info("[" + this.clientConfig.getClientName() + "] "
+ + "; loadbalancer server list override after:" + source);
+ // override
+ return source;
+ }
+
+ private List filterAliveAnsServer(List sourceServerList) {
+ final List resultServerList = new LinkedList<>();
+ sourceServerList.forEach(ansServer -> {
+ boolean isAlive = ansServer.isAlive(3);
+ if (isAlive) {
+ resultServerList.add(ansServer);
+ }
+ log.warn(ansServer.toString() + " isAlive :" + isAlive);
+ });
+ return resultServerList;
+ }
+
+ static Map> getServerRegistry() {
+
+ return Collections.unmodifiableMap(CALL_SERVICE_COUNT);
+ }
+
+ static Server checkAndGetServiceServer(String serviceId, Server server) {
+ if (server != null) {
+ return server;
+ }
+
+ log.warn(String.format("[%s] refers the server is null", server));
+
+ List ansServerList = SERVER_LIST_CONCURRENT_MAP.get(serviceId)
+ .getInitialListOfServers();
+
+ if (!ansServerList.isEmpty()) {
+ return ansServerList.get(0);
+ }
+
+ return server;
+ }
+
+ static void incrementCallService(String serviceId, Server server) {
+ ConcurrentMap concurrentHashMap = CALL_SERVICE_COUNT
+ .putIfAbsent(serviceId, new ConcurrentHashMap<>());
+
+ if (concurrentHashMap == null) {
+ concurrentHashMap = CALL_SERVICE_COUNT.get(serviceId);
+ }
+
+ String ipPort = server.getHostPort();
+ ServerWrapper serverWraper = concurrentHashMap.putIfAbsent(ipPort,
+ new ServerWrapper(server, new AtomicLong()));
+
+ if (serverWraper == null) {
+ serverWraper = concurrentHashMap.get(ipPort);
+ }
+ serverWraper.setServer(server);
+ serverWraper.getCallCount().incrementAndGet();
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerWrapper.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerWrapper.java
new file mode 100644
index 00000000..aeaa5a60
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerWrapper.java
@@ -0,0 +1,35 @@
+package org.springframework.cloud.alicloud.ans.migrate;
+
+import com.netflix.loadbalancer.Server;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class ServerWrapper {
+
+ private Server server;
+ private AtomicLong callCount;
+
+ public ServerWrapper() {
+ }
+
+ public ServerWrapper(Server server, AtomicLong callCount) {
+ this.server = server;
+ this.callCount = callCount;
+ }
+
+ public Server getServer() {
+ return server;
+ }
+
+ public void setServer(Server server) {
+ this.server = server;
+ }
+
+ public AtomicLong getCallCount() {
+ return callCount;
+ }
+
+ public void setCallCount(AtomicLong callCount) {
+ this.callCount = callCount;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java
index 0774f185..82d0d8eb 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java
@@ -16,8 +16,8 @@
package org.springframework.cloud.alicloud.ans.registry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
@@ -30,8 +30,7 @@ import org.springframework.util.StringUtils;
*/
public class AnsAutoServiceRegistration
extends AbstractAutoServiceRegistration {
- private static final Logger LOGGER = LoggerFactory
- .getLogger(AnsAutoServiceRegistration.class);
+ private static final Log log = LogFactory.getLog(AnsAutoServiceRegistration.class);
@Autowired
private AnsRegistration registration;
@@ -65,7 +64,7 @@ public class AnsAutoServiceRegistration
@Override
protected void register() {
if (!this.registration.getAnsProperties().isRegisterEnabled()) {
- LOGGER.debug("Registration disabled.");
+ log.debug("Registration disabled.");
return;
}
if (this.registration.getPort() < 0) {
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java
index 1fcb292f..cd763fdd 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java
@@ -16,12 +16,6 @@
package org.springframework.cloud.alicloud.ans.registry;
-import java.net.URI;
-import java.util.Map;
-
-import javax.annotation.PostConstruct;
-
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
@@ -31,6 +25,10 @@ import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
+import javax.annotation.PostConstruct;
+import java.net.URI;
+import java.util.Map;
+
/**
* @author xiaolongzuo
*/
@@ -40,12 +38,14 @@ public class AnsRegistration implements Registration, ServiceInstance {
private static final String MANAGEMENT_CONTEXT_PATH = "management.context-path";
private static final String MANAGEMENT_ADDRESS = "management.address";
- @Autowired
private AnsProperties ansProperties;
-
- @Autowired
private ApplicationContext context;
+ public AnsRegistration(AnsProperties ansProperties, ApplicationContext context) {
+ this.ansProperties = ansProperties;
+ this.context = context;
+ }
+
@PostConstruct
public void init() {
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java
index ebe65ee3..1ff187a3 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java
@@ -16,24 +16,23 @@
package org.springframework.cloud.alicloud.ans.registry;
+import com.alibaba.ans.core.NamingService;
+import com.alibaba.ans.shaded.com.taobao.vipserver.client.ipms.NodeReactor;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
-
-import com.alibaba.ans.core.NamingService;
-import com.alibaba.ans.shaded.com.taobao.vipserver.client.ipms.NodeReactor;
-
/**
* @author xiaolongzuo
*/
public class AnsServiceRegistry implements ServiceRegistry {
- private static Logger logger = LoggerFactory.getLogger(AnsServiceRegistry.class);
+ private static Log log = LogFactory.getLog(AnsServiceRegistry.class);
private static final String SEPARATOR = ",";
@@ -41,11 +40,11 @@ public class AnsServiceRegistry implements ServiceRegistry {
public void register(AnsRegistration registration) {
if (!registration.isRegisterEnabled()) {
- logger.info("Registration is disabled...");
+ log.info("Registration is disabled...");
return;
}
if (StringUtils.isEmpty(registration.getServiceId())) {
- logger.info("No service to register for client...");
+ log.info("No service to register for client...");
return;
}
@@ -63,13 +62,14 @@ public class AnsServiceRegistry implements ServiceRegistry {
NamingService.regDom(dom, registration.getHost(), registration.getPort(),
registration.getRegisterWeight(dom), registration.getCluster(),
tags);
- logger.info("INFO_ANS_REGISTER, {} {}:{} register finished", dom,
- registration.getAnsProperties().getClientIp(),
- registration.getAnsProperties().getClientPort());
+ log.info("INFO_ANS_REGISTER, " + dom + " "
+ + registration.getAnsProperties().getClientIp() + ":"
+ + registration.getAnsProperties().getClientPort()
+ + " register finished");
}
catch (Exception e) {
- logger.error("ERR_ANS_REGISTER, {} register failed...{},", dom,
- registration.toString(), e);
+ log.error("ERR_ANS_REGISTER, " + dom + " register failed..."
+ + registration.toString() + ",", e);
}
}
}
@@ -77,10 +77,10 @@ public class AnsServiceRegistry implements ServiceRegistry {
@Override
public void deregister(AnsRegistration registration) {
- logger.info("De-registering from ANSServer now...");
+ log.info("De-registering from ANSServer now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
- logger.info("No dom to de-register for client...");
+ log.info("No dom to de-register for client...");
return;
}
@@ -89,11 +89,11 @@ public class AnsServiceRegistry implements ServiceRegistry {
registration.getPort(), registration.getCluster());
}
catch (Exception e) {
- logger.error("ERR_ANS_DEREGISTER, de-register failed...{},",
- registration.toString(), e);
+ log.error("ERR_ANS_DEREGISTER, de-register failed..."
+ + registration.toString() + ",", e);
}
- logger.info("De-registration finished.");
+ log.info("De-registration finished.");
}
@Override
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java
index 7734e037..3f1f1516 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java
@@ -16,22 +16,24 @@
package org.springframework.cloud.alicloud.ans.ribbon;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
/**
* @author xiaolongzuo
*/
@Configuration
+@Conditional(MigrateOnConditionMissingClass.class)
public class AnsRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
- public ServerList> ribbonServerList(IClientConfig config) {
+ public ServerList> ansRibbonServerList(IClientConfig config) {
AnsServerList serverList = new AnsServerList(config.getClientName());
return serverList;
}
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java
index 8438a7f3..d19f6287 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java
@@ -16,12 +16,16 @@
package org.springframework.cloud.alicloud.ans.ribbon;
-import java.util.Collections;
-import java.util.Map;
-
import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import com.netflix.loadbalancer.Server;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
/**
* @author xiaolongzuo
*/
@@ -34,7 +38,8 @@ public class AnsServer extends Server {
public AnsServer(final Host host, final String dom) {
super(host.getIp(), host.getPort());
this.host = host;
- this.metadata = Collections.emptyMap();
+ this.metadata = new HashMap();
+ this.metadata.put("source", "ANS");
metaInfo = new MetaInfo() {
@Override
public String getAppName() {
@@ -48,16 +53,44 @@ public class AnsServer extends Server {
@Override
public String getServiceIdForDiscovery() {
- return null;
+ return dom;
}
@Override
public String getInstanceId() {
- return null;
+ return AnsServer.this.host.getIp() + ":" + dom + ":"
+ + AnsServer.this.host.getPort();
}
};
}
+ @Override
+ public boolean isAlive() {
+
+ return true;
+ }
+
+ /**
+ *
+ * @param timeOut Unit: Seconds
+ * @return
+ */
+ public boolean isAlive(long timeOut) {
+ try {
+ String hostName = this.host.getHostname();
+ hostName = hostName != null && hostName.trim().length() > 0 ? hostName
+ : this.host.getIp();
+ Socket socket = new Socket();
+ socket.connect(new InetSocketAddress(hostName, this.host.getPort()),
+ (int) TimeUnit.SECONDS.toMillis(timeOut));
+ socket.close();
+ return true;
+ }
+ catch (IOException e) {
+ return false;
+ }
+ }
+
@Override
public MetaInfo getMetaInfo() {
return metaInfo;
@@ -71,4 +104,9 @@ public class AnsServer extends Server {
return metadata;
}
+ @Override
+ public String toString() {
+ return "AnsServer{" + "metaInfo=" + metaInfo + ", host=" + host + ", metadata="
+ + metadata + '}';
+ }
}
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java
index f34f19ff..74472369 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java
@@ -16,19 +16,21 @@
package org.springframework.cloud.alicloud.ans.ribbon;
-import java.util.ArrayList;
-import java.util.List;
-
import com.alibaba.ans.core.NamingService;
import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @author xiaolongzuo
*/
public class AnsServerList extends AbstractServerList {
+ private final static int CONNECT_TIME_OUT = 3;
+
private String dom;
public AnsServerList(String dom) {
@@ -60,10 +62,12 @@ public class AnsServerList extends AbstractServerList {
List result = new ArrayList(hosts.size());
for (Host host : hosts) {
if (host.isValid()) {
- result.add(hostToServer(host));
+ AnsServer ansServer = hostToServer(host);
+ if (ansServer.isAlive(CONNECT_TIME_OUT)) {
+ result.add(ansServer);
+ }
}
}
-
return result;
}
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/MigrateRibbonCofiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/MigrateRibbonCofiguration.java
new file mode 100644
index 00000000..9074b786
--- /dev/null
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/MigrateRibbonCofiguration.java
@@ -0,0 +1,19 @@
+package org.springframework.cloud.alicloud.ans.ribbon;
+
+import com.netflix.client.config.IClientConfig;
+import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionClass;
+import org.springframework.cloud.alicloud.ans.migrate.MigrateRibbonBeanPostProcessor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Conditional(MigrateOnConditionClass.class)
+public class MigrateRibbonCofiguration {
+
+ @Bean
+ public MigrateRibbonBeanPostProcessor migrateBeanPostProcessor(IClientConfig clientConfig) {
+
+ return new MigrateRibbonBeanPostProcessor(clientConfig);
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java
index 4333cb53..cf7d52ff 100644
--- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java
+++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java
@@ -34,6 +34,7 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnRibbonAns
@AutoConfigureAfter(RibbonAutoConfiguration.class)
-@RibbonClients(defaultConfiguration = AnsRibbonClientConfiguration.class)
+@RibbonClients(defaultConfiguration = { AnsRibbonClientConfiguration.class,
+ MigrateRibbonCofiguration.class })
public class RibbonAnsAutoConfiguration {
}
diff --git a/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories b/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories
index 63d6cd5c..f733a74e 100644
--- a/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories
@@ -1,6 +1,8 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alicloud.ans.endpoint.AnsEndpointAutoConfiguration,\
org.springframework.cloud.alicloud.ans.ribbon.RibbonAnsAutoConfiguration,\
- org.springframework.cloud.alicloud.ans.AnsAutoConfiguration
+ org.springframework.cloud.alicloud.ans.AnsAutoConfiguration,\
+ org.springframework.cloud.alicloud.ans.migrate.MigrateEndpointAutoConfiguration,\
+ org.springframework.cloud.alicloud.ans.migrate.MigrationAutoconfiguration
org.springframework.cloud.client.discovery.EnableDiscoveryClient=\
- org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration
+ org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration
\ No newline at end of file
diff --git a/spring-cloud-alicloud-context/pom.xml b/spring-cloud-alicloud-context/pom.xml
index 39e73ab5..496aea37 100644
--- a/spring-cloud-alicloud-context/pom.xml
+++ b/spring-cloud-alicloud-context/pom.xml
@@ -50,6 +50,12 @@
provided