阅读 232

feign多服务间的调用

上文我们把我们项目注册到服务器上了,但是在微服务中,我们会有多个服务,同时也会使用A服务调用B服务的接口。springcloud netflix这里有两种方式ribbon和feign,我们分别介绍。

1.ribbon

ribbon说白了就是使用restTemplate。上文编写了被调用方的代码,下文将编写调用方的代码。

1.修改pom文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>     <parent>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-parent</artifactId>         <version>2.2.5.RELEASE</version>         <relativePath/> <!-- lookup parent from repository -->     </parent>     <groupId>com.baocl</groupId>     <artifactId>eureka-consumer</artifactId>     <version>0.0.1-SNAPSHOT</version>     <name>eureka-consumer</name>     <description>Demo project for Spring Boot</description>     <properties>         <java.version>1.8</java.version>         <spring-cloud.version>Hoxton.SR1</spring-cloud.version>     </properties>     <dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>         </dependency>         <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-test</artifactId>             <scope>test</scope>             <exclusions>                 <exclusion>                     <groupId>org.junit.vintage</groupId>                     <artifactId>junit-vintage-engine</artifactId>                 </exclusion>             </exclusions>         </dependency>     </dependencies>     <dependencyManagement>         <dependencies>             <dependency>                 <groupId>org.springframework.cloud</groupId>                 <artifactId>spring-cloud-dependencies</artifactId>                 <version>${spring-cloud.version}</version>                 <type>pom</type>                 <scope>import</scope>             </dependency>         </dependencies>     </dependencyManagement>     <build>         <plugins>             <plugin>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-maven-plugin</artifactId>             </plugin>         </plugins>     </build> </project> 复制代码

2.修改Application

