一、背景介绍
这两天在折腾升级项目框架,springboot由2.2.2.RELEASE升级到2.7.6,springcloud由Hoxton.SR1升级到2021.0.6
直接替换版本发现代码有报错,有些注解报错了,所以学习了下,在此做个学习笔记。
作为入门篇,先不深究openfeign和hystrix怎么实现的,有啥详细配置;大概知道有什么作用就行。
openfeign:实现RPC调用
hystrix:实现接口熔断,即被调用的接口出现异常,或者调用超时,调用方直接返回备胎方法
二、整合步骤
准备一个Eureka注册中心,一个订单服务order-service(接口提供方),一个商品服务goods-service(接口调用方)。
我们先整合openfeign,测试ok再整合hystrix。
1、订单服务order-service
order-service的pom.xm引入l如下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 整合openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.5</version>
</dependency>
<!-- 整合eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- swagger -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
yml配置文件内容如下
server:
port: 8088
spring:
application:
name: order-service
# swagger用到的配置
mvc:
pathmatch:
matching-strategy: ant_path_matcher
eureka:
client:
# 需要将我的服务注册到eureka上
register-with-eureka: true
# 需要检索服务
fetch-registry: true
service-url:
# 当前服务注册到eureka地址
defaultZone: http://localhost:8761/eureka/
# 从eureka服务器注册表中获取注册信息的时间间隔(s),默认为30秒
registry-fetch-interval-seconds: 15
# 心跳检测与续约时间
# 测试时将值设置小些,保证服务关闭后注册中心及时剔除服务
instance:
# Eureka客户端向服务端发送心跳的间隔时间,单位秒
lease-renewal-interval-in-seconds: 15
# 服务端在收到最后一次心跳之后等待的时间上限,单位秒,超过则剔除
lease-expiration-duration-in-seconds: 30
# 以IP地址注册到服务中心,相互注册使用IP地址
prefer-ip-address: true
随便定义一个Order实体类:
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "订单实体", description = "")
public class Order {
@ApiModelProperty(value = "订单号", required = true, example = "123")
private String orderNo;
@ApiModelProperty(value = "数量", required = true, example = "456")
private Integer num;
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
}
定义一个测试用的Controller接口
@Api(tags = "订单接口")
@RestController
@RequestMapping("/order")
public class OrderController {
@ApiOperation(value = "列表查询", notes = "")
@PostMapping(value = "/list")
public BaseResult getList(@RequestBody Order params) {
List<Order> list = new ArrayList<Order>();
Order order = new Order();
order.setOrderNo("123");
order.setNum(456);
list.add(order);
return BaseResult.success(list);
}
}
启动类增加注解,如下:
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class SpringcloudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudApplication.class, args);
}
}
2、商品服务goods-service
pom.xm引入和订单服务一样,yml配置也一样,修改下端口。Order实体也复制过去(实际项目中可以抽出来放到公共模块),启动类注解也一样。
定义一个远程调用的接口
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import com.example.springcloud.base.BaseResult;
import com.example.springcloud.entity.Order;
@FeignClient(value = "order-service") // 订单服务的应用名
public interface OrderServiceFeign {
@PostMapping(value = "/order/list") // 接口路径
public BaseResult getList(@RequestBody Order params); //参数和订单服务的controller一致
}
定义一个测试用的Controller接口,并且调用订单服务Controller的接口
@Api(tags = "商品接口")
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private OrderServiceFeign orderServiceFeign;
@ApiOperation(value = "列表订单查询", notes = "")
@PostMapping(value = "/orderList")
public BaseResult getList(@RequestBody Order params) {
return orderServiceFeign.getList(params);
}
}
3、启动服务
启动两个服务,可以在Eureka看到两个服务都注册上来了
然后打开商品服务的swagger,调用接口
响应内容是我们在订单服务controller接口设置的,测试没问题,说明能正常远程调用。
4、整合hystrix
在商品服务(调用方)的pom.xml引入:
<!-- 整合hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
yml文件加入以下:
hystrix:
command:
default:
execution:
isolation:
thread:
# 接口超时时间3s
timeoutInMilliseconds: 3000
启动类加入@EnableHystrix注解:
@EnableHystrix
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class SpringcloudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudApplication.class, args);
}
}
商品测试服务的controller定义熔断方法fallbackMethodOne,并在测试接口加入注解@HystrixCommand,指定熔断方法:
@Api(tags = "商品接口")
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private OrderServiceFeign orderServiceFeign;
@HystrixCommand(fallbackMethod = "fallbackMethod")
@ApiOperation(value = "列表订单查询", notes = "")
@PostMapping(value = "/orderList")
public BaseResult getList(@RequestBody Order params) {
return orderServiceFeign.getList(params);
}
// 熔断方法,注意这里参数要和上面方法的参数一致
public BaseResult fallbackMethod(@RequestBody Order params) {
return BaseResult.fail(500,"fail,接口熔断");
}
}
4.1、测试场景1:被调用的方法出现异常
在订单服务的接口增加异常:
@ApiOperation(value = "列表查询", notes = "")
@PostMapping(value = "/list")
public BaseResult getList(@RequestBody Order params) {
List<Order> list = new ArrayList<Order>();
Order order = new Order();
order.setOrderNo("123");
order.setNum(456);
list.add(order);
System.out.println(1/0); //设置异常
return BaseResult.success(list);
}
继续swagger上调用,结果如下
符合预期
4.2、测试场景2:被调用的方法超时未返回
在订单服务的接口增加sleep,睡眠4s或者更长,因为我们配置文件设置的超时时间是3s
@Api(tags = "订单接口")
@RestController
@RequestMapping("/order")
public class OrderController {
@ApiOperation(value = "列表查询", notes = "")
@PostMapping(value = "/list")
public BaseResult getList(@RequestBody Order params) {
List<Order> list = new ArrayList<Order>();
Order order = new Order();
order.setOrderNo("123");
order.setNum(456);
list.add(order);
//System.out.println(1/0); //设置异常
try {
// 设置睡眠
Thread.sleep(4*1000L);
} catch (Exception e) {
e.printStackTrace();
}
return BaseResult.success(list);
}
}
继续swagger上调用,结果如下
可以看到接口耗时3s,等待订单服务接口响应3s,超时未返回,返回了备胎的熔断方法结果,
测试符合预期。
到此整合结束。