个人博客:兰陵笑笑生,欢迎浏览博客!java
上一章 SpringCloud基础教程(六)-负载均衡Ribbon当中,咱们介绍了Ribbon在微服务中是如何作到负载均衡的,本期咱们将在此基础上使用Fegin更加简化的实现服务间的调用。git
什么是Fegin,在解释以前,咱们先梳理一下咱们以前学习到的,在微服模式下,解决服务间的调用能够经过Grpc、HttpClient、(Spring中的resttemplate是对HttpClient的封装)等开源框架,这种调用咱们称之为远程过程的调用,即RPC,那么进行RPC调用须要解决几个重要的问题,一个是序列化/反序列化,好比Json/xml等怎样序列化和反序列化等,再一个就是以什么样的协议实现这样的调用。这两个问题在开源社区都有了很好的技术方案。那么Spring Cloud Fegin主要是为了更简单的实现开发,封装了Http的调用流程,更适合面向接口化编程的习惯。咱们虽然能经过Ribbon和RestTemplate经过URL进行远程调用,可是这样拼接参数,并非特别的优雅,为此,咱们能够经过使用Feign让远程调用变的更简洁。程序员
咱们在上几章的服务调用方server-consumer示例的pom文件中添加Feign的依赖 (我使用的spring Cloud版本是Greenwich.SR3版本,不一样的Feign依赖可能不太同样):github
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
接着咱们在调用方主类上添加@EnableFeignClients 表示客户端容许开启使用Feign调用。web
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class ServerConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServerConsumerApplication.class, args); } }
而后定义Feign的接口,FeignClient(name = "server-provider") name 指的是在Eureka注册的服务名称,也是能够直接使用ip的,若是指定了url ,那么name就是只是一个标识。spring
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "server-provider") public interface HelloApi { @RequestMapping("/sayHello") public String sayHello(@RequestParam("name") String name); }
编写控制器注入接口,调用:编程
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class FeignController { @Autowired HelloApi helloApi; @GetMapping("/sayHello") public String sayHello(String name) { String res = helloApi.sayHello(name); return res; } }
服务的提供方server-provider代码不变:app
import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class RibbonController { @Value("${server.port}") private String port; @RequestMapping("/sayHello") public String sayHello(String name) { return "from:"+port+ ",hello!,"+name; } }
以后,咱们启动Eureka注册中心,启动服务提供者,启动修改的服务调用者,查看Eureka注册中心:有一个服务调用方,2个名称为server-provider的服务提供方:负载均衡
经过HTTP方式http://localhost:5168/sayHello?name=test 咱们能够正确的返回信息,而且经过屡次的调用,默认的负载均衡方式是轮询,而且集成了Ribbon,若是咱们想要修改负载均衡的策略,能够参考上一章框架
SpringCloud基础教程(六)-负载均衡Ribbon 实现。
经过以上的方式,咱们能够很方便的把一个HTTP的请求转换为很是友好的、接口的方式。
在引入了spring-cloud-starter-openfeign以后,咱们能够点击进入配置文件查看到底依赖了那些项目,它主要是集成了 io.github.OpenFeign:
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-openfeign-core</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-commons</artifactId> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-core</artifactId> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-slf4j</artifactId> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-hystrix</artifactId> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-java8</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-archaius</artifactId> <optional>true</optional> </dependency> </dependencies>
在spring-cloud-openfeign-core依赖中,org.springframework.cloud.openfeign.FeignClientsConfiguration是Feign的默认配置类:
咱们到底能够配置那些内容呢?咱们先看看具体的源代码:
/** * @author Dave Syer * @author Venil Noronha */ @Configuration public class FeignClientsConfiguration { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Autowired(required = false) private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>(); @Autowired(required = false) private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>(); @Autowired(required = false) private Logger logger; //反序列化 @Bean @ConditionalOnMissingBean public Decoder feignDecoder() { return new OptionalDecoder( new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))); } //序列化 @Bean @ConditionalOnMissingBean @ConditionalOnMissingClass("org.springframework.data.domain.Pageable") public Encoder feignEncoder() { return new SpringEncoder(this.messageConverters); } @Bean @ConditionalOnClass(name = "org.springframework.data.domain.Pageable") @ConditionalOnMissingBean public Encoder feignEncoderPageable() { return new PageableSpringEncoder(new SpringEncoder(this.messageConverters)); } //接口的验证等 @Bean @ConditionalOnMissingBean public Contract feignContract(ConversionService feignConversionService) { return new SpringMvcContract(this.parameterProcessors, feignConversionService); } @Bean public FormattingConversionService feignConversionService() { FormattingConversionService conversionService = new DefaultFormattingConversionService(); for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) { feignFormatterRegistrar.registerFormatters(conversionService); } return conversionService; } @Bean @ConditionalOnMissingBean public Retryer feignRetryer() { return Retryer.NEVER_RETRY; } //客户端构造器 @Bean @Scope("prototype") @ConditionalOnMissingBean public Feign.Builder feignBuilder(Retryer retryer) { return Feign.builder().retryer(retryer); } //默认的日志实现 @Bean @ConditionalOnMissingBean(FeignLoggerFactory.class) public FeignLoggerFactory feignLoggerFactory() { return new DefaultFeignLoggerFactory(this.logger); } @Bean @ConditionalOnClass(name = "org.springframework.data.domain.Page") public Module pageJacksonModule() { return new PageJacksonModule(); } //这里咱们能够配置集成 Hystrix @Configuration @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class }) protected static class HystrixFeignConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean @ConditionalOnProperty(name = "feign.hystrix.enabled") public Feign.Builder feignHystrixBuilder() { return HystrixFeign.builder(); } } }
从源代码当中,咱们提取如下几个配置,这些咱们均可以去自定义的配置的:
服务的调用方主类,若是咱们修改负载均衡的策略,添加@RibbonClient开启,参考上一章,其余的不变。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient //@RibbonClient(name = "server-provider",configuration = RibbonConfig.class) @EnableFeignClients public class ServerConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServerConsumerApplication.class, args); } }
Fegin接口的@FeignClient 配置MyFeignConfig.class
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "server-provider",configuration = MyFeignConfig.class) public interface HelloApi { @RequestMapping("/sayHello") public String sayHello(@RequestParam("name") String name); }
新建配置类MyFeignConfig.class,这里咱们能够为每一个客户端配置一个Logger.Level对象,级别有如下的级别:
import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyFeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
配置 application.yml,logging.level 添加具体Fegin接口的全类名,值为DUBUG,
logging: level: com.microservice.consumer.test.HelloApi : DEBUG
启动项目,经过HTTP咱们调用接口:看到调用的日志包含了请求的request,返回的response,包括编码使用了gzip,以及请求的元数据:
配置applicaiton.yml
feign: compression: request: enabled: true response: enabled: true
Hystrix集成Feign能够实现熔断的功能,首先配置applicaiton.yml,开启熔断功能
feign: hystrix: enabled: true
重构Feign接口,添加接口调用失败、出现异常时候,使用本地的服务降级的自定义结果,并注入应用中:
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "server-provider",configuration = MyFeignConfig.class, fallback =HelloApi.HelloApiFallBack.class) public interface HelloApi { @RequestMapping("/sayHello") public String sayHello(@RequestParam("name") String name); @Component class HelloApiFallBack implements HelloApi{ @Override public String sayHello(String name) { return "服务调用失败"; } } }
当服务调用失败的时候,会返回咱们自定义的结果:
关于更多的服务熔断组件Hystrix咱们将用单独的一章去介绍,这里简单的整合了Hystrix,实现了熔断的功能。
Feign组件的使用,不只可以大大简化HTTP调用的简化,提供编码的可读性和友好性。并且可以完美的支持Ribbon和Hystrix也是具备很大的优点。下一章咱们将介绍微服务中的熔断组件Hystrix。
以就是本期的分享,你还能够关注公众号:** 程序员笑笑生**,关注更多精彩内容!
SpringCloud基础教程(一)-微服务与SpringCloud
SpringCloud基础教程(二)-服务发现 Eureka
SpringCloud基础教程(五)-配置中心热生效和高可用
SpringCloud 基础教程(六)-负载均衡Ribbon
SpringCloud 基础教程(七)-Feign声明式服务调用
更多精彩内容,请期待...
本文由博客一文多发平台 OpenWrite 发布!
个人博客地址兰陵笑笑生,欢迎浏览!