往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用
。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可)
,即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。openfeign与feign区别:
openfign | feign |
---|---|
Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务 | OpenFeign是Spring Cloud 在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。 |
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId></dependency> | <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency> |
<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> <!-- 引入自己定义的api通用包,可以使用Payment支付Entity --> <dependency> <groupId>com.zhubayi.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </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>
application.yml
server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
OrderFeignMain80
package com.zhubayi.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author zhubayi */ @SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class, args); } }
不加@EnableFeignClients注解@FeignClient会不起作用
新建PaymentFeignService
接口并新增注解@FeignClient
package com.zhubayi.springcloud.service; import com.zhubayi.springcloud.entities.CommonResult; import com.zhubayi.springcloud.entities.Payment; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** * @author zhubayi */ @Service @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping("payment/list") CommonResult list(); @GetMapping("payment/get/{id}") CommonResult get(@PathVariable("id") Long id); @GetMapping("payment/feignTimeout") String paymentFeignServiceTimeout(); }
Controller
package com.zhubayi.springcloud.controller; import com.zhubayi.springcloud.entities.CommonResult; import com.zhubayi.springcloud.entities.Payment; import com.zhubayi.springcloud.service.PaymentFeignService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author zhubayi */ @RestController @RequestMapping("") public class OrderFeignController { @Autowired private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) { return paymentFeignService.get(id); } @GetMapping(value = "/consumer/payment/list") public CommonResult<Payment> list() { return paymentFeignService.list(); } @GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout() { // OpenFeign客户端一般默认等待1秒钟 我设置的两秒钟 return paymentFeignService.paymentFeignServiceTimeout(); } }
新建配置类FeignConfig
,配置输出远程调用情况
package com.zhubayi.springcloud.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author zhubayi */ @Configuration public class FeignConfig { @Bean public Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
完整目录结构
测试:先启动2个eureka集群7001/7002,再启动2个微服务8001/8002,最后启动这个80端口。
启动成功界面
浏览器输入:http://localhost/consumer/payment/get/1
再刷新一下:
可以看到端口变了,因为它引入了ribbon
负载均衡,默认采用轮询算法进行负载均衡。
注意:Feign调用的时候要路径写全。
控制台输出
超时设置,故意设置超时演示出错情况,浏览器输入:http://localhost/consumer/payment/feign/timeout
可以看到报错了,报的是超时异常。
因为OpenFeign默认等待1秒钟,超过后报错 。因为我设置的2s,超过了1
s,所以报错了。
有时我们处理业务的时间超过了1s,所以我们要设置一下超时等待的时间。
在cloud-consumer-feign-order80
模块的application.yml
文件里需要开启OpenFeign客户端超时控制
server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ #设置feign客户端超时时间(OpenFeign默认支持ribbon) ribbon: #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ReadTimeout: 5000 #指的是建立连接后从服务器读取到可用资源所用的时间 ConnectTimeout: 5000 logging: level: # feign日志以什么级别监控哪个接口 com.zhubayi.springcloud.service.PaymentFeignService: debug
配置后再去访问就不会报错了!