diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index bb075ac5..fc4b5d4d 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -17,7 +17,7 @@ Spring Cloud Alibaba Dependencies - 1.6.0 + 1.6.1 3.1.0 0.4.2 1.0.0 diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/resources/application.yaml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/resources/application.yaml index a614f5b7..a3304e39 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/resources/application.yaml +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/resources/application.yaml @@ -33,5 +33,11 @@ spring: dashboard: localhost:8080 filter: enabled: true + scg.fallback: + mode: redirect + redirect: http://www.taobao.com +# response-status: 444 +# response-body: 1234 +# content-type: text/plain management.endpoints.web.exposure.include: "*" \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpoint.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpoint.java index 1160db1b..b0134e77 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpoint.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpoint.java @@ -16,13 +16,6 @@ package org.springframework.cloud.alibaba.nacos.endpoint; -import org.springframework.boot.actuate.endpoint.annotation.Endpoint; -import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; -import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; -import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; -import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource; -import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory; - import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -30,6 +23,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; +import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource; +import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory; + /** * Endpoint for Nacos, contains config data and refresh history * @author xiaojing @@ -41,7 +41,12 @@ public class NacosConfigEndpoint { private final NacosRefreshHistory refreshHistory; - private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private ThreadLocal dateFormat = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + }; public NacosConfigEndpoint(NacosConfigProperties properties, NacosRefreshHistory refreshHistory) { @@ -60,7 +65,7 @@ public class NacosConfigEndpoint { for (NacosPropertySource ps : all) { Map source = new HashMap<>(16); source.put("dataId", ps.getDataId()); - source.put("lastSynced", dateFormat.format(ps.getTimestamp())); + source.put("lastSynced", dateFormat.get().format(ps.getTimestamp())); sources.add(source); } result.put("Sources", sources); diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshHistory.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshHistory.java index ec5a83ca..149453b6 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshHistory.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshHistory.java @@ -27,10 +27,15 @@ public class NacosRefreshHistory { private LinkedList records = new LinkedList<>(); - private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private ThreadLocal dateFormat = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + }; public void add(String dataId, String md5) { - records.addFirst(new Record(dateFormat.format(new Date()), dataId, md5)); + records.addFirst(new Record(dateFormat.get().format(new Date()), dataId, md5)); if (records.size() > MAX_SIZE) { records.removeLast(); } diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index c092f62a..9e348a1a 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -17,12 +17,9 @@ package org.springframework.cloud.alibaba.nacos; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.alibaba.nacos.discovery.NacosDiscoveryClientAutoConfiguration; import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration; import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration; import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry; diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/ConfigConstants.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/ConfigConstants.java new file mode 100644 index 00000000..a83f6cee --- /dev/null +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/ConfigConstants.java @@ -0,0 +1,33 @@ +/* + * 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.gateway; + +/** + * @author Jim + */ +public interface ConfigConstants { + + String APP_TYPE_ZUUL_GATEWAY = "12"; + + String ZUUl_PREFIX = "spring.cloud.sentinel.zuul"; + + String GATEWAY_PREFIX = "spring.cloud.sentinel.scg"; + + String FALLBACK_MSG_RESPONSE = "response"; + String FALLBACK_REDIRECT = "redirect"; + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/FallbackProperties.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/FallbackProperties.java new file mode 100644 index 00000000..7721571b --- /dev/null +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/FallbackProperties.java @@ -0,0 +1,93 @@ +/* + * 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.gateway; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +/** + * @author Jim + */ +public class FallbackProperties { + + /** + * The fallback mode for sentinel spring-cloud-gateway. choose `redirect` or + * `response`. + */ + private String mode; + /** + * Redirect Url for `redirect` mode. + */ + private String redirect; + /** + * Response Body for `response` mode. + */ + private String responseBody; + /** + * Response Status for `response` mode. + */ + private Integer responseStatus = HttpStatus.TOO_MANY_REQUESTS.value(); + /** + * Content-Type for `response` mode. + */ + private String contentType = MediaType.APPLICATION_JSON_UTF8.toString(); + + public String getMode() { + return mode; + } + + public FallbackProperties setMode(String mode) { + this.mode = mode; + return this; + } + + public String getRedirect() { + return redirect; + } + + public FallbackProperties setRedirect(String redirect) { + this.redirect = redirect; + return this; + } + + public String getResponseBody() { + return responseBody; + } + + public FallbackProperties setResponseBody(String responseBody) { + this.responseBody = responseBody; + return this; + } + + public Integer getResponseStatus() { + return responseStatus; + } + + public FallbackProperties setResponseStatus(Integer responseStatus) { + this.responseStatus = responseStatus; + return this; + } + + public String getContentType() { + return contentType; + } + + public FallbackProperties setContentType(String contentType) { + this.contentType = contentType; + return this; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/scg/SentinelGatewayProperties.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/scg/SentinelGatewayProperties.java new file mode 100644 index 00000000..64b61253 --- /dev/null +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/scg/SentinelGatewayProperties.java @@ -0,0 +1,42 @@ +/* + * 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.gateway.scg; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.cloud.alibaba.sentinel.gateway.ConfigConstants; +import org.springframework.cloud.alibaba.sentinel.gateway.FallbackProperties; + +/** + * @author Jim + */ +@ConfigurationProperties(prefix = ConfigConstants.GATEWAY_PREFIX) +public class SentinelGatewayProperties { + + @NestedConfigurationProperty + private FallbackProperties fallback; + + public FallbackProperties getFallback() { + return fallback; + } + + public SentinelGatewayProperties setFallback(FallbackProperties fallback) { + this.fallback = fallback; + return this; + } + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/scg/SentinelSCGAutoConfiguration.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/scg/SentinelSCGAutoConfiguration.java new file mode 100644 index 00000000..393e63cc --- /dev/null +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/scg/SentinelSCGAutoConfiguration.java @@ -0,0 +1,156 @@ +/* + * 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.gateway.scg; + +import static org.springframework.web.reactive.function.BodyInserters.fromObject; + +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.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alibaba.sentinel.gateway.ConfigConstants; +import org.springframework.cloud.alibaba.sentinel.gateway.FallbackProperties; +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.MediaType; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.reactive.result.view.ViewResolver; +import org.springframework.web.server.ServerWebExchange; + +import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants; +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.callback.RedirectBlockRequestHandler; +import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler; +import com.alibaba.csp.sentinel.config.SentinelConfig; +import com.alibaba.csp.sentinel.util.StringUtil; + +import reactor.core.publisher.Mono; + +/** + * @author Jim + */ +@Configuration +@ConditionalOnClass(GlobalFilter.class) +@ConditionalOnProperty(prefix = ConfigConstants.GATEWAY_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) +@EnableConfigurationProperties(SentinelGatewayProperties.class) +public class SentinelSCGAutoConfiguration { + + private static final Logger logger = LoggerFactory + .getLogger(SentinelSCGAutoConfiguration.class); + + private final List viewResolvers; + private final ServerCodecConfigurer serverCodecConfigurer; + + @Autowired + private Optional blockRequestHandlerOptional; + + @Autowired + private SentinelGatewayProperties gatewayProperties; + + @PostConstruct + private void init() { + // blockRequestHandlerOptional has low priority + blockRequestHandlerOptional.ifPresent(GatewayCallbackManager::setBlockHandler); + initAppType(); + initFallback(); + } + + public SentinelSCGAutoConfiguration( + ObjectProvider> viewResolversProvider, + ServerCodecConfigurer serverCodecConfigurer) { + this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); + this.serverCodecConfigurer = serverCodecConfigurer; + } + + private void initAppType() { + System.setProperty(SentinelConfig.APP_TYPE, + String.valueOf(SentinelGatewayConstants.APP_TYPE_GATEWAY)); + } + + private void initFallback() { + FallbackProperties fallbackProperties = gatewayProperties.getFallback(); + if (fallbackProperties == null + || StringUtil.isBlank(fallbackProperties.getMode())) { + return; + } + if (ConfigConstants.FALLBACK_MSG_RESPONSE.equals(fallbackProperties.getMode())) { + if (StringUtil.isNotBlank(fallbackProperties.getResponseBody())) { + GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() { + @Override + public Mono handleRequest(ServerWebExchange exchange, + Throwable t) { + return ServerResponse + .status(fallbackProperties.getResponseStatus()) + .contentType(MediaType + .valueOf(fallbackProperties.getContentType())) + .body(fromObject(fallbackProperties.getResponseBody())); + } + }); + logger.info( + "[Sentinel SpringCloudGateway] using AnonymousBlockRequestHandler, responseStatus: " + + fallbackProperties.getResponseStatus() + + ", responseBody: " + + fallbackProperties.getResponseStatus()); + } + } + String redirectUrl = fallbackProperties.getRedirect(); + if (ConfigConstants.FALLBACK_REDIRECT.equals(fallbackProperties.getMode()) + && StringUtil.isNotBlank(redirectUrl)) { + GatewayCallbackManager + .setBlockHandler(new RedirectBlockRequestHandler(redirectUrl)); + logger.info( + "[Sentinel SpringCloudGateway] using RedirectBlockRequestHandler, redirectUrl: " + + redirectUrl); + } + } + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + @ConditionalOnMissingBean + 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) + @ConditionalOnMissingBean + public SentinelGatewayFilter 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/handler/FallBackProviderHandler.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/zuul/FallBackProviderHandler.java similarity index 95% rename from spring-cloud-alibaba-sentinel-gateway/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/gateway/zuul/FallBackProviderHandler.java index 6b3c21f6..be27b988 100644 --- a/spring-cloud-alibaba-sentinel-gateway/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/gateway/zuul/FallBackProviderHandler.java @@ -1,4 +1,4 @@ -package org.springframework.cloud.alibaba.sentinel.zuul.handler; +package org.springframework.cloud.alibaba.sentinel.gateway.zuul; import java.util.Map; 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/gateway/zuul/SentinelZuulAutoConfiguration.java similarity index 64% rename from spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java rename to spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/zuul/SentinelZuulAutoConfiguration.java index feb9524a..0867df6a 100644 --- 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/gateway/zuul/SentinelZuulAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.alibaba.sentinel.zuul; +package org.springframework.cloud.alibaba.sentinel.gateway.zuul; import java.util.Optional; @@ -25,19 +25,20 @@ 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.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.alibaba.sentinel.zuul.handler.FallBackProviderHandler; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alibaba.sentinel.gateway.ConfigConstants; 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.alibaba.csp.sentinel.config.SentinelConfig; -import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.http.ZuulServlet; /** @@ -47,66 +48,49 @@ import com.netflix.zuul.http.ZuulServlet; */ @Configuration @ConditionalOnClass(ZuulServlet.class) -@ConditionalOnProperty(prefix = SentinelZuulAutoConfiguration.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnProperty(prefix = ConfigConstants.ZUUl_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) +@EnableConfigurationProperties(SentinelZuulProperties.class) 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; + @Autowired + private SentinelZuulProperties zuulProperties; + @PostConstruct private void init() { requestOriginParserOptional .ifPresent(ZuulGatewayCallbackManager::setOriginParser); + System.setProperty(SentinelConfig.APP_TYPE, + String.valueOf(ConfigConstants.APP_TYPE_ZUUL_GATEWAY)); } @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); + @ConditionalOnMissingBean + public SentinelZuulPreFilter sentinelZuulPreFilter() { + logger.info("[Sentinel Zuul] register SentinelZuulPreFilter {}", + zuulProperties.getOrder().getPre()); + return new SentinelZuulPreFilter(zuulProperties.getOrder().getPre()); } @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); + @ConditionalOnMissingBean + public SentinelZuulPostFilter sentinelZuulPostFilter() { + logger.info("[Sentinel Zuul] register SentinelZuulPostFilter {}", + zuulProperties.getOrder().getPost()); + return new SentinelZuulPostFilter(zuulProperties.getOrder().getPost()); } @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); + @ConditionalOnMissingBean + public SentinelZuulErrorFilter sentinelZuulErrorFilter() { + logger.info("[Sentinel Zuul] register SentinelZuulErrorFilter {}", + zuulProperties.getOrder().getError()); + return new SentinelZuulErrorFilter(zuulProperties.getOrder().getError()); } @Bean diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/zuul/SentinelZuulProperties.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/zuul/SentinelZuulProperties.java new file mode 100644 index 00000000..a89a1ad7 --- /dev/null +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/gateway/zuul/SentinelZuulProperties.java @@ -0,0 +1,88 @@ +/* + * 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.gateway.zuul; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.cloud.alibaba.sentinel.gateway.ConfigConstants; + +import com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant; +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; + +/** + * @author Jim + */ +@ConfigurationProperties(prefix = ConfigConstants.ZUUl_PREFIX) +public class SentinelZuulProperties { + + @NestedConfigurationProperty + private SentinelZuulProperties.Order order; + + public Order getOrder() { + return order; + } + + public SentinelZuulProperties setOrder(Order order) { + this.order = order; + return this; + } + + public static class Order { + + /** + * The order of {@link SentinelZuulPreFilter}. + */ + private int pre = 10000; + + /** + * The order of {@link SentinelZuulPostFilter}. + */ + private int post = ZuulConstant.SEND_RESPONSE_FILTER_ORDER; + + /** + * The order of {@link SentinelZuulErrorFilter}. + */ + private int error = -1; + + public int getPre() { + return pre; + } + + public void setPre(int pre) { + this.pre = pre; + } + + public int getPost() { + return post; + } + + public void setPost(int post) { + this.post = post; + } + + public int getError() { + return error; + } + + public void setError(int error) { + this.error = error; + } + } + +} \ No newline at end of file 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 deleted file mode 100644 index dd42c39f..00000000 --- a/spring-cloud-alibaba-sentinel-gateway/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelSpringCloudGatewayAutoConfiguration.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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/resources/META-INF/spring.factories b/spring-cloud-alibaba-sentinel-gateway/src/main/resources/META-INF/spring.factories index 5917e8ff..15297fce 100644 --- a/spring-cloud-alibaba-sentinel-gateway/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/resources/META-INF/spring.factories @@ -1,3 +1,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration,\ -org.springframework.cloud.alibaba.sentinel.zuul.SentinelSpringCloudGatewayAutoConfiguration \ No newline at end of file +org.springframework.cloud.alibaba.sentinel.gateway.zuul.SentinelZuulAutoConfiguration,\ +org.springframework.cloud.alibaba.sentinel.gateway.scg.SentinelSCGAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpoint.java b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpoint.java index 0133fe24..6160a5f6 100644 --- a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpoint.java +++ b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpoint.java @@ -16,13 +16,6 @@ package org.springframework.cloud.alicloud.acm.endpoint; -import org.springframework.boot.actuate.endpoint.annotation.Endpoint; -import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; -import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository; -import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource; -import org.springframework.cloud.alicloud.acm.refresh.AcmRefreshHistory; -import org.springframework.cloud.alicloud.context.acm.AcmProperties; - import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -30,6 +23,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository; +import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource; +import org.springframework.cloud.alicloud.acm.refresh.AcmRefreshHistory; +import org.springframework.cloud.alicloud.context.acm.AcmProperties; + /** * Created on 01/10/2017. * @@ -44,7 +44,12 @@ public class AcmEndpoint { private final AcmPropertySourceRepository propertySourceRepository; - private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private ThreadLocal dateFormat = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + }; public AcmEndpoint(AcmProperties properties, AcmRefreshHistory refreshHistory, AcmPropertySourceRepository propertySourceRepository) { @@ -65,7 +70,7 @@ public class AcmEndpoint { for (AcmPropertySource ps : all) { Map source = new HashMap<>(); source.put("dataId", ps.getDataId()); - source.put("lastSynced", dateFormat.format(ps.getTimestamp())); + source.put("lastSynced", dateFormat.get().format(ps.getTimestamp())); sources.add(source); } runtime.put("sources", sources); diff --git a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmRefreshHistory.java b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmRefreshHistory.java index 439e6360..19197b89 100644 --- a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmRefreshHistory.java +++ b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmRefreshHistory.java @@ -30,10 +30,15 @@ public class AcmRefreshHistory { private LinkedList records = new LinkedList<>(); - private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private ThreadLocal dateFormat = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + }; public void add(String dataId, String md5) { - records.addFirst(new Record(dateFormat.format(new Date()), dataId, md5)); + records.addFirst(new Record(dateFormat.get().format(new Date()), dataId, md5)); if (records.size() > MAX_SIZE) { records.removeLast(); }