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

sync sentinel in finchley:

1. support spring cloud gateway and webflux
2. fix bug about feign
3. enhance converter
This commit is contained in:
fangjian0423
2019-05-08 16:12:47 +08:00
parent 151584329b
commit f1ef11edcb
22 changed files with 678 additions and 261 deletions

View File

@@ -18,26 +18,35 @@ package org.springframework.cloud.alibaba.sentinel;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
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;
/**
* @author xiaojing
*/
@Configuration
@ConditionalOnWebApplication
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(CommonFilter.class)
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelWebAutoConfiguration {
@@ -48,6 +57,22 @@ public class SentinelWebAutoConfiguration {
@Autowired
private SentinelProperties properties;
@Autowired
private Optional<UrlCleaner> urlCleanerOptional;
@Autowired
private Optional<UrlBlockHandler> urlBlockHandlerOptional;
@Autowired
private Optional<RequestOriginParser> requestOriginParserOptional;
@PostConstruct
public void init() {
urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler);
urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner);
requestOriginParserOptional.ifPresent(WebCallbackManager::setRequestOriginParser);
}
@Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
public FilterRegistrationBean sentinelFilter() {
@@ -66,7 +91,8 @@ public class SentinelWebAutoConfiguration {
Filter filter = new CommonFilter();
registration.setFilter(filter);
registration.setOrder(filterConfig.getOrder());
log.info("[Sentinel Starter] register Sentinel with urlPatterns: {}.",
log.info(
"[Sentinel Starter] register Sentinel CommonFilter with urlPatterns: {}.",
filterConfig.getUrlPatterns());
return registration;

View File

@@ -0,0 +1,92 @@
/*
* 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 java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
import com.alibaba.csp.sentinel.adapter.spring.webflux.SentinelWebFluxFilter;
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.WebFluxCallbackManager;
import com.alibaba.csp.sentinel.adapter.spring.webflux.exception.SentinelBlockExceptionHandler;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@Configuration
@ConditionalOnWebApplication(type = Type.REACTIVE)
@ConditionalOnClass(SentinelReactorTransformer.class)
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelWebFluxAutoConfiguration {
private static final Logger log = LoggerFactory
.getLogger(SentinelWebFluxAutoConfiguration.class);
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
@Autowired
private Optional<BlockRequestHandler> blockRequestHandler;
public SentinelWebFluxAutoConfiguration(
ObjectProvider<List<ViewResolver>> viewResolvers,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@PostConstruct
public void init() {
blockRequestHandler.ifPresent(WebFluxCallbackManager::setBlockHandler);
}
@Bean
@Order(-2)
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
public SentinelBlockExceptionHandler sentinelBlockExceptionHandler() {
return new SentinelBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
public SentinelWebFluxFilter sentinelWebFluxFilter() {
log.info("[Sentinel Starter] register Sentinel SentinelWebFluxFilter");
return new SentinelWebFluxFilter();
}
}

View File

@@ -16,7 +16,11 @@
package org.springframework.cloud.alibaba.sentinel.custom;
import java.util.Optional;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
@@ -33,12 +37,14 @@ import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConver
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
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.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateGroupItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import com.alibaba.csp.sentinel.config.SentinelConfig;
@@ -52,7 +58,15 @@ import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.util.AppNameUtil;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
/**
@@ -71,15 +85,6 @@ public class SentinelAutoConfiguration {
@Autowired
private SentinelProperties properties;
@Autowired
private Optional<UrlCleaner> urlCleanerOptional;
@Autowired
private Optional<UrlBlockHandler> urlBlockHandlerOptional;
@Autowired
private Optional<RequestOriginParser> requestOriginParserOptional;
@PostConstruct
private void init() {
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR))
@@ -142,10 +147,6 @@ public class SentinelAutoConfiguration {
WebServletConfig.setBlockPage(properties.getServlet().getBlockPage());
}
urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler);
urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner);
requestOriginParserOptional.ifPresent(WebCallbackManager::setRequestOriginParser);
// earlier initialize
if (properties.isEager()) {
InitExecutor.doInit();
@@ -170,72 +171,164 @@ public class SentinelAutoConfiguration {
@Bean
public SentinelDataSourceHandler sentinelDataSourceHandler(
DefaultListableBeanFactory beanFactory) {
return new SentinelDataSourceHandler(beanFactory);
DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties,
Environment env) {
return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env);
}
@ConditionalOnClass(ObjectMapper.class)
@Configuration
protected static class SentinelConverterConfiguration {
private ObjectMapper objectMapper = new ObjectMapper();
static class ApiPredicateItemDeserializer
extends StdDeserializer<ApiPredicateItem> {
private Map<String, Class<? extends ApiPredicateItem>> registry = new HashMap<String, Class<? extends ApiPredicateItem>>();
@Bean("sentinel-json-flow-converter")
public JsonConverter jsonFlowConverter() {
return new JsonConverter(objectMapper, FlowRule.class);
ApiPredicateItemDeserializer() {
super(ApiPredicateItem.class);
}
void registerApiPredicateItem(String uniqueAttribute,
Class<? extends ApiPredicateItem> apiPredicateItemClass) {
registry.put(uniqueAttribute, apiPredicateItemClass);
}
@Override
public ApiPredicateItem deserialize(JsonParser jp,
DeserializationContext ctxt) throws IOException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = mapper.readTree(jp);
Class<? extends ApiPredicateItem> apiPredicateItemClass = null;
Iterator<Entry<String, JsonNode>> elementsIterator = root.fields();
while (elementsIterator.hasNext()) {
Entry<String, JsonNode> element = elementsIterator.next();
String name = element.getKey();
if (registry.containsKey(name)) {
apiPredicateItemClass = registry.get(name);
break;
}
}
if (apiPredicateItemClass == null) {
return null;
}
return mapper.readValue(root.toString(), apiPredicateItemClass);
}
}
@Bean("sentinel-json-degrade-converter")
public JsonConverter jsonDegradeConverter() {
return new JsonConverter(objectMapper, DegradeRule.class);
@Configuration
protected static class SentinelJsonConfiguration {
private ObjectMapper objectMapper = new ObjectMapper();
public SentinelJsonConfiguration() {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
ApiPredicateItemDeserializer deserializer = new ApiPredicateItemDeserializer();
deserializer.registerApiPredicateItem("pattern",
ApiPathPredicateItem.class);
deserializer.registerApiPredicateItem("items",
ApiPredicateGroupItem.class);
SimpleModule module = new SimpleModule(
"PolymorphicApiPredicateItemDeserializerModule",
new Version(1, 0, 0, null));
module.addDeserializer(ApiPredicateItem.class, deserializer);
objectMapper.registerModule(module);
}
@Bean("sentinel-json-flow-converter")
public JsonConverter jsonFlowConverter() {
return new JsonConverter(objectMapper, FlowRule.class);
}
@Bean("sentinel-json-degrade-converter")
public JsonConverter jsonDegradeConverter() {
return new JsonConverter(objectMapper, DegradeRule.class);
}
@Bean("sentinel-json-system-converter")
public JsonConverter jsonSystemConverter() {
return new JsonConverter(objectMapper, SystemRule.class);
}
@Bean("sentinel-json-authority-converter")
public JsonConverter jsonAuthorityConverter() {
return new JsonConverter(objectMapper, AuthorityRule.class);
}
@Bean("sentinel-json-param-flow-converter")
public JsonConverter jsonParamFlowConverter() {
return new JsonConverter(objectMapper, ParamFlowRule.class);
}
@Bean("sentinel-json-gateway-flow-converter")
public JsonConverter jsonGatewayFlowConverter() {
return new JsonConverter(objectMapper, GatewayFlowRule.class);
}
@Bean("sentinel-json-api-converter")
public JsonConverter jsonApiConverter() {
return new JsonConverter(objectMapper, ApiDefinition.class);
}
}
@Bean("sentinel-json-system-converter")
public JsonConverter jsonSystemConverter() {
return new JsonConverter(objectMapper, SystemRule.class);
@ConditionalOnClass(XmlMapper.class)
@Configuration
protected static class SentinelXmlConfiguration {
private XmlMapper xmlMapper = new XmlMapper();
public SentinelXmlConfiguration() {
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
ApiPredicateItemDeserializer deserializer = new ApiPredicateItemDeserializer();
deserializer.registerApiPredicateItem("pattern",
ApiPathPredicateItem.class);
deserializer.registerApiPredicateItem("items",
ApiPredicateGroupItem.class);
SimpleModule module = new SimpleModule(
"PolymorphicGatewayDeserializerModule",
new Version(1, 0, 0, null));
module.addDeserializer(ApiPredicateItem.class, deserializer);
xmlMapper.registerModule(module);
}
@Bean("sentinel-xml-flow-converter")
public XmlConverter xmlFlowConverter() {
return new XmlConverter(xmlMapper, FlowRule.class);
}
@Bean("sentinel-xml-degrade-converter")
public XmlConverter xmlDegradeConverter() {
return new XmlConverter(xmlMapper, DegradeRule.class);
}
@Bean("sentinel-xml-system-converter")
public XmlConverter xmlSystemConverter() {
return new XmlConverter(xmlMapper, SystemRule.class);
}
@Bean("sentinel-xml-authority-converter")
public XmlConverter xmlAuthorityConverter() {
return new XmlConverter(xmlMapper, AuthorityRule.class);
}
@Bean("sentinel-xml-param-flow-converter")
public XmlConverter xmlParamFlowConverter() {
return new XmlConverter(xmlMapper, ParamFlowRule.class);
}
@Bean("sentinel-xml-gateway-flow-converter")
public XmlConverter xmlGatewayFlowConverter() {
return new XmlConverter(xmlMapper, GatewayFlowRule.class);
}
@Bean("sentinel-xml-api-converter")
public XmlConverter xmlApiConverter() {
return new XmlConverter(xmlMapper, ApiDefinition.class);
}
}
@Bean("sentinel-json-authority-converter")
public JsonConverter jsonAuthorityConverter() {
return new JsonConverter(objectMapper, AuthorityRule.class);
}
@Bean("sentinel-json-param-flow-converter")
public JsonConverter jsonParamFlowConverter() {
return new JsonConverter(objectMapper, ParamFlowRule.class);
}
}
@ConditionalOnClass(XmlMapper.class)
protected static class SentinelXmlConfiguration {
private XmlMapper xmlMapper = new XmlMapper();
@Bean("sentinel-xml-flow-converter")
public XmlConverter xmlFlowConverter() {
return new XmlConverter(xmlMapper, FlowRule.class);
}
@Bean("sentinel-xml-degrade-converter")
public XmlConverter xmlDegradeConverter() {
return new XmlConverter(xmlMapper, DegradeRule.class);
}
@Bean("sentinel-xml-system-converter")
public XmlConverter xmlSystemConverter() {
return new XmlConverter(xmlMapper, SystemRule.class);
}
@Bean("sentinel-xml-authority-converter")
public XmlConverter xmlAuthorityConverter() {
return new XmlConverter(xmlMapper, AuthorityRule.class);
}
@Bean("sentinel-xml-param-flow-converter")
public XmlConverter xmlParamFlowConverter() {
return new XmlConverter(xmlMapper, ParamFlowRule.class);
}
}
}

View File

@@ -1,29 +1,30 @@
package org.springframework.cloud.alibaba.sentinel.custom;
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
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.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
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 com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
/**
* Sentinel {@link ReadableDataSource} Handler Handle the configurations of
@@ -47,12 +48,16 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
private final DefaultListableBeanFactory beanFactory;
public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
private final SentinelProperties sentinelProperties;
@Autowired
private SentinelProperties sentinelProperties;
private final Environment env;
public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory,
SentinelProperties sentinelProperties, Environment env) {
this.beanFactory = beanFactory;
this.sentinelProperties = sentinelProperties;
this.env = env;
}
@Override
public void afterSingletonsInstantiated() {
@@ -68,6 +73,7 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
}
AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties
.getValidDataSourceProperties();
abstractDataSourceProperties.setEnv(env);
abstractDataSourceProperties.preCheck(dataSourceName);
registerBean(abstractDataSourceProperties, dataSourceName
+ "-sentinel-" + validFields.get(0) + "-datasource");
@@ -189,7 +195,7 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
}
private void logAndCheckRuleType(AbstractDataSource dataSource, String dataSourceName,
Class<? extends AbstractRule> ruleClass) {
Class ruleClass) {
Object ruleConfig;
try {
ruleConfig = dataSource.loadConfig();
@@ -199,8 +205,8 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
+ " loadConfig error: " + e.getMessage(), e);
return;
}
if (ruleConfig instanceof List) {
List convertedRuleList = (List) ruleConfig;
if (ruleConfig instanceof List || ruleConfig instanceof Set) {
Collection convertedRuleList = (Collection) ruleConfig;
if (CollectionUtils.isEmpty(convertedRuleList)) {
log.warn("[Sentinel Starter] DataSource {} rule list is empty.",
dataSourceName);

View File

@@ -1,5 +1,6 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.sentinel.SentinelWebAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.SentinelWebFluxAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.feign.SentinelFeignAutoConfiguration