最近整理一下微服务的文章,先拿一直用的openfeign开刀
思考:微服务之间如何方便优雅的实现服务间的远程调用
一、说说openfeign是什么吧
说到这个,那不得不先说说rpc
1.什么是rpc
rpc 全称是 remote procedure call ,即远程过程调用,其对应的是我们的本地调用。rpc 的目的是:让我们调用远程方法像调用本地方法一样。
//本地调用 r result = orderservice.findorderbyuserid(id); //rpc远程调用 orderservice为代理对象 r result = orderservice.findorderbyuserid(id);
rpc框架设计架构
2. 什么是feign
feign是netflix开发的声明式、模板化的http客户端,feign可帮助我们更加便捷、优雅地调用http api。
feign可以做到使用 http 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 http 请求。它像 dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 http client 构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。
spring cloud openfeign对feign进行了增强,使其支持spring mvc注解,另外还整合了ribbon和eureka,从而使得feign的使用更加方便。
2.1 openfeign和feign的区别
feign
feign是springcloud组件中的一个轻量级restful的http服务客户端,feign内置了ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。feign的使用方式是:使用feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
openfeign
openfeign是springcloud在feign的基础上支持了springmvc的注解,如@requestmapping等。openfeign的@feignclient可以解析springmvc的@requestmapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
2.2 ribbon&feign对比
ribbon+resttemplate进行微服务调用
@bean @loadbalanced public resttemplate resttemplate() { return new resttemplate(); } //调用方式 string url = "http://mall-order/order/findorderbyuserid/"+id; r result = resttemplate.getforobject(url,r.class);
feign进行微服务调用
@feignclient(value = "mall-order",path = "/order") public interface orderfeignservice { @requestmapping("/findorderbyuserid/{userid}") public r findorderbyuserid(@pathvariable("userid") integer userid); } //调用 @autowired orderfeignservice orderfeignservice; //feign调用 r result = orderfeignservice.findorderbyuserid(id);
2.3 feign的设计架构
二、spring cloud alibaba快速整合feign
下面是springboot集成openfeign demo,完全照着来妥妥的没问题
服务提供者我就不写了,这就是正常的controller,主要是调用者这块,接下来写的也是这个
1.在pom.xml文件中添加以下依赖
<dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-openfeign</artifactid> </dependency>
2.调用端添加启动注解 @enablefeignclients
@enableasync @springbootapplication(exclude = { datasourceautoconfiguration.class, druiddatasourceautoconfigure.class }) @enablediscoveryclient @enablefeignclients //扫描和注册feign客户端的beandefinition @mapperscan("com.**.**.**.**.mapper") public class application { public static void main(string[] args) { springapplication.run(application.class, args); } }
3.编写调用接口+@feignclient注解
创建一个feignclient接口,用于定义要调用的远程服务的方法:
@feignclient(value = "base-application", path = "/base") @requestmapping("/api/testdemo") public interface openfeignbasedemo { @postmapping("/querylist") string querylist(@requestbody jsonobject jsonobject); }
在上面的代码中,我们使用@feignclient注解指定了要调用的远程服务的名称。然后,我们定义了一个名为querylist的方法,并使用@postmapping注解指定了要调用的远程服务的api路径。
4.发起调用,像调用本地方式一样调用远程服务
在其他类中使用openfeignbasedemo 来调用远程服务的方法
@restcontroller @requestmapping("/openfeigndemo") public class openfeigncontrollerdemo { @autowired private openfeignbasedemo openfeignbase; @postmapping(value = "/test", produces = { "application/json;charset=utf-8" }) public responseentity test(@requestbody jsonobject jsonobject) { //feign调用 string res = openfeignbase.querylist(jsonobject); return new responseentity(res, httpstatus.ok); } }
5.结果预览
启动两个工程,postmain调用 请求url :localhost:8088/server/openfeigndemo/test。
6.这里我必须强调一下第3步这个参数设置的含义
public @interface feignclient { @aliasfor("name") string value() default ""; string contextid() default ""; @aliasfor("value") string name() default ""; string qualifier() default ""; string url() default ""; boolean decode404() default false; class<?>[] configuration() default {}; class<?> fallback() default void.class; class<?> fallbackfactory() default void.class; string path() default ""; boolean primary() default true; }
下面就对各个属性进行分析
1.value、name
value和name的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。
2.contextid
我们不想将所有的调用接口都定义在一个类中,有一种解决方案就是为每个client手动指定不同的contextid,这样就不会冲突了。
3.url
url用于配置指定服务的地址,相当于直接请求这个服务,不经过ribbon的服务选择。像调试等场景可以使用。
4.decode404
当调用请求发生404错误时,decode404的值为true,那么会执行decoder解码,否则抛出异常。
5.configuration
configuration是配置feign配置类,在配置类中可以自定义feign的encoder、decoder、loglevel、contract等。
6.fallback
定义容错的处理类,也就是回退逻辑,fallback的类必须实现feign client的接口,无法知道熔断的异常信息。
7.fallbackfactory
也是容错的处理,可以知道熔断的异常信息。
8.path
path定义当前feignclient访问接口时的统一前缀,比如接口地址是/user/get, 如果你定义了前缀是user, 那么具体方法上的路径就只需要写/get 即可。
9.primary
primary对应的是@primary注解,默认为true,官方这样设置也是有原因的。当我们的feign实现了fallback后,也就意味着feign client有多个相同的bean在spring容器中,当我们在使用@autowired进行注入的时候,不知道注入哪个,所以我们需要设置一个优先级高的,@primary注解就是干这件事情的。
10.qualifier
qualifier对应的是@qualifier注解,使用场景跟上面的primary关系很淡,一般场景直接@autowired直接注入就可以了。
7.报错解决
如果遇到这样的错误:feign.retryableexception: read timed out executing post
可以做如下处理:yaml配置
feign: client: config: default: connecttimeout: 1000 readtimeout: 6000
或者propertis配置
feign.client.config.default.connect-timeout=20000 feign.client.config.default.read-timeout=20000
到此这篇关于springboot集成openfeign demo详解的文章就介绍到这了,更多相关springboot集成openfeign内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论