openfeign集成sentinel实现服务降级
- 使用openfeign调用服务(不含sentinel)
- 代码
- 测试
- openfeign集成sentinel实现服务降级
- 引入sentinel相关环境
- 编写@FeignClient注解接口的实现类
- 在服务提供者中,认为添加异常代码,以供测试 / 或者不启动服务提供者,服务消费者找不到服务提供者,也会报错,同样能够达到测试效果!
- 测试,启动服务提供者及服务消费者
- 未完待续:使用工厂模式来实现Fallback
使用openfeign调用服务(不含sentinel)
代码
application.properties
server.port=8083
spring.application.name=nacos-consumer02
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
#feign.sentinel.enabled=true
#开启热部署
#spring.devtools.restart.enabled=true
主启动类
package com.xl.projects;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class NacosConsumer02Application {
public static void main(String[] args) {
SpringApplication.run(NacosConsumer02Application.class, args);
}
}
Controller
package com.xl.projects.controller;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xl.projects.feign.Consumer02Feign;
@RestController
public class Consumer02Controller {
@Resource
private Consumer02Feign consumer02Feign;
@GetMapping("/another/consumer")
public String testInvoke() {
return consumer02Feign.invokeProvider("oooh!~~~,this is another consumer,named consumer02");
}
}
@FeignClient注解的接口
package com.xl.projects.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "nacos-provider",fallback = FeignFallbackImpl.class)
public interface Consumer02Feign {
/**
* 注意!!!,这里需要显示的指定@RquestParam,否者调用的时候会报错!
*
* @param param
* @return
*/
@GetMapping("/provider/test")
String invokeProvider(@RequestParam String param);
}
以上代码为服务调用者(消费者)代码,以下为服务提供者的Controller代码,其他部分略:
package com.xl.projects.controller;
import java.util.Date;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* For Test!!!
* @author xl
*
*/
@RestController
public class TestProviderController {
@Value("${spring.application.name}")
private String appName;
/**
* For Test!
* @param param
* @return
*/
@GetMapping("/provider/test")
public String test(String param) {
// throw new RuntimeException("服务端测试异常!");
return new Date().getSeconds()+
", this is provider return msg: current param="+param;
}
@GetMapping("/test")
public String testParam() {
return appName;
}
}
pom.xml 中需添加spring cloud open feign的依赖:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xl.projects</groupId>
<artifactId>xl-springcloud-parent-pom</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>xl-nacos-cunsumer02</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- <dependency> -->
<!-- <groupId>com.alibaba.cloud</groupId> -->
<!-- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>org.springframework.boot</groupId> -->
<!-- <artifactId>spring-boot-devtools</artifactId> -->
<!-- <scope>test</scope> -->
<!-- </dependency> -->
</dependencies>
</project>
测试
启动Nacos, 启动服务提供者项目以及服务消费者项目。浏览器访问:
http://localhost:8083/another/consumer :
上图说明使用openfeign调用成功。
在上面@FeignClient注解的接口代码中,@FeignClient注解有个属性fallback!这个fallback是干什么用的呢?见官网:
https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign-circuitbreaker
Spring Cloud CircuitBreaker supports the notion of a fallback: a default code path that is executed when the circuit is open
or there is an error.
大意翻译 : 当遇到一个错误或者熔断器处于开放状态,那么程序就会执行fallback属性配置的类!
To enable fallbacks for a given @FeignClient set the fallback attribute to the class name that implements the fallback.
You also need to declare your implementation as a Spring bean.
大意翻译 : fallback配置的类需要实现@FeignClient配置的接口,并且还的是一个Spring bean (类上需要加上@Component注解!)
根据以上翻译内容,“当程序遇到错误时,就会执行fallback配置的类” ,说明fallback可以充当服务降级的作用,那如何通过fallback来实现服务降级呢?
openfeign集成sentinel实现服务降级
可通过openfeign的注解@FeignClient的属性fallback结合sentinel实现服务降级!
引入sentinel相关环境
引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
application.properties中引入配置(启用):feign.sentinel.enabled=true
server.port=8083
spring.application.name=nacos-consumer02
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
feign.sentinel.enabled=true
#开启热部署
#spring.devtools.restart.enabled=true
编写@FeignClient注解接口的实现类
package com.xl.projects.feign;
import org.springframework.stereotype.Component;
@Component
public class FeignFallbackImpl implements Consumer02Feign {
@Override
public String invokeProvider(String param) {
return ">>>>>>>>>>>>fallback results>>>>>>>>>>>>";
}
}
在服务提供者中,认为添加异常代码,以供测试 / 或者不启动服务提供者,服务消费者找不到服务提供者,也会报错,同样能够达到测试效果!
测试,启动服务提供者及服务消费者
启动服务消费者时,控制台报错,启动失败!
Caused by: java.lang.IllegalAccessError: class org.springframework.cloud.openfeign.HystrixTargeter$$EnhancerBySpringCGLIB$$29430b6f cannot access its superclass org.springframework.cloud.openfeign.HystrixTargeter
at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_201]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:535) ~[spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE]
... 78 common frames omitted
解决:
删除/取消项目热部署,但,有个问题是热部署依赖是在父项目的pom中的,直接屏蔽掉,其他子项目都无法使用热部署的功能了。所以,需要将热部署的依赖拷贝到本服务消费的pom中,同时将<scope>改为test。因为这样会覆盖父pom中的依赖,同时scope为test也不会影响正常的编译阶段和运行阶段。
修改后 :
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xl.projects</groupId>
<artifactId>xl-springcloud-parent-pom</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>xl-nacos-cunsumer02</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
再次启动,成功!访问地址 :
http://localhost:8083/another/consumer
验证成功!
未完待续:使用工厂模式来实现Fallback
FallbackFactory工厂