OpenFegin 调用微服务

1. 流程

在这我们创建两个支付微服务 一个订单服务 和 一个单机版的eureka服务注册中心

并且将 支付服务注册进eureka

在订单服务中使用openfeign调用 支付服务 并且实现负载均衡

其实openfeign也是在集成了ribbon

image-20200810221324335

2.euruka服务注册中心的搭建

2.1.pom

(版本控制都在父项目中,springboot版本 2.2.2.RELEASE springcloud版本 Hoxton.SR1 其他的自行选择)

 <dependencies>
        <!--eureka-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--boot web actuator-->
        <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.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

2.2yml

server:
  port: 7001

eureka:
  instance:
    hostname:localhost #eureka服务端的实例名称
  client:
    register-with-eureka: false     #false表示不向注册中心注册自己。
    fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    service-url:
      #设置与Eureka server 交互的地址查询服务和注册服务都需要依赖这个地址。
      defaultZone: http://localhost.com:7001/eureka/ #单机版 指向自己

2.3主启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @author Xkuna
 * @date 2020/7/22 15:32.
 */

@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class, args) ;
    }
}

3.创建支付服务8001

3.1pom

  <dependencies>
        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.2yml

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service #微服务名称
eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机版
      defaultZone: http://localhost:7001/eureka
  instance:
    instance-id: payment8001
    prefer-ip-address: true

3.3主启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author Xkuna
 * @date 2020/7/21 23:05.
 */

@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class, args) ;
    }
}

3.4创建controller

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

/**
 * @author Xkuna
 * @date 2020/7/22 11:10.
 */
@RestController
@Slf4j
public class PaymentControler {

    @Value("${server.port}")
    private String serverPort ;

    @GetMapping("/port")
    public String getPort(){
        return this.serverPort ;
    }

    @GetMapping("/timeout")
    public String timeout() {
        try {
            TimeUnit.SECONDS.sleep(3) ;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return this.serverPort ;
    }
}

4.创建支付服务8002

将支付服务8001 copy一份 把端口改为 8002 即可

5.创建订单服务80

5.1pom

   <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--web-->
        <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.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

5.2 yml

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:7001/eureka/

5.3主启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @author Xkuna
 * @date 2020/8/7 15:51.
 */
@SpringBootApplication
@EnableFeignClients//开启openfeign
public class OrderOpenfeginMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderOpenfeginMain80.class, args) ;
    }
}

5.4创建service接口

创建一个openfeign调用支付服务的接口

方法 直接copy支付服务的接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;


/**
 * @author Xkuna
 * @date 2020/8/7 16:00.
 */
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE") //调用的服务名称
public interface PaymentFeignService {
   
	@GetMapping("/port")
    public String getPort()@GetMapping("/timeout")
    public String timeout() ;
}

5.5创建controller

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import top.xkuna.springcloud.service.PaymentFeignService;

import javax.annotation.Resource;

/**
 * @author Xkuna
 * @date 2020/8/7 16:03.
 */
@RestController
@Slf4j
public class OrderController {
    @Resource
    private PaymentFeignService paymentFeignService ;


	@GetMapping("/port")
    public String getPort(){
        return paymentFeignService.getPort() ;
    }

    @GetMapping("/timeout")
    public String timeout() {
        return paymentFeignService.timeout() ;
    }
}

6.启动测试

先启动eureka7001 然后启动 支付服务8001 8002 最后启动 订单服务80

访问: http://localhost/port

访问成功 并且发现实现了负载均衡

image-20200810232629109

image-20200810232646219

但是当我们访问timeout接口时 出现了报错

image-20200810233113729

原因是openfeign 负载均衡的底层还是调用了ribbon

在ribbon中 调用服务时 默认的调用 时限为 1000ms

我们在支付服务的timeout接口 暂停了 3 s 所以超时调用报错

修改ribbon默认调用时限

在订单服务的yml配置中添加


#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ConnectTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ReadTimeout: 5000

此时我们再次调用 支付服务

image-20200810233835653

image-20200810233854168

成功调用 支付服务 并且实现了负载均衡

7.openfeign日志打印

openfeign自带了日志打印功能

7.1创建日志配置类


import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Xkuna
 * @date 2020/8/7 16:29.
 */
@Configuration
public class FeginConfig {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

7.2修改yml

在yml中添加 日志配置

logging:
  level:
    top.xkuna.springcloud.service: debug  //前面的是要输出日志的openfeign接口包 或者类

访问订单服务port接口

查看控制台

image-20200810234652116

8.结束语

openfeign 跟ribbon比 使用起来是不是更舒服一些呢~ 😄 😄

可以根据自己需求选择 ribbon 或者 feign 再或者 openfeign 来做服务调用

踩坑

报错The bean 'xx.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.

这句话的意思是 ioc容器中已经存在FeignClientSpecification这个bean

出现这种情况是 多个feign客户端调用了 同一个服务

比如:

image-20200812172345201

image-20200812172359072

这两个feign客户端调用了 同一个服务 导致bean注册失败

出现这种情况,一般来说 是 服务功能划分还是不够“”,

解决方法是 在yml中添加一个配置

spring:
 main:
   allow-bean-definition-overriding: true #表示后发现的bean会覆盖之前相同名称的bean。

不过 建议还是不要这样做,否则后者覆盖前者,多人分工合作的时候,难以避免某些bean被覆盖,会出现很多诡异的问题 ,甚至会带来线上真实的业务损失

所以 建议 要么将该服务下的业务 写在同一个 feign客户端接口中, 要么就在项目初期 规划好项目服务的划分,真正达到微服务中的“

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值