spring-cloud 服务间通信与调用(Feign)
spring-cloud 服务间通信与调用(Feign)
Feign简介 Feign 的主要作用就是简化远程调用 我们可以对比一下使用Eureka做原始HTTP调用,Ribbon调用和Feign调用三种方式
- 使用Eureka做原始HTTP调用
- Ribbon调用
- Feign组件调用 controller service:
- feign的简单使用案例 运行条件注册中心启动,服务提供者启动(服务名:eureka-client)
第一步:依赖
<dependencies> <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.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
第二步:启动类
package com.lys.springcloud; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; /** * Created with IntelliJ IDEA. * User: Administrator * Date: 2021/4/19 * Time: 22:55 * Description: No Description */ @EnableDiscoveryClient @SpringBootApplication @EnableFeignClients // 开启feign public class FeignConsumerApplication { public static void main(String[] args) { new SpringApplicationBuilder(FeignConsumerApplication.class) .web(WebApplicationType.SERVLET) .run(args); } }
第三步:配置文件
spring.application.name=feign-consumer server.port=40001 #允许注解重载(解决spring-cloud G版 @FeignClient修饰的接口无法继承的问题) #spring.main.allow-bean-definition-overriding=true eureka.client.service-url.defaultZone=http://localhost:20000/eureka/
第四步:声明接口
package com.lys.springcloud; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; /** * Created with IntelliJ IDEA. * User: Administrator * Date: 2021/4/19 * Time: 22:59 * Description: No Description */ @FeignClient("eureka-client") //服务提供者的服务名 public interface IService { @GetMapping("/hello") String hello(); }
第五步:调用
package com.lys.springcloud; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * Created with IntelliJ IDEA. * User: Administrator * Date: 2021/4/19 * Time: 23:05 * Description: No Description */ @RestController public class Controller { @Autowired private IService iService; @GetMapping("/hello") public String hello() { return iService.hello(); } }
深入学习Feign
- Feign的体系架构 feign是如何实现简化远程调用的呢?总体来说就是:声明一个代理接口,服务调用者通过调用这个代理接口来实现远程调用。 Feign 构建请求: 如上图所示,feign自身就引用了Ribbon组件和Hystrix组件,在构建请求时,Feign通过调用Ribbon的负载均衡策略来选定目标机器,通过调用Hystrix的熔断机制来判断是否发起调用
- Feign的底层机制
第六步:InvocationHandler类的invoke方法进行拦截
第七步:最终将由SynchronousMethodHandler类的invoke进行请求调用和结果返回
- 重试
理想的Feign风格项目结构 基于HTTP的服务治理方案在使用了feign组件之后,确实简化了一大部分的服务间调用代码,但是也出现了冗余的部分。在我们书写调用代码的过程中,有的人可能会发现,使用@FeignClient声明的接口代码中,如路径、post/get等信息,服务提供者已经书写过一遍了,我们要怎么样才能简化代码做到最理想化呢? answer: 当然是分离接口和接口实现,将接口作为一个独立的模块,如果要使用接口, 那么服务提供者可以实现该接口,而服务调用者只需继承该接口即可。 这里会有两种方式: 第一种在抽象的接口模块中加了@FeignClient注解,调用方需注意两点: 1.注意feign版本冲突,如若依赖冲突了可以在pom中使用exclude排除冲突项 2.调用方继承接口可不指定@FeignClient注解,但是需要指定basePackages属性,确保能代理本地接口 3.当然,如果要指定降级策略肯定需要加@FeignClient,然后添加fallback,不过需要注意父接口子自接口的primary属性都等于true的问题 第二种:在抽象的接口模块中没有加@FeignClient注解,调用方需注意两点: 1.调用方继承接口需要指定@FeignClient注解 其他属性视具体调用清空指定。 推荐使用第二种,第二种更灵活,适用性更高。