在SpringCloud 从入门到精通 09--- 支付服务集群中,我们通过使用RestTemplate
进行了服务的调用,本节我们使用更优雅的方式OpenFeign
来实现基于接口的微服务调用.本节内容较多,不会一一的把每个服务中的内容都写清楚,所以如果有不明白的地方,可以看前几章,也可以在下放留言交流.
本节需准备三个项目
cloud-alibaba-payment-9001
cloud-alibaba-payment-9002
cloud-alibaba-order-8000
这三个项目在之前的章节中有相关的代码,现在我们使用nacos
作为服务注册中心、配置中心,把cloud-alibaba-payment-9001
cloud-alibaba-payment-9002
cloud-alibaba-order-8000
都注册进入nacos
集群,通过cloud-alibaba-order-8000
来访问cloud-alibaba-payment-9001
和 cloud-alibaba-payment-9002
,并实现负载均衡.
之前,我们采用的是注入RestTemplate
实现微服务的调用,现在引入了OpenFeign
后,就不再采用它了,首先在pom.xml
中引入OpenFeign
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloudservice</artifactId>
<groupId>com.felix</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-alibaba-order-8000</artifactId>
<dependencies>
<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>com.felix</groupId>
<artifactId>cloud-mbg</artifactId>
</dependency>
<dependency>
<groupId>com.felix</groupId>
<artifactId>cloud-common</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-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
</project>
复制代码
注释掉ApplicationContextConfig
//package com.felix.order.config;
//
//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;
//
//@Configuration
//public class ApplicationContextConfig {
// @Bean
// @LoadBalanced
// public RestTemplate restTemplate(){
// return new RestTemplate();
// };
//}
复制代码
增加service
包,新增PaymentService
package com.felix.order.service;
import com.felix.common.result.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@Component
@FeignClient(value = "cloud-alibaba-payment")
public interface PaymentService {
@PostMapping(value = "/payment/create")
CommonResult createPayment(String serialNo);
@GetMapping(value = "/payment/{id}")
CommonResult getPayment(@PathVariable(value = "id") Long id);
@GetMapping(value = "/payment/timeout")
CommonResult timeout();
}
复制代码
这里,我们添加了@FeignClient(value = "cloud-alibaba-payment")
注解,不同于之前的项目,我们采用http://
的形式引入微服务的名称,大家可以把这个注解理解为相同的逻辑,指明我们将要使用OpenFeign
进行微服务的调用.请注意,这里的@PostMapping(value = "/payment/create")
@GetMapping(value = "/payment/{id}")
@GetMapping(value = "/payment/timeout")
与cloud-alibaba-payment-9001
的接口请求方式和接口uri
是对应的,这里贴一下cloud-alibaba-payment-9001
的PaymentController
中的内容
package com.felix.payment.controller;
import com.felix.common.result.CommonResult;
import com.felix.payment.service.CPaymentService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Controller
@RequestMapping("/payment")
public class PaymentController {
@Resource
private CPaymentService paymentService;
@PostMapping(value = "/create")
@ResponseBody
public CommonResult createPayment(String serialNo){
return paymentService.createPayment(serialNo);
}
@GetMapping(value = "/{id}")
@ResponseBody
public CommonResult getPayment(@PathVariable Long id){
return paymentService.getPayment(id);
}
@GetMapping(value = "/timeout")
@ResponseBody
public CommonResult timeout(){
return paymentService.timeout();
}
}
复制代码
这里新增了一个timeout
的接口,其实现是
@Override
public CommonResult timeout() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new CommonResult(200,"操作成功,当前服务是:payment"+port,"success",null);
}
复制代码
只进行了 3 秒的线程 sleep
,大家先添加好,后面针对应用场景进行说明
回到cloud-alibaba-order-8000
,有了PaymentService
接口,我们直接在OrderController
中按照常规的方式去写
package com.felix.order.controller;
import com.felix.common.result.CommonResult;
import com.felix.order.service.PaymentService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Controller
@RequestMapping("/order")
public class OrderController {
@Resource
private PaymentService paymentService;
@PostMapping(value = "/payment/create")
@ResponseBody
public CommonResult createPayment(String serialNo){
return paymentService.createPayment(serialNo);
}
@GetMapping(value = "/payment/{id}")
@ResponseBody
public CommonResult getPayment(@PathVariable Long id){
return paymentService.getPayment(id);
}
@GetMapping(value = "/payment/timeout")
@ResponseBody
public CommonResult timeout(){
return paymentService.timeout();
}
}
复制代码
这里PaymentService
没有实现,其实现由OpenFeign
帮我们实现,我们只需要注入PaymentService
然后使用即可,现在,项目目录如下ApplicationContextConfig
是全部注释掉了,所以显示的图标如此
然后,配置CloudOrderApplication
开启对于OpenFeign
的使用
package com.felix.order;
import feign.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class CloudOrderApplication {
public static void main(String[] args) {
SpringApplication.run(CloudOrderApplication.class,args);
}
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
复制代码
解释一下这里注入的feignLoggerLevel
,目的是用来对OpenFeign
所作的请求进行的日志输出级别的定义.
然后,配置一下bootstrap.yml
spring:
application:
name: cloud-alibaba-order-comsumer
cloud:
nacos:
discovery:
server-addr: localhost:8847
config:
server-addr: localhost:8847
file-extension: yaml
group: PROD_GROUP
namespace: 0ca7333d-533c-4fdf-9860-f1fb69b9edc6
ribbon:
ReadTimeout: 60000 #等待服务器处理的超时时间
ConnectTimeout: 2000 #建立 socket 连接所需要的超时时间
server:
port: 8000
management:
endpoints:
web:
exposure:
include: '*'
logging:
level:
com.felix.order.service.PaymentService: debug
复制代码
这里spring.cloud.nacos.config
的内容,如果在nacos
中没有进行配置,那么这里可以忽略不写.然后ribbon
中定义了ReadTimeout
和ConnectTimeout
的超时时间,为什么呢?
OpenFeign 自带了 Ribbon,Ribbon 在进行服务调用的时候,默认超时时间为 1S,所以,按照我们在 cloud-alibaba-payment-9001 的/payment/timeout 接口中进行了 3 秒的延时操作,会直接导致 Ribbon 的调用超时,进而报错,为了避免这种情况,就需要在 OpenFeign 的服务中,针对超时的时间进行定义
接下来,启动cloud-alibaba-payment-9001
cloud-alibaba-payment-9002
cloud-alibaba-order-8000
,然后多次访问http://localhost:8000/order/payment/1,不仅可以正常的返回信息,而且实现了负载均衡
本节有两个坑,
第一个是当spring.application.name
为 consumer
开头的时候,那么服务注册会出现问题,目前未见官方修复,请避免使用consumer
的prefix
2021-02-02 修正:上述的问题理论上不应该存在,而是在注册服务的时候出了问题,所以还是要检查自己的服务和注册中心是否有问题
当前我使用的nacos-client
版本是1.3.3
,启动两个相同的服务后(9001 和 9002),那么nacos
中的健康实例数会持续跳变,目前也采用了1.4.1
1.4.0
两个版本,并未解决此问题,等待官方进行解决.
2021-02-02 修正:部署完线上版本之后,服务端采用1.3.2
可以正常使用,并且不存在健康实例数持续跳变的问题,可参考我在简书上的文章https://www.jianshu.com/p/1128b2640565
评论