From f1ef11edcb3ea687a4b0e0a8c24bbb5ffbcc3cff Mon Sep 17 00:00:00 2001 From: fangjian0423 Date: Wed, 8 May 2019 16:12:47 +0800 Subject: [PATCH] sync sentinel in finchley: 1. support spring cloud gateway and webflux 2. fix bug about feign 3. enhance converter --- pom.xml | 2 +- spring-cloud-alibaba-dependencies/pom.xml | 20 +- .../pom.xml | 6 + .../alibaba/sentinel/datasource/RuleType.java | 12 +- .../config/AbstractDataSourceProperties.java | 19 ++ .../config/NacosDataSourceProperties.java | 17 +- .../config/ZookeeperDataSourceProperties.java | 13 + .../converter/SentinelConverter.java | 55 ++-- .../datasource/SentinelConverterTests.java | 6 +- .../README.md | 2 +- .../pom.xml | 15 +- ...elSpringCloudGatewayAutoConfiguration.java | 90 +++++++ .../zuul/SentinelZuulAutoConfiguration.java | 118 +++++++++ .../zuul/handler/FallBackProviderHandler.java | 10 +- .../main/resources/META-INF/spring.factories | 3 +- .../zuul/SentinelZuulAutoConfiguration.java | 114 --------- spring-cloud-alibaba-sentinel/pom.xml | 33 ++- .../SentinelWebAutoConfiguration.java | 30 ++- .../SentinelWebFluxAutoConfiguration.java | 92 +++++++ .../custom/SentinelAutoConfiguration.java | 239 ++++++++++++------ .../custom/SentinelDataSourceHandler.java | 42 +-- .../main/resources/META-INF/spring.factories | 1 + 22 files changed, 678 insertions(+), 261 deletions(-) rename {spring-cloud-alibaba-sentinel-zuul => spring-cloud-alibaba-sentinel-gateway}/README.md (98%) rename {spring-cloud-alibaba-sentinel-zuul => spring-cloud-alibaba-sentinel-gateway}/pom.xml (73%) create mode 100644 spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelSpringCloudGatewayAutoConfiguration.java create mode 100644 spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java rename {spring-cloud-alibaba-sentinel-zuul => spring-cloud-alibaba-sentinel-gateway}/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/handler/FallBackProviderHandler.java (76%) rename {spring-cloud-alibaba-sentinel-zuul => spring-cloud-alibaba-sentinel-gateway}/src/main/resources/META-INF/spring.factories (54%) delete mode 100644 spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java create mode 100644 spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebFluxAutoConfiguration.java diff --git a/pom.xml b/pom.xml index b383cf27..4543d0aa 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,7 @@ spring-cloud-alibaba-dependencies spring-cloud-alibaba-sentinel spring-cloud-alibaba-sentinel-datasource - spring-cloud-alibaba-sentinel-zuul + spring-cloud-alibaba-sentinel-gateway spring-cloud-alibaba-nacos-config spring-cloud-alibaba-nacos-discovery spring-cloud-alibaba-seata diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index 94bfa05e..bb075ac5 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -17,7 +17,7 @@ Spring Cloud Alibaba Dependencies - 1.5.2 + 1.6.0 3.1.0 0.4.2 1.0.0 @@ -152,6 +152,11 @@ sentinel-zuul-adapter ${sentinel.version} + + com.alibaba.csp + sentinel-spring-cloud-gateway-adapter + ${sentinel.version} + com.alibaba.csp sentinel-transport-simple-http @@ -187,6 +192,17 @@ sentinel-cluster-client-default ${sentinel.version} + + com.alibaba.csp + sentinel-spring-webflux-adapter + ${sentinel.version} + + + + com.alibaba.csp + sentinel-api-gateway-adapter-common + ${sentinel.version} + @@ -252,7 +268,7 @@ org.springframework.cloud - spring-cloud-alibaba-sentinel-zuul + spring-cloud-alibaba-sentinel-gateway ${project.version} diff --git a/spring-cloud-alibaba-sentinel-datasource/pom.xml b/spring-cloud-alibaba-sentinel-datasource/pom.xml index 81817ae7..a7ea7472 100644 --- a/spring-cloud-alibaba-sentinel-datasource/pom.xml +++ b/spring-cloud-alibaba-sentinel-datasource/pom.xml @@ -27,6 +27,12 @@ true + + com.alibaba.csp + sentinel-api-gateway-adapter-common + true + + com.alibaba.csp sentinel-datasource-nacos diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/RuleType.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/RuleType.java index e59a5735..2318f321 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/RuleType.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/RuleType.java @@ -6,6 +6,8 @@ import java.util.Optional; import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties; import org.springframework.util.StringUtils; +import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition; +import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.slots.block.AbstractRule; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; @@ -40,7 +42,15 @@ public enum RuleType { /** * authority */ - AUTHORITY("authority", AuthorityRule.class); + AUTHORITY("authority", AuthorityRule.class), + /** + * gateway flow + */ + GW_FLOW("gw-flow", GatewayFlowRule.class), + /** + * api + */ + GW_API_GROUP("gw-api-group", ApiDefinition.class); /** * alias for {@link AbstractRule} diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/AbstractDataSourceProperties.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/AbstractDataSourceProperties.java index 272252c2..0b830217 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/AbstractDataSourceProperties.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/AbstractDataSourceProperties.java @@ -4,7 +4,10 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import org.springframework.cloud.alibaba.sentinel.datasource.RuleType; +import org.springframework.core.env.Environment; +import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager; +import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.datasource.AbstractDataSource; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; @@ -28,6 +31,8 @@ public class AbstractDataSourceProperties { private String converterClass; @JsonIgnore private final String factoryBeanName; + @JsonIgnore + private Environment env; public AbstractDataSourceProperties(String factoryBeanName) { this.factoryBeanName = factoryBeanName; @@ -61,6 +66,14 @@ public class AbstractDataSourceProperties { return factoryBeanName; } + protected Environment getEnv() { + return env; + } + + public void setEnv(Environment env) { + this.env = env; + } + public void preCheck(String dataSourceName) { } @@ -82,6 +95,12 @@ public class AbstractDataSourceProperties { case AUTHORITY: AuthorityRuleManager.register2Property(dataSource.getProperty()); break; + case GW_FLOW: + GatewayRuleManager.register2Property(dataSource.getProperty()); + break; + case GW_API_GROUP: + GatewayApiDefinitionManager.register2Property(dataSource.getProperty()); + break; default: break; } diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java index 9df4d473..12c6e7f7 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java @@ -2,8 +2,6 @@ package org.springframework.cloud.alibaba.sentinel.datasource.config; import javax.validation.constraints.NotEmpty; -import org.springframework.cloud.alibaba.sentinel.datasource.RuleType; -import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants; import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean; import org.springframework.util.StringUtils; @@ -34,9 +32,13 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { @Override public void preCheck(String dataSourceName) { - if (StringUtils.isEmpty(serverAddr) && acmPropertiesInvalid()) { - throw new IllegalArgumentException( - "NacosDataSource properties value not correct. serverAddr is empty but there is empty value in accessKey, secretKey, endpoint, namespace property"); + if (StringUtils.isEmpty(serverAddr)) { + serverAddr = this.getEnv().getProperty( + "spring.cloud.sentinel.datasource.nacos.server-addr", ""); + if (StringUtils.isEmpty(serverAddr)) { + throw new IllegalArgumentException( + "NacosDataSource server-addr is empty"); + } } } @@ -96,9 +98,4 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { this.secretKey = secretKey; } - public boolean acmPropertiesInvalid() { - return StringUtils.isEmpty(endpoint) || StringUtils.isEmpty(accessKey) - || StringUtils.isEmpty(secretKey) || StringUtils.isEmpty(namespace); - } - } diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/ZookeeperDataSourceProperties.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/ZookeeperDataSourceProperties.java index 0ebfee4d..65fcaf09 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/ZookeeperDataSourceProperties.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/ZookeeperDataSourceProperties.java @@ -3,6 +3,7 @@ package org.springframework.cloud.alibaba.sentinel.datasource.config; import javax.validation.constraints.NotEmpty; import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean; +import org.springframework.util.StringUtils; /** * Zookeeper Properties class Using by {@link DataSourcePropertiesConfiguration} and @@ -25,6 +26,18 @@ public class ZookeeperDataSourceProperties extends AbstractDataSourceProperties private String dataId; + @Override + public void preCheck(String dataSourceName) { + if (StringUtils.isEmpty(serverAddr)) { + serverAddr = this.getEnv() + .getProperty("spring.cloud.sentinel.datasource.zk.server-addr", ""); + if (StringUtils.isEmpty(serverAddr)) { + throw new IllegalArgumentException( + "ZookeeperDataSource server-addr is empty"); + } + } + } + public String getServerAddr() { return serverAddr; } diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/converter/SentinelConverter.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/converter/SentinelConverter.java index 302bcd45..649f8f3b 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/converter/SentinelConverter.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/converter/SentinelConverter.java @@ -1,7 +1,20 @@ package org.springframework.cloud.alibaba.sentinel.datasource.converter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.alibaba.sentinel.datasource.RuleType; +import org.springframework.util.StringUtils; + +import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition; +import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.datasource.Converter; -import com.alibaba.csp.sentinel.slots.block.AbstractRule; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; @@ -13,15 +26,6 @@ import com.alibaba.csp.sentinel.slots.system.SystemRule; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.alibaba.sentinel.datasource.RuleType; -import org.springframework.util.StringUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Optional; /** * Convert sentinel rules for json or xml array Using strict mode to parse json or xml @@ -34,8 +38,8 @@ import java.util.Optional; * @see ParamFlowRule * @see ObjectMapper */ -public abstract class SentinelConverter - implements Converter> { +public abstract class SentinelConverter + implements Converter> { private static final Logger log = LoggerFactory.getLogger(SentinelConverter.class); @@ -49,11 +53,20 @@ public abstract class SentinelConverter } @Override - public List convert(String source) { - List ruleList = new ArrayList<>(); + public Collection convert(String source) { + Collection ruleCollection; + + // hard code + if (ruleClass == GatewayFlowRule.class || ruleClass == ApiDefinition.class) { + ruleCollection = new HashSet<>(); + } + else { + ruleCollection = new ArrayList<>(); + } + if (StringUtils.isEmpty(source)) { log.warn("converter can not convert rules because source is empty"); - return ruleList; + return ruleCollection; } try { List sourceArray = objectMapper.readValue(source, @@ -70,11 +83,11 @@ public abstract class SentinelConverter } Optional.ofNullable(convertRule(item)) - .ifPresent(convertRule -> ruleList.add(convertRule)); + .ifPresent(convertRule -> ruleCollection.add(convertRule)); }); - if (ruleList.size() != sourceArray.size()) { - throw new IllegalArgumentException("convert " + ruleList.size() + if (ruleCollection.size() != sourceArray.size()) { + throw new IllegalArgumentException("convert " + ruleCollection.size() + " rules but there are " + sourceArray.size() + " rules from datasource. RuleClass: " + ruleClass.getSimpleName()); @@ -83,12 +96,12 @@ public abstract class SentinelConverter catch (Exception e) { throw new RuntimeException("convert error: " + e.getMessage(), e); } - return ruleList; + return ruleCollection; } - private AbstractRule convertRule(String ruleStr) { + private Object convertRule(String ruleStr) { try { - final AbstractRule rule = objectMapper.readValue(ruleStr, ruleClass); + final Object rule = objectMapper.readValue(ruleStr, ruleClass); RuleType ruleType = RuleType.getByClass(ruleClass).get(); switch (ruleType) { case FLOW: diff --git a/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelConverterTests.java b/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelConverterTests.java index c6ae7a67..c4ffdc3b 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelConverterTests.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelConverterTests.java @@ -46,7 +46,7 @@ public class SentinelConverterTests { @Test public void testJsonConverter() { JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class); - List flowRules = jsonConverter + List flowRules = (List) jsonConverter .convert(readFileContent("classpath: flowrule.json")); assertEquals("json converter flow rule size was wrong", 1, flowRules.size()); assertEquals("json converter flow rule resource name was wrong", "resource", @@ -67,7 +67,7 @@ public class SentinelConverterTests { @Test public void testConverterEmptyContent() { JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class); - List flowRules = jsonConverter.convert(""); + List flowRules = (List) jsonConverter.convert(""); assertEquals("json converter flow rule size was not empty", 0, flowRules.size()); } @@ -86,7 +86,7 @@ public class SentinelConverterTests { @Test public void testXmlConverter() { XmlConverter jsonConverter = new XmlConverter(xmlMapper, FlowRule.class); - List flowRules = jsonConverter + List flowRules = (List) jsonConverter .convert(readFileContent("classpath: flowrule.xml")); assertEquals("xml converter flow rule size was wrong", 2, flowRules.size()); assertEquals("xml converter flow rule1 resource name was wrong", "resource", diff --git a/spring-cloud-alibaba-sentinel-zuul/README.md b/spring-cloud-alibaba-sentinel-gateway/README.md similarity index 98% rename from spring-cloud-alibaba-sentinel-zuul/README.md rename to spring-cloud-alibaba-sentinel-gateway/README.md index 2d0d2fd1..8c8c4a02 100755 --- a/spring-cloud-alibaba-sentinel-zuul/README.md +++ b/spring-cloud-alibaba-sentinel-gateway/README.md @@ -14,7 +14,7 @@ Sentinel can provide `ServiceId` level and `API Path` level flow control for spr ```xml org.springframework.cloud - spring-cloud-alibaba-sentinel-zuul + spring-cloud-alibaba-sentinel-gateway x.y.z diff --git a/spring-cloud-alibaba-sentinel-zuul/pom.xml b/spring-cloud-alibaba-sentinel-gateway/pom.xml similarity index 73% rename from spring-cloud-alibaba-sentinel-zuul/pom.xml rename to spring-cloud-alibaba-sentinel-gateway/pom.xml index 4b1a526e..c7510e67 100644 --- a/spring-cloud-alibaba-sentinel-zuul/pom.xml +++ b/spring-cloud-alibaba-sentinel-gateway/pom.xml @@ -10,19 +10,28 @@ 4.0.0 org.springframework.cloud - spring-cloud-alibaba-sentinel-zuul - Spring Cloud Alibaba Sentinel Zuul + spring-cloud-alibaba-sentinel-gateway + Spring Cloud Alibaba Sentinel Gateway org.springframework.cloud spring-cloud-starter-netflix-zuul - provided + true com.alibaba.csp sentinel-zuul-adapter + + com.alibaba.csp + sentinel-spring-cloud-gateway-adapter + + + org.springframework.cloud + spring-cloud-starter-gateway + true + org.springframework.boot spring-boot-configuration-processor diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelSpringCloudGatewayAutoConfiguration.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelSpringCloudGatewayAutoConfiguration.java new file mode 100644 index 00000000..dd42c39f --- /dev/null +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelSpringCloudGatewayAutoConfiguration.java @@ -0,0 +1,90 @@ +/* + * 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 + * + * https://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.zuul; + +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.cloud.gateway.filter.GlobalFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +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.gateway.sc.SentinelGatewayFilter; +import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler; +import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; +import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler; + +/** + * @author Jim + */ +@Configuration +@ConditionalOnClass(GlobalFilter.class) +@ConditionalOnProperty(prefix = "spring.cloud.sentinel.spring-cloud-gateway", name = "enabled", havingValue = "true", matchIfMissing = true) +public class SentinelSpringCloudGatewayAutoConfiguration { + + private static final Logger logger = LoggerFactory + .getLogger(SentinelSpringCloudGatewayAutoConfiguration.class); + + private final List viewResolvers; + private final ServerCodecConfigurer serverCodecConfigurer; + + @Autowired + private Optional blockRequestHandlerOptional; + + @PostConstruct + private void init() { + blockRequestHandlerOptional.ifPresent(GatewayCallbackManager::setBlockHandler); + } + + public SentinelSpringCloudGatewayAutoConfiguration( + ObjectProvider> viewResolversProvider, + ServerCodecConfigurer serverCodecConfigurer) { + this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); + this.serverCodecConfigurer = serverCodecConfigurer; + } + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { + // Register the block exception handler for Spring Cloud Gateway. + logger.info( + "[Sentinel SpringCloudGateway] register SentinelGatewayBlockExceptionHandler"); + return new SentinelGatewayBlockExceptionHandler(viewResolvers, + serverCodecConfigurer); + } + + @Bean + @Order(-1) + public GlobalFilter sentinelGatewayFilter() { + logger.info("[Sentinel SpringCloudGateway] register SentinelGatewayFilter"); + return new SentinelGatewayFilter(); + } + +} diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java new file mode 100644 index 00000000..feb9524a --- /dev/null +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java @@ -0,0 +1,118 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * 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.zuul; + +import java.util.Optional; + +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.alibaba.sentinel.zuul.handler.FallBackProviderHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.RequestOriginParser; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.ZuulGatewayCallbackManager; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.http.ZuulServlet; + +/** + * Sentinel Spring Cloud Zuul AutoConfiguration + * + * @author tiger + */ +@Configuration +@ConditionalOnClass(ZuulServlet.class) +@ConditionalOnProperty(prefix = SentinelZuulAutoConfiguration.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) +public class SentinelZuulAutoConfiguration { + + private static final Logger logger = LoggerFactory + .getLogger(SentinelZuulAutoConfiguration.class); + + public static final String PREFIX = "spring.cloud.sentinel.zuul"; + + @Autowired + private Environment environment; + + @Autowired + private Optional requestOriginParserOptional; + + @PostConstruct + private void init() { + requestOriginParserOptional + .ifPresent(ZuulGatewayCallbackManager::setOriginParser); + } + + @Bean + public ZuulFilter sentinelZuulPreFilter() { + String preOrderStr = environment.getProperty(PREFIX + "." + "order.pre"); + int order = 10000; + try { + order = Integer.parseInt(preOrderStr); + } + catch (NumberFormatException e) { + // ignore + } + logger.info("[Sentinel Zuul] register SentinelZuulPreFilter {}", order); + return new SentinelZuulPreFilter(order); + } + + @Bean + public ZuulFilter sentinelZuulPostFilter() { + String postOrderStr = environment.getProperty(PREFIX + "." + "order.post"); + int order = 1000; + try { + order = Integer.parseInt(postOrderStr); + } + catch (NumberFormatException e) { + // ignore + } + logger.info("[Sentinel Zuul] register SentinelZuulPostFilter {}", order); + return new SentinelZuulPostFilter(order); + } + + @Bean + public ZuulFilter sentinelZuulErrorFilter() { + String errorOrderStr = environment.getProperty(PREFIX + "." + "order.error"); + int order = -1; + try { + order = Integer.parseInt(errorOrderStr); + } + catch (NumberFormatException e) { + // ignore + } + logger.info("[Sentinel Zuul] register SentinelZuulErrorFilter {}", order); + return new SentinelZuulErrorFilter(order); + } + + @Bean + public FallBackProviderHandler fallBackProviderHandler( + DefaultListableBeanFactory beanFactory) { + return new FallBackProviderHandler(beanFactory); + } + +} diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/handler/FallBackProviderHandler.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/handler/FallBackProviderHandler.java similarity index 76% rename from spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/handler/FallBackProviderHandler.java rename to spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/handler/FallBackProviderHandler.java index 564fc446..6b3c21f6 100644 --- a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/handler/FallBackProviderHandler.java +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/handler/FallBackProviderHandler.java @@ -2,15 +2,15 @@ package org.springframework.cloud.alibaba.sentinel.zuul.handler; import java.util.Map; -import org.apache.commons.collections.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.util.CollectionUtils; -import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultBlockFallbackProvider; -import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackManager; -import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackProvider; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.DefaultBlockFallbackProvider; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider; /** * @author tiger @@ -30,7 +30,7 @@ public class FallBackProviderHandler implements SmartInitializingSingleton { public void afterSingletonsInstantiated() { Map providerMap = beanFactory .getBeansOfType(ZuulBlockFallbackProvider.class); - if (MapUtils.isNotEmpty(providerMap)) { + if (!CollectionUtils.isEmpty(providerMap)) { providerMap.forEach((k, v) -> { logger.info("[Sentinel Zuul] Register provider name:{}, instance: {}", k, v); diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-sentinel-gateway/src/main/resources/META-INF/spring.factories similarity index 54% rename from spring-cloud-alibaba-sentinel-zuul/src/main/resources/META-INF/spring.factories rename to spring-cloud-alibaba-sentinel-gateway/src/main/resources/META-INF/spring.factories index b4ced151..5917e8ff 100644 --- a/spring-cloud-alibaba-sentinel-zuul/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/resources/META-INF/spring.factories @@ -1,2 +1,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration \ No newline at end of file +org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration,\ +org.springframework.cloud.alibaba.sentinel.zuul.SentinelSpringCloudGatewayAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java deleted file mode 100644 index 35577cae..00000000 --- a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 1999-2018 Alibaba Group Holding Ltd. - * - * 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.zuul; - -import static org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration.PREFIX; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.alibaba.sentinel.zuul.handler.FallBackProviderHandler; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; - -import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultRequestOriginParser; -import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultUrlCleaner; -import com.alibaba.csp.sentinel.adapter.zuul.fallback.RequestOriginParser; -import com.alibaba.csp.sentinel.adapter.zuul.fallback.UrlCleaner; -import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelErrorFilter; -import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPostFilter; -import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPreFilter; -import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties; -import com.alibaba.csp.sentinel.util.StringUtil; - -import com.netflix.zuul.ZuulFilter; - -/** - * Sentinel Spring Cloud Zuul AutoConfiguration - * - * @author tiger - */ -@Configuration -@ConditionalOnProperty(prefix = PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) -public class SentinelZuulAutoConfiguration { - - @Autowired - private Environment environment; - - public static final String PREFIX = "spring.cloud.sentinel.zuul"; - - @Bean - public SentinelZuulProperties sentinelZuulProperties() { - SentinelZuulProperties properties = new SentinelZuulProperties(); - String enabledStr = environment.getProperty(PREFIX + "." + "enabled"); - String preOrderStr = environment.getProperty(PREFIX + "." + "order.pre"); - String postOrderStr = environment.getProperty(PREFIX + "." + "order.post"); - String errorOrderStr = environment.getProperty(PREFIX + "." + "order.error"); - if (StringUtil.isNotEmpty(enabledStr)) { - Boolean enabled = Boolean.valueOf(enabledStr); - properties.setEnabled(enabled); - } - if (StringUtil.isNotEmpty(preOrderStr)) { - properties.getOrder().setPre(Integer.parseInt(preOrderStr)); - } - if (StringUtil.isNotEmpty(postOrderStr)) { - properties.getOrder().setPost(Integer.parseInt(postOrderStr)); - } - if (StringUtil.isNotEmpty(errorOrderStr)) { - properties.getOrder().setError(Integer.parseInt(errorOrderStr)); - } - return properties; - } - - @Bean - @ConditionalOnMissingBean(UrlCleaner.class) - public UrlCleaner urlCleaner() { - return new DefaultUrlCleaner(); - } - - @Bean - @ConditionalOnMissingBean(RequestOriginParser.class) - public RequestOriginParser requestOriginParser() { - return new DefaultRequestOriginParser(); - } - - @Bean - public ZuulFilter preFilter(SentinelZuulProperties sentinelZuulProperties, - UrlCleaner urlCleaner, RequestOriginParser requestOriginParser) { - return new SentinelPreFilter(sentinelZuulProperties, urlCleaner, - requestOriginParser); - } - - @Bean - public ZuulFilter postFilter(SentinelZuulProperties sentinelZuulProperties) { - return new SentinelPostFilter(sentinelZuulProperties); - } - - @Bean - public ZuulFilter errorFilter(SentinelZuulProperties sentinelZuulProperties) { - return new SentinelErrorFilter(sentinelZuulProperties); - } - - @Bean - public FallBackProviderHandler fallBackProviderListener( - DefaultListableBeanFactory beanFactory) { - return new FallBackProviderHandler(beanFactory); - } - -} diff --git a/spring-cloud-alibaba-sentinel/pom.xml b/spring-cloud-alibaba-sentinel/pom.xml index 782f8876..d42d742f 100644 --- a/spring-cloud-alibaba-sentinel/pom.xml +++ b/spring-cloud-alibaba-sentinel/pom.xml @@ -42,6 +42,28 @@ true + + com.alibaba.csp + sentinel-web-servlet + + + + org.springframework.boot + spring-boot-starter-web + true + + + + com.alibaba.csp + sentinel-spring-webflux-adapter + + + + org.springframework.boot + spring-boot-starter-webflux + true + + org.springframework.cloud spring-cloud-starter-openfeign @@ -88,6 +110,11 @@ provided + + com.alibaba.csp + sentinel-api-gateway-adapter-common + + @@ -129,12 +156,6 @@ provided true - - org.springframework.boot - spring-boot-starter-web - provided - true - org.springframework.boot diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java index 5a73f2cb..37d77137 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java @@ -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 urlCleanerOptional; + + @Autowired + private Optional urlBlockHandlerOptional; + + @Autowired + private Optional 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; diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebFluxAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebFluxAutoConfiguration.java new file mode 100644 index 00000000..f36f326e --- /dev/null +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebFluxAutoConfiguration.java @@ -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 Jim + */ +@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 viewResolvers; + private final ServerCodecConfigurer serverCodecConfigurer; + + @Autowired + private Optional blockRequestHandler; + + public SentinelWebFluxAutoConfiguration( + ObjectProvider> 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(); + } + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java index d2423e00..46b10431 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java @@ -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 urlCleanerOptional; - - @Autowired - private Optional urlBlockHandlerOptional; - - @Autowired - private Optional 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 { + private Map> registry = new HashMap>(); - @Bean("sentinel-json-flow-converter") - public JsonConverter jsonFlowConverter() { - return new JsonConverter(objectMapper, FlowRule.class); + ApiPredicateItemDeserializer() { + super(ApiPredicateItem.class); + } + + void registerApiPredicateItem(String uniqueAttribute, + Class 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 apiPredicateItemClass = null; + Iterator> elementsIterator = root.fields(); + while (elementsIterator.hasNext()) { + Entry 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); - } - } } 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 df57f919..6b5fce5f 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,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 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); 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 d964e3b0..20f314cc 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 @@ -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