写点什么

SpringCloud 从入门到精通 14---OpenFeign 服务调用

用户头像
Felix
关注
发布于: 2021 年 01 月 21 日

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-9001cloud-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-9001PaymentController中的内容

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@EnableFeignClientspublic 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中定义了ReadTimeoutConnectTimeout的超时时间,为什么呢?

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.nameconsumer开头的时候,那么服务注册会出现问题,目前未见官方修复,请避免使用consumerprefix


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


发布于: 2021 年 01 月 21 日阅读数: 37
用户头像

Felix

关注

还未添加个人签名 2020.12.24 加入

还未添加个人简介

评论

发布
暂无评论
SpringCloud 从入门到精通14---OpenFeign服务调用