diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigProperties.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigProperties.java index 0478ac887..853d8ee07 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigProperties.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigProperties.java @@ -81,7 +81,7 @@ public class NacosConfigProperties { .resolvePlaceholders("${spring.cloud.nacos.config.server-addr:}"); if (StringUtils.isEmpty(serverAddr)) { serverAddr = environment - .resolvePlaceholders("${spring.cloud.nacos.server-addr:}"); + .resolvePlaceholders("${spring.cloud.nacos.server-addr:localhost:8848}"); } this.setServerAddr(serverAddr); } diff --git a/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json index c9c872616..3d322070e 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -3,6 +3,7 @@ { "name": "spring.cloud.nacos.server-addr", "type": "java.lang.String", + "defaultValue": "localhost:8848", "description": "nacos server address." }, { diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java index 7e419ec6f..23e476876 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java @@ -431,7 +431,7 @@ public class NacosDiscoveryProperties { .resolvePlaceholders("${spring.cloud.nacos.discovery.server-addr:}"); if (StringUtils.isEmpty(serverAddr)) { serverAddr = env - .resolvePlaceholders("${spring.cloud.nacos.server-addr:}"); + .resolvePlaceholders("${spring.cloud.nacos.server-addr:localhost:8848}"); } this.setServerAddr(serverAddr); } diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 2f0718f95..b3dc069b9 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -2,6 +2,7 @@ { "name": "spring.cloud.nacos.server-addr", "type": "java.lang.String", + "defaultValue": "localhost:8848", "description": "nacos server address." }, { diff --git a/spring-cloud-alibaba-seata/pom.xml b/spring-cloud-alibaba-seata/pom.xml index 5f4a2802d..216008cc0 100644 --- a/spring-cloud-alibaba-seata/pom.xml +++ b/spring-cloud-alibaba-seata/pom.xml @@ -38,6 +38,12 @@ true + + org.springframework.cloud + spring-cloud-loadbalancer + true + + org.springframework.cloud spring-cloud-starter-netflix-ribbon diff --git a/spring-cloud-alibaba-seata/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignBlockingLoadBalancerClient.java b/spring-cloud-alibaba-seata/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignBlockingLoadBalancerClient.java new file mode 100644 index 000000000..3ad4a09ae --- /dev/null +++ b/spring-cloud-alibaba-seata/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignBlockingLoadBalancerClient.java @@ -0,0 +1,95 @@ +/* + * Copyright 2013-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 com.alibaba.cloud.seata.feign; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import feign.Client; +import feign.Request; +import feign.Response; +import io.seata.core.context.RootContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient; +import org.springframework.http.HttpStatus; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * @author yuhuangbin + */ +public class SeataFeignBlockingLoadBalancerClient implements Client { + + private static final Log LOG = LogFactory + .getLog(SeataFeignBlockingLoadBalancerClient.class); + + private final Client delegate; + + private final BlockingLoadBalancerClient loadBalancerClient; + + SeataFeignBlockingLoadBalancerClient(Client delegate, + BlockingLoadBalancerClient loadBalancerClient) { + this.delegate = delegate; + this.loadBalancerClient = loadBalancerClient; + } + + @Override + public Response execute(Request request, Request.Options options) throws IOException { + final URI originalUri = URI.create(request.url()); + String serviceId = originalUri.getHost(); + Assert.state(serviceId != null, + "Request URI does not contain a valid hostname: " + originalUri); + ServiceInstance instance = loadBalancerClient.choose(serviceId); + if (instance == null) { + String message = "Load balancer does not contain an instance for the service " + + serviceId; + if (LOG.isWarnEnabled()) { + LOG.warn(message); + } + return Response.builder().request(request) + .status(HttpStatus.SERVICE_UNAVAILABLE.value()) + .body(message, StandardCharsets.UTF_8).build(); + } + String reconstructedUrl = loadBalancerClient.reconstructURI(instance, originalUri) + .toString(); + Request newRequest = Request.create(request.httpMethod(), reconstructedUrl, + enrichRequstHeader(request.headers()), request.requestBody()); + + return delegate.execute(newRequest, options); + } + + private Map> enrichRequstHeader( + Map> headers) { + String xid = RootContext.getXID(); + if (!StringUtils.isEmpty(xid)) { + Map> newHeaders = new HashMap<>(); + newHeaders.putAll(headers); + newHeaders.put(RootContext.KEY_XID, Arrays.asList(xid)); + return newHeaders; + } + return headers; + } + +} diff --git a/spring-cloud-alibaba-seata/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignObjectWrapper.java b/spring-cloud-alibaba-seata/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignObjectWrapper.java index 95c2a3f8e..58b9ef2c7 100644 --- a/spring-cloud-alibaba-seata/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignObjectWrapper.java +++ b/spring-cloud-alibaba-seata/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignObjectWrapper.java @@ -16,9 +16,14 @@ package com.alibaba.cloud.seata.feign; +import java.lang.reflect.Field; + import feign.Client; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient; import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory; import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient; @@ -28,12 +33,16 @@ import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient; */ public class SeataFeignObjectWrapper { + private static final Log LOG = LogFactory.getLog(SeataFeignObjectWrapper.class); + private final BeanFactory beanFactory; private CachingSpringLoadBalancerFactory cachingSpringLoadBalancerFactory; private SpringClientFactory springClientFactory; + private BlockingLoadBalancerClient loadBalancerClient; + SeataFeignObjectWrapper(BeanFactory beanFactory) { this.beanFactory = beanFactory; } @@ -45,11 +54,41 @@ public class SeataFeignObjectWrapper { return new SeataLoadBalancerFeignClient(client.getDelegate(), factory(), clientFactory(), this.beanFactory); } + if (bean.getClass().getName().equals( + "org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient")) { + return new SeataFeignBlockingLoadBalancerClient(getClient(bean), + loadBalancerClient()); + } return new SeataFeignClient(this.beanFactory, (Client) bean); } return bean; } + private Client getClient(Object bean) { + Field client = null; + boolean oldAccessible = false; + try { + client = bean.getClass().getDeclaredField("delegate"); + oldAccessible = client.isAccessible(); + client.setAccessible(true); + return (Client) client.get(bean); + } + catch (Exception e) { + LOG.error("get delegate client error", e); + } + finally { + client.setAccessible(oldAccessible); + } + return null; + } + + private BlockingLoadBalancerClient loadBalancerClient() { + if (this.loadBalancerClient != null) { + return this.loadBalancerClient; + } + return beanFactory.getBean(BlockingLoadBalancerClient.class); + } + CachingSpringLoadBalancerFactory factory() { if (this.cachingSpringLoadBalancerFactory == null) { this.cachingSpringLoadBalancerFactory = this.beanFactory diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/com/alibaba/cloud/sentinel/datasource/config/NacosDataSourceProperties.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/com/alibaba/cloud/sentinel/datasource/config/NacosDataSourceProperties.java index cbb63e8ea..3fc74945c 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/com/alibaba/cloud/sentinel/datasource/config/NacosDataSourceProperties.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/com/alibaba/cloud/sentinel/datasource/config/NacosDataSourceProperties.java @@ -54,11 +54,7 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { public void preCheck(String dataSourceName) { 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"); - } + "spring.cloud.sentinel.datasource.nacos.server-addr", "localhost:8848"); } } diff --git a/spring-cloud-alibaba-sentinel-gateway/src/main/java/com/alibaba/cloud/sentinel/gateway/scg/SentinelSCGAutoConfiguration.java b/spring-cloud-alibaba-sentinel-gateway/src/main/java/com/alibaba/cloud/sentinel/gateway/scg/SentinelSCGAutoConfiguration.java index cd397158a..386b7d1b3 100644 --- a/spring-cloud-alibaba-sentinel-gateway/src/main/java/com/alibaba/cloud/sentinel/gateway/scg/SentinelSCGAutoConfiguration.java +++ b/spring-cloud-alibaba-sentinel-gateway/src/main/java/com/alibaba/cloud/sentinel/gateway/scg/SentinelSCGAutoConfiguration.java @@ -120,7 +120,7 @@ public class SentinelSCGAutoConfiguration { "[Sentinel SpringCloudGateway] using AnonymousBlockRequestHandler, responseStatus: " + fallbackProperties.getResponseStatus() + ", responseBody: " - + fallbackProperties.getResponseStatus()); + + fallbackProperties.getResponseBody()); } } String redirectUrl = fallbackProperties.getRedirect(); diff --git a/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/ReactiveSentinelCircuitBreakerAutoConfiguration.java b/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/ReactiveSentinelCircuitBreakerAutoConfiguration.java index 14a7bc181..974ad2cf1 100644 --- a/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/ReactiveSentinelCircuitBreakerAutoConfiguration.java +++ b/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/ReactiveSentinelCircuitBreakerAutoConfiguration.java @@ -24,6 +24,7 @@ import javax.annotation.PostConstruct; 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.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory; import org.springframework.context.annotation.Bean; @@ -35,6 +36,8 @@ import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnClass( name = { "reactor.core.publisher.Mono", "reactor.core.publisher.Flux" }) +@ConditionalOnProperty(name = "spring.cloud.circuitbreaker.sentinel.enabled", + havingValue = "true", matchIfMissing = true) public class ReactiveSentinelCircuitBreakerAutoConfiguration { @Bean diff --git a/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/SentinelCircuitBreakerAutoConfiguration.java b/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/SentinelCircuitBreakerAutoConfiguration.java index 2d22ba077..d4b373253 100644 --- a/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/SentinelCircuitBreakerAutoConfiguration.java +++ b/spring-cloud-circuitbreaker-sentinel/src/main/java/com/alibaba/cloud/circuitbreaker/sentinel/SentinelCircuitBreakerAutoConfiguration.java @@ -26,6 +26,7 @@ import com.alibaba.csp.sentinel.SphU; 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.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.context.annotation.Bean; @@ -38,6 +39,8 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @ConditionalOnClass({ SphU.class }) +@ConditionalOnProperty(name = "spring.cloud.circuitbreaker.sentinel.enabled", + havingValue = "true", matchIfMissing = true) public class SentinelCircuitBreakerAutoConfiguration { @Bean diff --git a/spring-cloud-circuitbreaker-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-circuitbreaker-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..44597a6d6 --- /dev/null +++ b/spring-cloud-circuitbreaker-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,7 @@ +{"properties": [ + { + "name": "spring.cloud.circuitbreaker.sentinel.enabled", + "type": "java.lang.Boolean", + "description": "enable sentinel circuitbreaker or not." + } +]}