SpringCloud实战之Feign声明式服务调用

时间:2022-08-26 18:23:18

在前面的文章中可以发现当我们通过resttemplate调用其它服务的api时,所需要的参数须在请求的url中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。

那么有没有更好的解决方案呢?答案是确定的有,netflix已经为我们提供了一个框架:feign。

feign是一个声明式的web service客户端,它的目的就是让web service调用更加简单。feign提供了http请求的模板,通过编写简单的接口和插入注解,就可以定义好http请求的参数、格式、地址等信息。

而feign则会完全代理http请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。feign整合了ribbon和hystrix(关于hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。

总起来说,feign具有如下特性:

  1. 可插拔的注解支持,包括feign注解和jax-rs注解;
  2. 支持可插拔的http编码器和解码器;
  3. 支持hystrix和它的fallback;
  4. 支持ribbon的负载均衡;
  5. 支持http请求和响应的压缩。

这看起来有点像我们springmvc模式的controller层的requestmapping映射。这种模式是我们非常喜欢的。feign是用@feignclient来映射服务的。

首先第一步,在原来的基础上新建一个feign模块,接着引入相关依赖,引入feign依赖,会自动引入hystrix依赖的,如下:

?
1
2
3
4
5
6
7
8
9
10
11
<dependency>
  <groupid>org.springframework.cloud</groupid>
  <artifactid>spring-cloud-starter-eureka</artifactid>
  <version>1.3.5.release</version>
</dependency>
 
<dependency>
  <groupid>org.springframework.cloud</groupid>
  <artifactid>spring-cloud-starter-feign</artifactid>
  <version>1.4.0.release</version>
</dependency>

application.yml配置如下:

?
1
2
3
4
5
6
7
8
9
server:
 port: 8083
spring:
 application:
  name: feign-consumer
eureka:
 client:
  service-url:
   defaultzone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

接着在前面文章中的的的两个provider1和provider2两个模块的服务新增几个方法,如下代码所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
 * created by cong on 2018/5/8.
 */
@restcontroller
public class hellocontroller {
 
  @requestmapping("/hello")
  public string hello(){
    system.out.println("访问来1了......");
    return "hello1";
  }
 
  @requestmapping("/hjcs")
  public list<string> laowangs(string ids){
    list<string> list = new arraylist<>();
    list.add("laowang1");
    list.add("laowang2");
    list.add("laowang3");
    return list;
  }
 
  //新增的方法
  @requestmapping(value = "/hellol", method= requestmethod.get)
  public string hello(@requestparam string name) {
    return "hello " + name;
  }
 
  @requestmapping(value = "/hello2", method= requestmethod.get)
  public user hello(@requestheader string name, @requestheader integer age) {
    return new user(name, age);
  }
 
  @requestmapping(value = "/hello3", method = requestmethod.post)
  public string hello (@requestbody user user) {
    return "hello "+ user. getname () + ", " + user. getage ();
  }
 
}

接着是上面代码所需用到的user类,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * created by cong 2017/12/2.
 */
public class user {
 
  private string name;
  private integer age;
 
  //序列化传输的时候必须要有空构造方法,不然会出错
  public user() {
  }
  public user(string name, integer age) {
    this.name = name;
    this.age = age;
  }
 
  public string getname() {
    return name;
  }
 
  public void setname(string name) {
    this.name = name;
  }
 
  public integer getage() {
    return age;
  }
 
  public void setage(integer age) {
    this.age = age;
  }
}

接下来用feign的@feignclient(“服务名称”)映射服务调用。代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package hjc;
 
import org.springframework.cloud.netflix.feign.feignclient;
import org.springframework.web.bind.annotation.*;
 
/**
 * created by cong on 2018/5/17.
 */
//configuration = xxx.class 这个类配置hystrix的一些精确属性
//value=“你用到的服务名称”
 
@feignclient(value = "hello-service",fallback = feignfallback.class)
public interface feignservice {
  //服务中方法的映射路径
  @requestmapping("/hello")
  string hello();
 
  @requestmapping(value = "/hellol", method= requestmethod.get)
  string hello(@requestparam("name") string name) ;
 
  @requestmapping(value = "/hello2", method= requestmethod.get)
  user hello(@requestheader("name") string name, @requestheader("age") integer age);
 
  @requestmapping(value = "/hello3", method= requestmethod.post)
  string hello(@requestbody user user);
}

接着在controller层注入feiservice这个接口,进行远程服务调用,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * created by cong on 2018/5/17.
 */
@restcontroller
public class consumercontroller {
 
  @autowired
  feignservice feignservice;
 
  @requestmapping("/consumer")
  public string helloconsumer(){
    return feignservice.hello();
  }
 
  @requestmapping("/consumer2")
  public string helloconsumer2(){
    string r1 = feignservice.hello("hjc");
    string r2 = feignservice.hello("hjc", 23).tostring();
    string r3 = feignservice.hello(new user("hjc", 23));
    return r1 + "-----" + r2 + "----" + r3;
  }
 
}

接着在feign模块的启动类哪里打上eureka客户端的注解@enablediscoveryclient  feign客户端的注解

?
1
2
3
4
5
6
7
8
9
10
11
@enablefeignclients,代码如下:
 
@springbootapplication
@enablediscoveryclient
@enablefeignclients
public class feignapplication {
 
  public static void main(string[] args) {
    springapplication.run(feignapplication.class, args);
  }
}

接着启动启动类,浏览器上输入localhost:8083/consumer  运行结果如下:

SpringCloud实战之Feign声明式服务调用

SpringCloud实战之Feign声明式服务调用

可以看到负载均衡轮询出现hello1,hello2。

接着继续在浏览器上输入localhost:8083/consumer2,运行结果如下:

SpringCloud实战之Feign声明式服务调用

接下来我们进行feign声明式调用服务下的,服务降级的使用,那么我们就必须新建一个feignfallback类来继承feiservice,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package hjc;
 
import org.springframework.stereotype.component;
 
/**
 * created by cong on 2018/5/17.
 */
@component
public class feignfallback implements feignservice{
  //实现的方法是服务调用的降级方法
  @override
  public string hello() {
    return "error";
  }
 
  @override
  public string hello(string name) {
    return "error";
  }
 
  @override
  public user hello(string name, integer age) {
    return new user();
  }
 
  @override
  public string hello(user user) {
    return "error";
  }
}

接着我们再把那两个服务提供模块provider1,provider2模块进行停止,运行结果如下所示:

SpringCloud实战之Feign声明式服务调用

可以看到我们这几个调用,都进行了服务降级了。

那么如果我们想精确的控制一下hystrix的参数也是可以的,比方说跟hystrix结合的参数,那么可以在feignclient注解里面配置一个configuration=xxx类.class属性,在哪个类里面精确的指定一下属性。

或者在application.yml里面配置,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hystrix:
 command:
  default:
   execution:
    isolation:
     thread:
      timeoutinmilliseconds: 5000
 
ribbon:
 connecttimeout: 500
 
 
#如果想对单独的某个服务进行详细配置,如下
hello-service:
 ribbon:
  connecttimeout: 500

这里满足了我们大部分场景的调用,但是有写精细场景,还是要用原生的hystrix,跟我们之前的hystrix用法一下,不要走feign客户端调用就行了,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * created by cong on 2018/5/17.
 */
public class hjccommand extends hystrixcommand {
  protected hjccommand(hystrixcommandgroupkey group) {
    super(group);
  }
 
  @override
  protected object run() throws exception {
    return null;
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://www.cnblogs.com/*ncong/p/9053576.html