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

Merge pull request #1978 from theonefx/2020.0.0

Adapt to the spring cloud 2020.1
This commit is contained in:
TheoneFx 2021-03-20 10:54:40 +08:00 committed by GitHub
commit 65417d4f9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 201 additions and 2088 deletions

View File

@ -15,7 +15,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
## 主要功能
* **服务限流降级**:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
* **服务限流降级**:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
* **服务注册与发现**:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
* **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。
* **消息驱动能力**:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。

123
pom.xml
View File

@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>2.3.1.RELEASE</version>
<version>3.0.1</version>
<relativePath/>
</parent>
@ -80,18 +80,10 @@
<properties>
<!-- Project revision -->
<revision>2.2.5.RC2</revision>
<revision>2021.1-SNAPSHOT</revision>
<!-- Dependency Versions -->
<spring-cloud-commons.version>2.2.5.RELEASE</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.2.5.RELEASE</spring-cloud-netflix.version>
<spring-cloud-openfeign.version>2.2.5.RELEASE</spring-cloud-openfeign.version>
<spring-cloud-bus.version>2.2.3.RELEASE</spring-cloud-bus.version>
<spring-cloud-gateway.version>2.2.5.RELEASE</spring-cloud-gateway.version>
<spring-cloud-stream.version>Horsham.SR3</spring-cloud-stream.version>
<spring-cloud-consul.version>2.2.4.RELEASE</spring-cloud-consul.version>
<spring-cloud-config.version>2.2.5.RELEASE</spring-cloud-config.version>
<spring-cloud-zookeeper.version>2.2.3.RELEASE</spring-cloud-zookeeper.version>
<!-- Spring Cloud -->
<spring.cloud.version>2020.0.1</spring.cloud.version>
<!-- Apache Dubbo -->
<dubbo.version>2.7.8</dubbo.version>
@ -132,6 +124,14 @@
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
@ -140,85 +140,6 @@
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons-dependencies</artifactId>
<version>${spring-cloud-commons.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
<version>${spring-cloud-commons.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-dependencies</artifactId>
<version>${spring-cloud-netflix.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>${spring-cloud-openfeign.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-dependencies</artifactId>
<version>${spring-cloud-config.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus-dependencies</artifactId>
<version>${spring-cloud-bus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-dependencies</artifactId>
<version>${spring-cloud-gateway.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-dependencies</artifactId>
<version>${spring-cloud-stream.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul-dependencies</artifactId>
<version>${spring-cloud-consul.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-zookeeper-dependencies</artifactId>
<version>${spring-cloud-zookeeper.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Dubbo Dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
@ -274,6 +195,21 @@
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</plugin>
<!-- disable auto format from parent -->
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
<version>${spring-javaformat.version}</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
@ -298,10 +234,6 @@
</additionalConfig>
</configuration>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
@ -332,7 +264,6 @@
<configuration>
<source>1.8</source>
<target>1.8</target>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>

View File

@ -18,7 +18,7 @@
<description>Spring Cloud Alibaba Dependencies</description>
<properties>
<revision>2.2.5.RC2</revision>
<revision>2021.1-SNAPSHOT</revision>
<sentinel.version>1.8.0</sentinel.version>
<seata.version>1.3.0</seata.version>
<nacos.client.version>1.4.1</nacos.client.version>
@ -102,11 +102,6 @@
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-zuul-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>

View File

@ -254,29 +254,6 @@ NOTE: 默认情况下xml 格式是不支持的。需要添加 `jackson-datafo
关于 Sentinel 动态数据源的实现原理,参考: https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95[动态规则扩展]
=== Zuul 支持
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81[参考 Sentinel 网关限流]
若想跟 Sentinel Starter 配合使用,需要加上 `spring-cloud-alibaba-sentinel-gateway` 依赖,同时需要添加 `spring-cloud-starter-netflix-zuul` 依赖来让 `spring-cloud-alibaba-sentinel-gateway` 模块里的 Zuul 自动化配置类生效:
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
```
=== Spring Cloud Gateway 支持
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81[参考 Sentinel 网关限流]
@ -438,9 +415,6 @@ Spring Cloud Alibaba Sentinel 提供了这些配置选项
|`spring.cloud.sentinel.servlet.block-page`| 自定义的跳转 URL当请求被限流时会自动跳转至设定好的 URL |
|`spring.cloud.sentinel.flow.cold-factor`| https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---
%E5%86%B7%E5%90%AF%E5%8A%A8[冷启动因子] |3
|`spring.cloud.sentinel.zuul.order.pre`| SentinelZuulPreFilter 的 order | 10000
|`spring.cloud.sentinel.zuul.order.post`| SentinelZuulPostFilter 的 order | 1000
|`spring.cloud.sentinel.zuul.order.error`| SentinelZuulErrorFilter 的 order | -1
|`spring.cloud.sentinel.scg.fallback.mode`| Spring Cloud Gateway 熔断后的响应模式(选择 `redirect` or `response`) |
|`spring.cloud.sentinel.scg.fallback.redirect`| Spring Cloud Gateway 响应模式为 'redirect' 模式对应的重定向 URL |
|`spring.cloud.sentinel.scg.fallback.response-body`| Spring Cloud Gateway 响应模式为 'response' 模式对应的响应内容 |

View File

@ -255,29 +255,6 @@ NOTE: XML format is not supported by default. To make it effective, you need to
To learn more about how dynamic data sources work in Sentinel, refer to https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95[Dynamic Rule Extension].
=== Support Zuul
Refer https://github.com/alibaba/Sentinel/wiki/API-Gateway-Flow-Control[API Gateway Flow Control]
If you want to use Sentinel Starter with Zuul, you need to add the `spring-cloud-alibaba-sentinel-gateway` dependency, and you need to add the `spring-cloud-starter-netflix-zuul` dependency to let Zuul AutoConfiguration class in the gateway module takes effect:
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
```
=== Support Spring Cloud Gateway
Refer https://github.com/alibaba/Sentinel/wiki/API-Gateway-Flow-Control[API Gateway Flow Control]
@ -438,9 +415,6 @@ The following table shows all the configurations of Spring Cloud Alibaba Sentine
|`spring.cloud.sentinel.log.switch-pid`|If PID is required for Sentinel log file names|false
|`spring.cloud.sentinel.servlet.blockPage`| Customized redirection URL. When rate limited, the request will be redirected to the pre-defined URL |
|`spring.cloud.sentinel.flow.coldFactor`| https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8[ColdFactor] |3
|`spring.cloud.sentinel.zuul.order.pre`| The order of SentinelZuulPreFilter | 10000
|`spring.cloud.sentinel.zuul.order.post`| The order of SentinelZuulPostFilter | 1000
|`spring.cloud.sentinel.zuul.order.error`| The order of SentinelZuulErrorFilter | -1
|`spring.cloud.sentinel.scg.fallback.mode`| Response mode after Spring Cloud Gateway circuit break (select `redirect` or `response`) |
|`spring.cloud.sentinel.scg.fallback.redirect`| Spring Cloud Gateway response mode is the redirect URL corresponding to 'redirect' mode |
|`spring.cloud.sentinel.scg.fallback.response-body`| Spring Cloud Gateway response mode is response content corresponding to 'response' mode |

View File

@ -31,11 +31,6 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
@ -46,6 +41,10 @@
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -47,6 +47,11 @@
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>

View File

@ -32,11 +32,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.reactive.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.reactive.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.reactive.Request;
import org.springframework.cloud.client.loadbalancer.reactive.Response;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
@ -78,8 +77,7 @@ public class ConsumerSCLBApplication {
}
@Configuration
@LoadBalancerClient(value = "service-provider",
configuration = MyLoadBalancerConfiguration.class)
@LoadBalancerClient(value = "service-provider", configuration = MyLoadBalancerConfiguration.class)
class MySCLBConfiguration {
}
@ -104,8 +102,16 @@ public class ConsumerSCLBApplication {
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
log.info("random spring cloud loadbalacer active -.-");
public Mono<Response<ServiceInstance>> choose(
org.springframework.cloud.client.loadbalancer.Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
@Override
public Mono<Response<ServiceInstance>> choose() {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
@ -120,11 +126,9 @@ public class ConsumerSCLBApplication {
return new DefaultResponse(instance);
}
}
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class,
configuration = FeignConfiguration.class)
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
@GetMapping("/echo/{str}")

View File

@ -36,11 +36,6 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -32,6 +32,10 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -25,7 +25,6 @@
<module>sentinel-example/sentinel-feign-example/sentinel-feign-provider-example</module>
<module>sentinel-example/sentinel-webflux-example</module>
<module>sentinel-example/sentinel-spring-cloud-gateway-example</module>
<module>sentinel-example/sentinel-zuul-example</module>
<module>nacos-example/nacos-discovery-example</module>
<module>nacos-example/nacos-config-example</module>
<module>nacos-example/nacos-gateway-example</module>

View File

@ -26,10 +26,6 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>

View File

@ -42,6 +42,11 @@
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -1,44 +0,0 @@
/*
* 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.examples.fallback;
import com.alibaba.cloud.examples.service.EchoService;
/**
* @author lengleng
* <p>
* sentinel 降级处理
*/
public class EchoServiceFallback implements EchoService {
private Throwable throwable;
EchoServiceFallback(Throwable throwable) {
this.throwable = throwable;
}
/**
* 调用服务提供方的输出接口.
* @param str 用户输入
* @return String
*/
@Override
public String echo(String str) {
return "consumer-fallback-default-str" + throwable.getMessage();
}
}

View File

@ -1,34 +0,0 @@
/*
* 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.examples.fallback;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* @author lengleng
*/
@Component
public class EchoServiceFallbackFactory implements FallbackFactory<EchoServiceFallback> {
@Override
public EchoServiceFallback create(Throwable throwable) {
return new EchoServiceFallback(throwable);
}
}

View File

@ -16,8 +16,6 @@
package com.alibaba.cloud.examples.service;
import com.alibaba.cloud.examples.fallback.EchoServiceFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -27,8 +25,7 @@ import org.springframework.web.bind.annotation.PathVariable;
* <p>
* example feign client
*/
@FeignClient(name = "service-provider",
fallbackFactory = EchoServiceFallbackFactory.class)
@FeignClient(name = "service-provider")
public interface EchoService {
/**

View File

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-zuul-example</artifactId>
<name>Spring Cloud Starter Alibaba Sentinel x Zuul Example</name>
<description>Example demonstrating how to use sentinel with zuul</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>com.alibaba.csp</groupId>-->
<!--<artifactId>sentinel-datasource-nacos</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>com.alibaba.csp</groupId>-->
<!--<artifactId>sentinel-datasource-zookeeper</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>com.alibaba.csp</groupId>-->
<!--<artifactId>sentinel-datasource-apollo</artifactId>-->
<!--</dependency>-->
<!-- define in spring-boot-autoconfigure module -->
<!--<dependency>-->
<!--<groupId>com.fasterxml.jackson.dataformat</groupId>-->
<!--<artifactId>jackson-dataformat-xml</artifactId>-->
<!--</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,53 +0,0 @@
/*
* 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.examples;
import java.util.List;
import java.util.Set;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@RestController
public class RulesController {
@GetMapping("/api")
public Set<ApiDefinition> apiRules() {
return GatewayApiDefinitionManager.getApiDefinitions();
}
@GetMapping("/gateway")
public Set<GatewayFlowRule> apiGateway() {
return GatewayRuleManager.getRules();
}
@GetMapping("/flow")
public List<FlowRule> apiFlow() {
return FlowRuleManager.getRules();
}
}

View File

@ -1,34 +0,0 @@
/*
* 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.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@SpringBootApplication
@EnableZuulProxy
public class SentinelZuulApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelZuulApplication.class, args);
}
}

View File

@ -1,68 +0,0 @@
/*
* 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.examples;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@Configuration
public class ZuulConfiguration {
@Bean
public ZuulBlockFallbackProvider zuulBlockFallbackProvider1() {
return new ZuulBlockFallbackProvider() {
@Override
public String getRoute() {
return "*";
}
@Override
public BlockResponse fallbackResponse(String route, Throwable cause) {
if ("my-service3".equals(route)) {
return new BlockResponse(433, "Sentinel Block3", route);
}
else if ("my-service4".equals(route)) {
return new BlockResponse(444, "my-service4", route);
}
else {
return new BlockResponse(499, "Sentinel Block 499", route);
}
}
};
}
@Bean
public RequestOriginParser requestOriginParser() {
return new RequestOriginParser() {
@Override
public String parseOrigin(HttpServletRequest request) {
return "123";
}
};
}
}

View File

@ -1,32 +0,0 @@
[
{
"apiName": "some_customized_api",
"predicateItems": [
{
"pattern": "/product/baz"
},
{
"pattern": "/product/foo/**",
"matchStrategy": 1
},
{
"items": [
{
"pattern": "/spring-cloud/**"
},
{
"pattern": "/spring-cloud-alibaba/**"
}
]
}
]
},
{
"apiName": "another_customized_api",
"predicateItems": [
{
"pattern": "/ahas"
}
]
}
]

View File

@ -1,40 +0,0 @@
server:
port: 18086
spring:
application:
name: sentinel-zuul
cloud:
sentinel:
datasource.ds2.file:
file: "classpath: gateway.json"
ruleType: gw-flow
datasource.ds1.file:
file: "classpath: api.json"
ruleType: gw-api-group
transport:
dashboard: localhost:8080
filter:
enabled: false
management.endpoints.web.exposure.include: "*"
zuul.routes.my-service.path: "/product/foo/**"
zuul.routes.my-service.service-id: "my-service"
zuul.routes.my-service2.path: "/my-service2/**"
zuul.routes.my-service2.service-id: "my-service2"
zuul.routes.my-service3.path: "/my-service3/**"
zuul.routes.my-service3.service-id: "my-service3"
zuul.routes.my-service4.path: "/my-service4/**"
zuul.routes.my-service4.service-id: "my-service4"
spring.cloud.sentinel.zuul.order.pre: 2000
spring.cloud.sentinel.zuul.order.post: 500
spring.cloud.sentinel.zuul.order.error: -100
spring.cloud.sentinel.zuul.enabled: true

View File

@ -1,26 +0,0 @@
[
{
"resource": "some_customized_api",
"count": 0
},
{
"resource": "my-service2",
"count": 0
},
{
"resource": "my-service3",
"count": 0,
"paramItem": {
"parseStrategy": 2,
"fieldName": "Spring-Cloud-Alibaba"
}
},
{
"resource": "my-service4",
"count": 0,
"paramItem": {
"parseStrategy": 3,
"fieldName": "name"
}
}
]

View File

@ -99,7 +99,11 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>

View File

@ -90,7 +90,6 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
</dependency>
<!-- REST support dependencies -->
@ -134,6 +133,11 @@
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -89,7 +89,6 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
</dependency>
</dependencies>

View File

@ -137,6 +137,12 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -23,12 +23,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
@ -39,11 +33,6 @@
<artifactId>sentinel-parameter-flow-control</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-zuul-adapter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>

View File

@ -17,28 +17,17 @@
package com.alibaba.cloud.sentinel.gateway;
import com.alibaba.cloud.sentinel.gateway.scg.SentinelGatewayProperties;
import com.alibaba.cloud.sentinel.gateway.zuul.SentinelZuulProperties;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public final class ConfigConstants {
/**
* Netflix Zuul type.
*/
public static final String APP_TYPE_ZUUL_GATEWAY = "12";
/**
* Spring Cloud Gateway type.
*/
public static final String APP_TYPE_SCG_GATEWAY = "11";
/**
* ConfigurationProperties for {@link SentinelZuulProperties}.
*/
public static final String ZUUL_PREFIX = "spring.cloud.sentinel.zuul";
/**
* ConfigurationProperties for {@link SentinelGatewayProperties}.
*/

View File

@ -1,62 +0,0 @@
/*
* 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.sentinel.gateway.zuul;
import java.util.Map;
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;
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;
/**
* @author tiger
*/
public class FallBackProviderHandler implements SmartInitializingSingleton {
private static final Logger logger = LoggerFactory
.getLogger(FallBackProviderHandler.class);
private final DefaultListableBeanFactory beanFactory;
public FallBackProviderHandler(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterSingletonsInstantiated() {
Map<String, ZuulBlockFallbackProvider> providerMap = beanFactory
.getBeansOfType(ZuulBlockFallbackProvider.class);
if (!CollectionUtils.isEmpty(providerMap)) {
providerMap.forEach((k, v) -> {
logger.info("[Sentinel Zuul] Register provider name:{}, instance: {}", k,
v);
ZuulBlockFallbackManager.registerProvider(v);
});
}
else {
logger.info("[Sentinel Zuul] Register default fallback provider. ");
ZuulBlockFallbackManager.registerProvider(new DefaultBlockFallbackProvider());
}
}
}

View File

@ -1,102 +0,0 @@
/*
* 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.sentinel.gateway.zuul;
import java.util.Optional;
import javax.annotation.PostConstruct;
import com.alibaba.cloud.sentinel.gateway.ConfigConstants;
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.http.ZuulServlet;
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.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Sentinel Spring Cloud Zuul AutoConfiguration.
*
* @author tiger
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZuulServlet.class)
@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);
@Autowired
private Optional<RequestOriginParser> requestOriginParserOptional;
@Autowired
private SentinelZuulProperties zuulProperties;
@PostConstruct
private void init() {
requestOriginParserOptional
.ifPresent(ZuulGatewayCallbackManager::setOriginParser);
System.setProperty(SentinelConfig.APP_TYPE_PROP_KEY,
String.valueOf(ConfigConstants.APP_TYPE_ZUUL_GATEWAY));
}
@Bean
@ConditionalOnMissingBean
public SentinelZuulPreFilter sentinelZuulPreFilter() {
logger.info("[Sentinel Zuul] register SentinelZuulPreFilter {}",
zuulProperties.getOrder().getPre());
return new SentinelZuulPreFilter(zuulProperties.getOrder().getPre());
}
@Bean
@ConditionalOnMissingBean
public SentinelZuulPostFilter sentinelZuulPostFilter() {
logger.info("[Sentinel Zuul] register SentinelZuulPostFilter {}",
zuulProperties.getOrder().getPost());
return new SentinelZuulPostFilter(zuulProperties.getOrder().getPost());
}
@Bean
@ConditionalOnMissingBean
public SentinelZuulErrorFilter sentinelZuulErrorFilter() {
logger.info("[Sentinel Zuul] register SentinelZuulErrorFilter {}",
zuulProperties.getOrder().getError());
return new SentinelZuulErrorFilter(zuulProperties.getOrder().getError());
}
@Bean
public FallBackProviderHandler fallBackProviderHandler(
DefaultListableBeanFactory beanFactory) {
return new FallBackProviderHandler(beanFactory);
}
}

View File

@ -1,89 +0,0 @@
/*
* 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.sentinel.gateway.zuul;
import com.alibaba.cloud.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;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@ConfigurationProperties(prefix = ConfigConstants.ZUUL_PREFIX)
public class SentinelZuulProperties {
@NestedConfigurationProperty
private SentinelZuulProperties.Order order = new SentinelZuulProperties.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;
}
}
}

View File

@ -1,5 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.sentinel.gateway.zuul.SentinelZuulAutoConfiguration,\
com.alibaba.cloud.sentinel.gateway.scg.SentinelSCGAutoConfiguration,\
com.alibaba.cloud.sentinel.gateway.SentinelGatewayAutoConfiguration
org.springframework.boot.env.EnvironmentPostProcessor=com.alibaba.cloud.sentinel.gateway.GatewayEnvironmentPostProcessor

View File

@ -62,6 +62,12 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -51,12 +51,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>

View File

@ -33,6 +33,12 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
@ -85,12 +91,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock.modules.test.powermockito/powermock-modules-test-powermockito -->
<dependency>
<groupId>org.powermock</groupId>

View File

@ -81,11 +81,6 @@
<artifactId>spring-cloud-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
@ -111,12 +106,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>

View File

@ -1,31 +0,0 @@
/*
* 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.nacos.ribbon;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@ConditionalOnProperty(value = "ribbon.nacos.enabled", matchIfMissing = true)
public @interface ConditionalOnRibbonNacos {
}

View File

@ -1,38 +0,0 @@
/*
* 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.nacos.ribbon;
import java.util.List;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;
/**
* @author itmuch.com
*/
public class ExtendBalancer extends Balancer {
/**
* Choose instance by weight.
* @param instances Instance List
* @return the chosen instance
*/
public static Instance getHostByRandomWeight2(List<Instance> instances) {
return getHostByRandomWeight(instances);
}
}

View File

@ -1,62 +0,0 @@
/*
* 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.nacos.ribbon;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.netflix.ribbon.PropertiesFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* integrated Ribbon by default.
*
* @author xiaojing
* @author liujunjie
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnRibbonNacos
public class NacosRibbonClientConfiguration {
@Autowired
private PropertiesFactory propertiesFactory;
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config,
NacosDiscoveryProperties nacosDiscoveryProperties) {
if (this.propertiesFactory.isSet(ServerList.class, config.getClientName())) {
ServerList serverList = this.propertiesFactory.get(ServerList.class, config,
config.getClientName());
return serverList;
}
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public NacosServerIntrospector nacosServerIntrospector() {
return new NacosServerIntrospector();
}
}

View File

@ -1,100 +0,0 @@
/*
* 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.nacos.ribbon;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
/**
* Supports preferentially calling the ribbon load balancing rules of the same cluster
* instance.
*
* @author itmuch.com
*/
public class NacosRule extends AbstractLoadBalancerRule {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosRule.class);
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Autowired
private NacosServiceManager nacosServiceManager;
@Override
public Server choose(Object key) {
try {
String clusterName = this.nacosDiscoveryProperties.getClusterName();
String group = this.nacosDiscoveryProperties.getGroup();
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
String name = loadBalancer.getName();
NamingService namingService = nacosServiceManager
.getNamingService(nacosDiscoveryProperties.getNacosProperties());
List<Instance> instances = namingService.selectInstances(name, group, true);
if (CollectionUtils.isEmpty(instances)) {
LOGGER.warn("no instance in service {}", name);
return null;
}
List<Instance> instancesToChoose = instances;
if (StringUtils.isNotBlank(clusterName)) {
List<Instance> sameClusterInstances = instances.stream()
.filter(instance -> Objects.equals(clusterName,
instance.getClusterName()))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(sameClusterInstances)) {
instancesToChoose = sameClusterInstances;
}
else {
LOGGER.warn(
"A cross-cluster call occursname = {}, clusterName = {}, instance = {}",
name, clusterName, instances);
}
}
Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);
return new NacosServer(instance);
}
catch (Exception e) {
LOGGER.warn("NacosRule error", e);
return null;
}
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
}

View File

@ -1,76 +0,0 @@
/*
* 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.nacos.ribbon;
import java.util.Map;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.loadbalancer.Server;
/**
* @author xiaojing
* @author pbting
*/
public class NacosServer extends Server {
private final MetaInfo metaInfo;
private final Instance instance;
private final Map<String, String> metadata;
public NacosServer(final Instance instance) {
super(instance.getIp(), instance.getPort());
this.instance = instance;
this.metaInfo = new MetaInfo() {
@Override
public String getAppName() {
return instance.getServiceName();
}
@Override
public String getServerGroup() {
return null;
}
@Override
public String getServiceIdForDiscovery() {
return null;
}
@Override
public String getInstanceId() {
return instance.getInstanceId();
}
};
this.metadata = instance.getMetadata();
}
@Override
public MetaInfo getMetaInfo() {
return metaInfo;
}
public Instance getInstance() {
return instance;
}
public Map<String, String> getMetadata() {
return metadata;
}
}

View File

@ -1,47 +0,0 @@
/*
* 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.nacos.ribbon;
import java.util.Map;
import com.netflix.loadbalancer.Server;
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
/**
* @author xiaojing
*/
public class NacosServerIntrospector extends DefaultServerIntrospector {
@Override
public Map<String, String> getMetadata(Server server) {
if (server instanceof NacosServer) {
return ((NacosServer) server).getMetadata();
}
return super.getMetadata(server);
}
@Override
public boolean isSecure(Server server) {
if (server instanceof NacosServer) {
return Boolean.valueOf(((NacosServer) server).getMetadata().get("secure"));
}
return super.isSecure(server);
}
}

View File

@ -1,87 +0,0 @@
/*
* 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.nacos.ribbon;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
/**
* @author xiaojing
* @author renhaojun
*/
public class NacosServerList extends AbstractServerList<NacosServer> {
private NacosDiscoveryProperties discoveryProperties;
private String serviceId;
public NacosServerList(NacosDiscoveryProperties discoveryProperties) {
this.discoveryProperties = discoveryProperties;
}
@Override
public List<NacosServer> getInitialListOfServers() {
return getServers();
}
@Override
public List<NacosServer> getUpdatedListOfServers() {
return getServers();
}
private List<NacosServer> getServers() {
try {
String group = discoveryProperties.getGroup();
List<Instance> instances = discoveryProperties.namingServiceInstance()
.selectInstances(serviceId, group, true);
return instancesToServerList(instances);
}
catch (Exception e) {
throw new IllegalStateException(
"Can not get service instances from nacos, serviceId=" + serviceId,
e);
}
}
private List<NacosServer> instancesToServerList(List<Instance> instances) {
List<NacosServer> result = new ArrayList<>();
if (CollectionUtils.isEmpty(instances)) {
return result;
}
for (Instance instance : instances) {
result.add(new NacosServer(instance));
}
return result;
}
public String getServiceId() {
return serviceId;
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
this.serviceId = iClientConfig.getClientName();
}
}

View File

@ -1,42 +0,0 @@
/*
* 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.nacos.ribbon;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Configuration;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} that sets up Ribbon for Nacos.
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnRibbonNacos
@ConditionalOnNacosDiscoveryEnabled
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = NacosRibbonClientConfiguration.class)
public class RibbonNacosAutoConfiguration {
}

View File

@ -1,6 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\
com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\
com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\

View File

@ -1,78 +0,0 @@
/*
* 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.nacos.ribbon;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author xiaojing
*/
public class NacosRibbonClientConfigurationTests {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(NacosRibbonTestConfiguration.class,
NacosRibbonClientConfiguration.class,
NacosDiscoveryClientConfiguration.class,
RibbonNacosAutoConfiguration.class))
.withPropertyValues("spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848")
.withPropertyValues("spring.cloud.nacos.discovery.port=18080")
.withPropertyValues("spring.cloud.nacos.discovery.service=myapp");
@Test
public void testProperties() {
this.contextRunner.run(context -> {
NacosServerList serverList = context.getBean(NacosServerList.class);
assertThat(serverList.getServiceId()).isEqualTo("myapp");
});
}
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
static class NacosRibbonTestConfiguration {
@Bean
IClientConfig iClientConfig() {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.setClientName("myapp");
return config;
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 2013-2017 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.nacos.ribbon;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration;
import com.netflix.loadbalancer.ConfigurationBasedServerList;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author liujunjie
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosRibbonClientPropertyOverrideTests.TestConfiguration.class,
properties = { "spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.discovery.port=18080",
"spring.cloud.nacos.discovery.service=remoteApp",
"localApp.ribbon.NIWSServerListClassName="
+ "com.netflix.loadbalancer.ConfigurationBasedServerList",
"localApp.ribbon.listOfServers=127.0.0.1:19090",
"localApp.ribbon.ServerListRefreshInterval=15000" })
public class NacosRibbonClientPropertyOverrideTests {
@Autowired
private SpringClientFactory factory;
@Test
public void serverListOverridesToTest() {
ConfigurationBasedServerList.class
.cast(getLoadBalancer("localApp").getServerListImpl());
}
@Test
public void serverListRemoteTest() {
NacosServerList.class.cast(getLoadBalancer("remoteApp").getServerListImpl());
}
@SuppressWarnings("unchecked")
private ZoneAwareLoadBalancer<Server> getLoadBalancer(String name) {
return (ZoneAwareLoadBalancer<Server>) this.factory.getLoadBalancer(name);
}
@Configuration
@RibbonClients
@EnableAutoConfiguration
@ImportAutoConfiguration({ UtilAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class,
RibbonNacosAutoConfiguration.class, NacosDiscoveryClientConfiguration.class })
protected static class TestConfiguration {
}
}

View File

@ -1,165 +0,0 @@
/*
* 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.nacos.ribbon;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.test.NacosMockTest;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author xiaojing
*/
public class NacosServerListTests {
@Test
@SuppressWarnings("unchecked")
public void testEmptyInstancesReturnsEmptyList() throws Exception {
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(namingService.selectInstances(anyString(), eq("DEFAULT"), eq(true)))
.thenReturn(null);
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
List<NacosServer> servers = serverList.getInitialListOfServers();
assertThat(servers).isEmpty();
}
@Test
@SuppressWarnings("unchecked")
public void testGetServers() throws Exception {
ArrayList<Instance> instances = new ArrayList<>();
instances.add(NacosMockTest.serviceInstance("test-service", false,
Collections.emptyMap()));
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT");
when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT");
when(namingService.selectInstances(eq("test-service"), eq("DEFAULT"), eq(true)))
.thenReturn(instances);
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(clientConfig);
List<NacosServer> servers = serverList.getInitialListOfServers();
assertThat(servers).hasSize(1);
servers = serverList.getUpdatedListOfServers();
assertThat(servers).hasSize(1);
}
@Test
@SuppressWarnings("unchecked")
public void testGetServersWithInstanceStatus() throws Exception {
ArrayList<Instance> instances = new ArrayList<>();
HashMap<String, String> map1 = new HashMap<>();
map1.put("instanceNum", "1");
HashMap<String, String> map2 = new HashMap<>();
map2.put("instanceNum", "2");
instances.add(NacosMockTest.serviceInstance("test-service", false, map1));
instances.add(NacosMockTest.serviceInstance("test-service", true, map2));
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT");
when(namingService.selectInstances(eq("test-service"), eq("DEFAULT"), eq(true)))
.thenReturn(instances.stream().filter(Instance::isHealthy)
.collect(Collectors.toList()));
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(clientConfig);
List<NacosServer> servers = serverList.getInitialListOfServers();
assertThat(servers).hasSize(1);
NacosServer nacosServer = servers.get(0);
assertThat(nacosServer.getMetaInfo().getInstanceId())
.isEqualTo(instances.get(1).getInstanceId());
assertThat(nacosServer.getMetadata()).isEqualTo(map2);
assertThat(nacosServer.getInstance().isHealthy()).isEqualTo(true);
assertThat(nacosServer.getInstance().getServiceName()).isEqualTo("test-service");
assertThat(nacosServer.getInstance().getMetadata().get("instanceNum"))
.isEqualTo("2");
}
@Test
public void testUpdateServers() throws Exception {
ArrayList<Instance> instances = new ArrayList<>();
HashMap<String, String> map = new HashMap<>();
map.put("instanceNum", "1");
instances.add(NacosMockTest.serviceInstance("test-service", true, map));
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT");
when(namingService.selectInstances(eq("test-service"), eq("DEFAULT"), eq(true)))
.thenReturn(instances.stream().filter(Instance::isHealthy)
.collect(Collectors.toList()));
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(clientConfig);
List<NacosServer> servers = serverList.getUpdatedListOfServers();
assertThat(servers).hasSize(1);
assertThat(servers.get(0).getInstance().isHealthy()).isEqualTo(true);
assertThat(servers.get(0).getInstance().getMetadata().get("instanceNum"))
.isEqualTo("1");
}
}

View File

@ -92,12 +92,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@ -22,7 +22,9 @@ import feign.Client;
import feign.Request;
import feign.Response;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
/**
@ -32,9 +34,11 @@ public class SeataFeignBlockingLoadBalancerClient
extends FeignBlockingLoadBalancerClient {
public SeataFeignBlockingLoadBalancerClient(Client delegate,
BlockingLoadBalancerClient loadBalancerClient,
SeataFeignObjectWrapper seataFeignObjectWrapper) {
super((Client) seataFeignObjectWrapper.wrap(delegate), loadBalancerClient);
BlockingLoadBalancerClient loadBalancerClient,
LoadBalancerProperties properties,
LoadBalancerClientFactory loadBalancerClientFactory,
SeataFeignObjectWrapper seataFeignObjectWrapper) {
super((Client) seataFeignObjectWrapper.wrap(delegate), loadBalancerClient, properties, loadBalancerClientFactory);
}
@Override

View File

@ -38,14 +38,6 @@ import org.springframework.context.annotation.Scope;
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class SeataFeignClientAutoConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnClass(name = "com.netflix.hystrix.HystrixCommand")
@ConditionalOnProperty(name = "feign.hystrix.enabled", havingValue = "true")
Feign.Builder feignHystrixBuilder(BeanFactory beanFactory) {
return SeataHystrixFeignBuilder.builder(beanFactory);
}
@Bean
@Scope("prototype")
@ConditionalOnClass(name = "com.alibaba.csp.sentinel.SphU")

View File

@ -21,11 +21,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/**
* @author xiaojing
@ -37,9 +36,6 @@ public class SeataFeignObjectWrapper {
private final BeanFactory beanFactory;
private CachingSpringLoadBalancerFactory cachingSpringLoadBalancerFactory;
private SpringClientFactory springClientFactory;
SeataFeignObjectWrapper(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
@ -47,35 +43,16 @@ public class SeataFeignObjectWrapper {
Object wrap(Object bean) {
if (bean instanceof Client && !(bean instanceof SeataFeignClient)) {
if (bean instanceof LoadBalancerFeignClient) {
LoadBalancerFeignClient client = ((LoadBalancerFeignClient) bean);
return new SeataLoadBalancerFeignClient(client.getDelegate(), factory(),
clientFactory(), this);
}
if (bean instanceof FeignBlockingLoadBalancerClient) {
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) bean;
return new SeataFeignBlockingLoadBalancerClient(client.getDelegate(),
beanFactory.getBean(BlockingLoadBalancerClient.class), this);
beanFactory.getBean(BlockingLoadBalancerClient.class),
beanFactory.getBean(LoadBalancerProperties.class),
beanFactory.getBean(LoadBalancerClientFactory.class),
this);
}
return new SeataFeignClient(this.beanFactory, (Client) bean);
}
return bean;
}
CachingSpringLoadBalancerFactory factory() {
if (this.cachingSpringLoadBalancerFactory == null) {
this.cachingSpringLoadBalancerFactory = this.beanFactory
.getBean(CachingSpringLoadBalancerFactory.class);
}
return this.cachingSpringLoadBalancerFactory;
}
SpringClientFactory clientFactory() {
if (this.springClientFactory == null) {
this.springClientFactory = this.beanFactory
.getBean(SpringClientFactory.class);
}
return this.springClientFactory;
}
}

View File

@ -1,38 +0,0 @@
/*
* 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 feign.Feign;
import feign.Retryer;
import feign.hystrix.HystrixFeign;
import org.springframework.beans.factory.BeanFactory;
/**
* @author xiaojing
*/
final class SeataHystrixFeignBuilder {
private SeataHystrixFeignBuilder() {
}
static Feign.Builder builder(BeanFactory beanFactory) {
return HystrixFeign.builder().retryer(Retryer.NEVER_RETRY)
.client(new SeataFeignClient(beanFactory));
}
}

View File

@ -1,48 +0,0 @@
/*
* 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 feign.Client;
import feign.Request;
import feign.Response;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/**
* @author xiaojing
* @author yuhuangbin
*/
public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
SeataLoadBalancerFeignClient(Client delegate,
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory,
SeataFeignObjectWrapper seataFeignObjectWrapper) {
super((Client) seataFeignObjectWrapper.wrap(delegate), lbClientFactory,
clientFactory);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
return super.execute(request, options);
}
}

View File

@ -1,37 +0,0 @@
/*
* 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.hystrix;
import com.netflix.hystrix.HystrixCommand;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaojing
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HystrixCommand.class)
public class SeataHystrixAutoConfiguration {
@Bean
SeataHystrixConcurrencyStrategy seataHystrixConcurrencyStrategy() {
return new SeataHystrixConcurrencyStrategy();
}
}

View File

@ -1,175 +0,0 @@
/*
* 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.hystrix;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import io.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
/**
* @author xiaojing
*/
public class SeataHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
private final Logger logger = LoggerFactory
.getLogger(SeataHystrixConcurrencyStrategy.class);
private HystrixConcurrencyStrategy delegate;
public SeataHystrixConcurrencyStrategy() {
try {
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
if (this.delegate instanceof SeataHystrixConcurrencyStrategy) {
return;
}
HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins
.getInstance().getCommandExecutionHook();
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance()
.getEventNotifier();
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance()
.getMetricsPublisher();
HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
.getPropertiesStrategy();
logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher,
propertiesStrategy);
HystrixPlugins.reset();
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
HystrixPlugins.getInstance()
.registerCommandExecutionHook(commandExecutionHook);
HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
}
catch (Exception ex) {
logger.error("Failed to register Seata Hystrix Concurrency Strategy", ex);
}
}
private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
HystrixMetricsPublisher metricsPublisher,
HystrixPropertiesStrategy propertiesStrategy) {
if (logger.isDebugEnabled()) {
logger.debug("Current Hystrix plugins configuration is ["
+ "concurrencyStrategy [" + this.delegate + "]," + "eventNotifier ["
+ eventNotifier + "]," + "metricPublisher [" + metricsPublisher + "],"
+ "propertiesStrategy [" + propertiesStrategy + "]," + "]");
logger.debug("Registering Seata Hystrix Concurrency Strategy.");
}
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixProperty<Integer> corePoolSize,
HystrixProperty<Integer> maximumPoolSize,
HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize,
keepAliveTime, unit, workQueue);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixThreadPoolProperties threadPoolProperties) {
return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
@Override
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}
@Override
public <T> HystrixRequestVariable<T> getRequestVariable(
HystrixRequestVariableLifecycle<T> rv) {
return this.delegate.getRequestVariable(rv);
}
@Override
public <K> Callable<K> wrapCallable(Callable<K> c) {
if (c instanceof SeataContextCallable) {
return c;
}
Callable<K> wrappedCallable;
if (this.delegate != null) {
wrappedCallable = this.delegate.wrapCallable(c);
}
else {
wrappedCallable = c;
}
if (wrappedCallable instanceof SeataContextCallable) {
return wrappedCallable;
}
return new SeataContextCallable<>(wrappedCallable,
RequestContextHolder.getRequestAttributes());
}
private static class SeataContextCallable<K> implements Callable<K> {
private final Callable<K> actual;
private final String xid;
private final RequestAttributes requestAttributes;
SeataContextCallable(Callable<K> actual, RequestAttributes requestAttribute) {
this.actual = actual;
this.requestAttributes = requestAttribute;
this.xid = RootContext.getXID();
}
@Override
public K call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
if (!StringUtils.isEmpty(xid)) {
RootContext.bind(xid);
}
return actual.call();
}
finally {
if (!StringUtils.isEmpty(xid)) {
RootContext.unbind();
}
RequestContextHolder.resetRequestAttributes();
}
}
}
}

View File

@ -1,6 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.seata.rest.SeataRestTemplateAutoConfiguration,\
com.alibaba.cloud.seata.web.SeataHandlerInterceptorConfiguration,\
com.alibaba.cloud.seata.feign.SeataFeignClientAutoConfiguration,\
com.alibaba.cloud.seata.feign.hystrix.SeataHystrixAutoConfiguration
com.alibaba.cloud.seata.feign.SeataFeignClientAutoConfiguration

View File

@ -83,7 +83,7 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<optional>true</optional>
</dependency>
@ -162,6 +162,12 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -25,18 +25,20 @@ import feign.Contract;
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.Target;
import feign.hystrix.FallbackFactory;
import feign.hystrix.HystrixFeign;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.cloud.openfeign.FeignClientFactoryBean;
import org.springframework.cloud.openfeign.FeignContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* {@link Feign.Builder} like {@link HystrixFeign.Builder}.
* {@link Feign.Builder}.
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@ -77,20 +79,22 @@ public final class SentinelFeign {
@Override
public InvocationHandler create(Target target,
Map<Method, MethodHandler> dispatch) {
// using reflect get fallback and fallbackFactory properties from
// FeignClientFactoryBean because FeignClientFactoryBean is a package
// level class, we can not use it in our package
Object feignClientFactoryBean = Builder.this.applicationContext
.getBean("&" + target.type().getName());
Class fallback = (Class) getFieldValue(feignClientFactoryBean,
"fallback");
Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean,
"fallbackFactory");
String beanName = (String) getFieldValue(feignClientFactoryBean,
"contextId");
GenericApplicationContext gctx = (GenericApplicationContext) Builder.this.applicationContext;
BeanDefinition def = gctx.getBeanDefinition(target.type().getName());
/**
* Due to the change of the initialization sequence, BeanFactory.getBean will cause a circular dependency.
* So FeignClientFactoryBean can only be obtained from BeanDefinition
*/
FeignClientFactoryBean feignClientFactoryBean = (FeignClientFactoryBean) def.getAttribute("feignClientsRegistrarFactoryBean");
Class fallback = feignClientFactoryBean.getFallback();
Class fallbackFactory = feignClientFactoryBean.getFallbackFactory();
String beanName = feignClientFactoryBean.getContextId();
if (!StringUtils.hasText(beanName)) {
beanName = (String) getFieldValue(feignClientFactoryBean, "name");
beanName = feignClientFactoryBean.getName();
}
Object fallbackInstance;

View File

@ -33,7 +33,8 @@ import feign.Feign;
import feign.InvocationHandlerFactory.MethodHandler;
import feign.MethodMetadata;
import feign.Target;
import feign.hystrix.FallbackFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import static feign.Util.checkNotNull;
@ -71,7 +72,8 @@ public class SentinelInvocationHandler implements InvocationHandler {
if ("equals".equals(method.getName())) {
try {
Object otherHandler = args.length > 0 && args[0] != null
? Proxy.getInvocationHandler(args[0]) : null;
? Proxy.getInvocationHandler(args[0])
: null;
return equals(otherHandler);
}
catch (IllegalArgumentException e) {

View File

@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -122,7 +123,7 @@ public class ContextIdSentinelFeignTests {
}
public static class CustomFallbackFactory
implements feign.hystrix.FallbackFactory<FooService> {
implements FallbackFactory<FooService> {
private FooService fooService = new FooServiceFallback();

View File

@ -31,6 +31,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -191,7 +192,7 @@ public class SentinelFeignTests {
}
public static class CustomFallbackFactory
implements feign.hystrix.FallbackFactory<FooService> {
implements FallbackFactory<FooService> {
private FooService fooService = new FooServiceFallback();

View File

@ -16,7 +16,10 @@
package com.alibaba.cloud.sidecar.consul;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.cloud.sidecar.SidecarProperties;
import com.ecwid.consul.v1.agent.model.NewService;
@ -29,6 +32,8 @@ import org.springframework.cloud.consul.serviceregistry.ConsulManagementRegistra
import org.springframework.cloud.consul.serviceregistry.ConsulRegistrationCustomizer;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* @author www.itmuch.com
@ -59,16 +64,28 @@ public class SidecarConsulAutoRegistration extends ConsulAutoRegistration {
service.setAddress(sidecarProperties.getIp());
}
service.setName(normalizeForDns(appName));
service.setTags(createTags(properties));
service.setTags(new ArrayList<>(properties.getTags()));
service.setEnableTagOverride(properties.getEnableTagOverride());
service.setMeta(getMetadata(properties));
// set health check, use alibaba sidecar self's port rather than polyglot app's
// port.
service.setPort(
Integer.valueOf(context.getEnvironment().getProperty("server.port")));
setCheck(service, autoServiceRegistrationProperties, properties, context,
heartbeatProperties);
if (sidecarProperties.getPort() != null && sidecarProperties.getPort() > 0) {
service.setPort(properties.getPort());
}
else if (properties.getPort() != null && properties.getPort() > 0) {
service.setPort(properties.getPort());
}
else if (context.getEnvironment().getProperty("server.port") != null) {
// set health check, use alibaba sidecar self's port rather than polyglot
// app's port.
service.setPort(
Integer.valueOf(context.getEnvironment().getProperty("server.port")));
}
service.setPort(sidecarProperties.getPort());
if (service.getPort() != null) {
// we know the port and can set the check
setCheck(service, autoServiceRegistrationProperties, properties, context,
heartbeatProperties);
}
ConsulAutoRegistration registration = new ConsulAutoRegistration(service,
autoServiceRegistrationProperties, properties, context,
@ -77,6 +94,33 @@ public class SidecarConsulAutoRegistration extends ConsulAutoRegistration {
return registration;
}
/**
* copyed from
* org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration#getMetadata.
*/
private static Map<String, String> getMetadata(ConsulDiscoveryProperties properties) {
LinkedHashMap<String, String> metadata = new LinkedHashMap<>();
if (!CollectionUtils.isEmpty(properties.getMetadata())) {
metadata.putAll(properties.getMetadata());
}
// add metadata from other properties. See createTags above.
if (!StringUtils.isEmpty(properties.getInstanceZone())) {
metadata.put(properties.getDefaultZoneMetadataName(),
properties.getInstanceZone());
}
if (!StringUtils.isEmpty(properties.getInstanceGroup())) {
metadata.put("group", properties.getInstanceGroup());
}
// store the secure flag in the tags so that clients will be able to figure
// out whether to use http or https automatically
metadata.put("secure",
Boolean.toString(properties.getScheme().equalsIgnoreCase("https")));
return metadata;
}
public static String getInstanceId(SidecarProperties sidecarProperties,
Environment environment) {
return String.format("%s-%s-%s",

View File

@ -37,7 +37,7 @@ public class SidecarNacosDiscoveryProperties extends NacosDiscoveryProperties {
super.init();
String ip = sidecarProperties.getIp();
if (!StringUtils.isEmpty(ip)) {
if (!StringUtils.hasText(ip)) {
this.setIp(ip);
}

View File

@ -28,7 +28,7 @@ import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import static org.springframework.cloud.bus.SpringCloudBusClient.INPUT;
import static org.springframework.cloud.bus.BusConstants.INPUT;
/**
* The lowest precedence {@link EnvironmentPostProcessor} configures default RocketMQ Bus

View File

@ -78,7 +78,6 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<version>${spring-cloud-zookeeper.version}</version>
<optional>true</optional>
<exclusions>
<exclusion>
@ -112,7 +111,6 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
<optional>true</optional>
</dependency>

View File

@ -58,6 +58,13 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -131,7 +131,7 @@ public class RocketMQMessageHandler extends AbstractMessageHandler implements Li
}
}
catch (MQClientException e) {
logger.error("fetch publish message queues fail", e);
logger.error(e, "fetch publish message queues fail");
}
}
running = true;