然后修改EurekaConsumerApplication类,需要在新建RestTemplate的bean。

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient public class EurekaConsumerApplication { @Bean @LoadBalanced // ribbon注解 public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(EurekaConsumerApplication.class, args); } } 复制代码

3.新建调用方接口DcController

新建普通接口,调用上文被调用方的服务。

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/eureka1") public class DcController { @Autowired LoadBalancerClient loadBalancerClient; @Autowired RestTemplate restTemplate; @Autowired DiscoveryClient discoveryClient; @GetMapping("/consumer") public ResponseEntity<String> dc() { //String url = "http://eureka-client/aaa/dc?dk=3001"; String url = "http://EUREKA-CLIENT/aaa/dc?dk=3001"; System.out.println(url); // ServiceInstance serviceInstance = // loadBalancerClient.choose("eureka-client");// 获取服务提供者信息 // // String url = "http://localhost:" + serviceInstance.getPort() + "/aaa/dc"; // System.out.println(serviceInstance.getPort() ); // System.out.println(url); // ResponseEntity r = restTemplate.getForEntity("http://eureka-client/aaa/dc", // String.class); // System.out.println("r.getHeaders().getHost():"+r.getHeaders().getHost()); // System.out.println("r.getHeaders().getLocation():"+r.getHeaders().getLocation()); // System.out.println("r.getHeaders().getOrigin():"+r.getHeaders().getOrigin()); return restTemplate.getForEntity(url, String.class); // ribbon应用 } } 复制代码

有一个坑  在调用时候需要String url = "http://eureka-client/aaa/dc?dk=3001",而不是String url ="http://localhost:2002/aaa/dc?dk=3001",否则会报错java.lang.IllegalStateException: No instances available for localhost.

4.修改application

最后是配置文件application.yml,这里我们使用.yml文件,都是基础配置。

eureka:   client:     registery-fetch-interval-seconds: 5000      serviceUrl:       defaultZone: http://localhost:1001/eureka/       eureka-client:   ribbon:     NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  server:   port: 3001 spring:   application:     name: eureka-consumer 复制代码

输入http://localhost:3001/eureka1/consumer 就可以调用到上文的client服务了,同时还可以配置负载均衡策略。在NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule 处配置。

2.feign

1.修改pom文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>     <parent>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-parent</artifactId>         <version>2.2.5.RELEASE</version>         <relativePath/> <!-- lookup parent from repository -->     </parent>     <groupId>com.baocl</groupId>     <artifactId>eureka-consumer-feign</artifactId>     <version>0.0.1-SNAPSHOT</version>     <name>eureka-consumer-feign</name>     <description>Demo project for Spring Boot</description>     <properties>         <java.version>1.8</java.version>         <spring-cloud.version>Hoxton.SR1</spring-cloud.version>     </properties>     <dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-feign</artifactId>             <version>1.4.7.RELEASE</version>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>             <scope>test</scope>             <exclusions>                 <exclusion>                     <groupId>org.junit.vintage</groupId>                     <artifactId>junit-vintage-engine</artifactId>                 </exclusion>             </exclusions>         </dependency>     </dependencies>     <dependencyManagement>         <dependencies>             <dependency>                 <groupId>org.springframework.cloud</groupId>                 <artifactId>spring-cloud-dependencies</artifactId>                 <version>${spring-cloud.version}</version>                 <type>pom</type>                 <scope>import</scope>             </dependency>         </dependencies>     </dependencyManagement>     <build>         <plugins>             <plugin>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-maven-plugin</artifactId>             </plugin>         </plugins>     </build> </project> 复制代码

版本问题一定要控制!!!!这里有一个坑 就是版本问题,有时会报错

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [F:\workspace\springcloud\tse9\eureka-consumer-feign\target\classes\com\cloud\DcClient.class]; nested exception is org.springframework.core.annotation.AnnotationConfigurationException: Attribute 'value' in annotation [org.springframework.cloud.netflix.feign.FeignClient] must be declared as an @AliasFor 'serviceId', not 'name'. 复制代码

解决办法可以参考:www.pianshen.com/article/223…

2.修改EurekaConsumerFeignApplication

首先在EurekaConsumerFeignApplication使用@EnableFeignClients中开启feign

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients @EnableDiscoveryClient @SpringBootApplication public class EurekaConsumerFeignApplication { public static void main(String[] args) { SpringApplication.run(EurekaConsumerFeignApplication.class, args); } } 复制代码

3.新建接口DcClient

新建一个接口DcClient,配置调用其他服务的名称和接口名称。(被调用方客户端的服务与接口信息)

import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(name = "eureka-client") public interface DcClient { @GetMapping("/aaa/dc?dk=3002") String consumer(); @GetMapping("/aaa/dc?dk=3002") String consumer2(); } 复制代码

4.新建调用接口DcController

业务接口的书写,同时注入dcClient调用其他服务。

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.cloud.DcClient; @RestController @RequestMapping("/eureka2") public class DcController { @Autowired DcClient dcClient; @GetMapping("/consumer") public String dc() { return dcClient.consumer(); } } 复制代码

5.修改application.properties

下文是最基础的配置。

spring.application.name=eureka-consumer-feign server.port=3002 eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/ 复制代码

然后调用http://localhost:3002/eureka2/consumer 可以发现接口掉通了 ,在被调用方也有相应的日志。

3.ribbon和Eureka整合原理

基本流程就是 客户端从eureka中获取到缓存的服务列表,获取到目的服务的信息,然后通过自身的负载均衡策略,去调用对应的服务。 在这里插入图片描述

1.负载均衡策略

  1. BestAvailableRule 选择一个最小的并发请求的server。

  2. AvailabilityFilteringRule 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)。

  3. WeightedResponseTimeRule 根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。

  4. RetryRule 对选定的负载均衡策略机上重试机制。

  5. RoundRobinRule roundRobin方式轮询选择server.。

  6. RandomRule 随机选择一个server。

  7. ZoneAvoidanceRule 复合判断server所在区域的性能和server的可用性选择server。


作者:小黄鸡1992
链接:https://juejin.cn/post/7022429183842189320

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