五、利用Feign实现声明试Rest调用

6 篇文章 0 订阅
5 篇文章 0 订阅

五、利用Feign实现声明试Rest调用

1、前景回顾

还记得我在《基于Ribbon实现负载均衡》里面的服务调用吗?如下:(例举其中一种)

/**
 * getForEntity方式一
 * @param userName
 * @param pwd
 * @param address
 * @return
 */
public Domain getDomain12(String userName, String pwd, String address)
{
    String url="http://app-8801/domain/get003?userName={0}&pwd={1}&address={2}";
    ResponseEntity<Domain> responseEntity=restTemplate.getForEntity(url,Domain.class,userName,pwd,address);
    return responseEntity.getBody();
}

我是通过注入RestTemplate实现服务的调用的。我是通过拼接字符串的方式构造Url的,例子中只有3个参数,感觉就有点受不了,现实环境中URL中有十几个参数的,那么这种方式就变得非常繁琐、低效了,代码也难以维护。Feign为我们解决了这问题。

2、Feign 简介

Feign是Netflix开发声明式、模板化的http客户端。Feign可以帮我们非常快速便捷、优雅的调用HTTP API。

在Springcloud中,Feign只要创建多个接口(其实就是服务调用),并在接口上添加一些注解,就可以实现服务调用了。Feign支持多种注解,Feign自带的注解和JAX-RS注解等。重要的是,SpringCloud对Feign进行了增强,试的Feign支持SpringMVC的注解,并整合了Eureka 与Ribbon,使我们在开发中更加便捷。

3、Feign实现APP2-8901 对 APP-8801的调用

我们只需要对调用方进行修改。

  • 1.首先我们需要在App2 项目的pom.xml中引入Feign:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>
    

并在启动类上面添加@EnableFeignClients 注解,启用Feign。

  • 2.创建Feign 接口

        /**
         * @Author: pangfei
         * @description:此处取代了 restTemplate方式的服务调用,采用基于Feign的模板化服务调用方式
         * 每个服务可以设置单独的调用接口
         * Feign 具有重构的特性,我们可以将每个服务提供的服务,抽象成一个接口,然后提供api jar 供 服务提供方和服务消费方来实现。
         * 及利用SpringCloud Feign 的继承的特性来实现rest接口的定义。
         * 此处由于只是demo,并未以rest 接口的形式去实现,如后期服务较多,可以尝试以rest接口的形式实现。可以进一步减少代码量的开发。
         * 其中也有一定的缺陷:服务本身会依赖,api jar的接口,api接口的变动,会影响到服务本身。因此后期运营此方式,会有牵一发动全身的后果,
         * 所以要尽量做好前后版本的兼容。
         * fallback 是基于feign的服务降级
         * @Date: Create in 14:40 2018/1/15
         */
        @FeignClient(name = "app-8801",fallback = ServiceFallback.class)
        public interface  App8801Feign {
            @GetMapping("/domain/get001/{id}")
            public Domain getDomain001(@PathVariable("id")@CacheKey("id") String id);
            @GetMapping("/domain/get002/{id}")
            public Domain getDomain002(@PathVariable("id") String id);
            //多参数调用 可以是两种
            @GetMapping("/domain/get003")
            public Domain getDomain003(@RequestParam("userName") String userName,@RequestParam("pwd")String pwd,@RequestParam("address")String address);
            @GetMapping("/domain/get004")
            public Domain getDomain004(@RequestParam Map<String,Object> map);
            @PostMapping("/domain/post001")
            public Domain postDomain001(@RequestBody Domain domain);
            @PostMapping("/domain/post002")
            public Domain postDomain002(@RequestBody Domain domain);
    
        }
    

通过代码,我们发现,其跟我们平时写的接口多了一个注解 @FeignClient(name = "app-8801",fallback = ServiceFallback.class) 和每个方法中出现Springmvc的注解。

其中 @FeignClient 中的name 就是需要调用的服务名称,因为与Eureka 和ribbon 整合,所以ribbon 会吧app-8801解析成Eureka 注册表中的服务。如果不想用Eureka 可以参考《基于Ribbon实现负载均衡》中脱离Eureka 使用ribbon。 @FeignClient 还可以指定URL属性 例如@FeignClient(name="app-8801",url="localhost:8801/")

在SpringMVC中类似@RequestParam("userName")、@RequestHeader("userName") 中的username 有时候是可以省略的,但在Feign接口中,不可省略,不然会抛出非法参数异常。 对于post方法中的Domain 类,其类中必须要有默认构造函数,不然Springcloud Feign 根据JSON 字符串转换Domain会抛出异常。

大家发现注解中有一个 fallback = ServiceFallback.class ,这是下一节 Hystrix 容错我会讲到的服务降级,这里是Feign 对Hystrix 服务降级的支持。

3.创建service层(非必须,个人行为)

我在controller与服务调用 中间增加一层Service层,不见直接调用也可以。 代码如下:

/**
 * @Author: pangfei
 * @description:
 * @Date: Create in 15:39 2018/1/16
 */
@Service("feignService")
public class FeignServiceImpl{
    final  Logger LOGGER= LoggerFactory.getLogger(FeignServiceImpl.class);
    final  Logger SERVICECAllLOGGER= LoggerFactory.getLogger("logstash");

    @Value("${spring.application.name}")
    private String appName;
    @Autowired
    private App8801Feign app8801Feign;//注入Feign接口

    public Domain getDomain01( String id)
    {
        LOGGER.info(appName+"--执行getDomian001操作");
        return app8801Feign.getDomain001(id);   //服务调用
    }
    public Domain getDomain02(String id)
    {
        return app8801Feign.getDomain002(id);    //服务调用
    }
    public Domain getDomain03(String userName, String pwd, String address)
    {
        return app8801Feign.getDomain003(userName,pwd,address);    //服务调用
    }
    public Domain getDomain04(String userName, String pwd, String address)
    {
        Map<String,Object> map=new HashMap<>();
        map.put("userName",userName);
        map.put("pwd",pwd);
        map.put("address",address);
        return app8801Feign.getDomain004(map);    //服务调用
    }
    public Domain postDomain001(Domain domain){
        return app8801Feign.postDomain001(domain);    //服务调用
    }
    public Domain postDomain002(Domain domain){
        return  app8801Feign.postDomain002(domain);    //服务调用
    }
}

代码中包含get与post类型调用。

4.创建Controller 进行调用service层

/**
 * @Author: pangfei
 * @description:
 * @Date: Create in 11:27 2018/1/15
 */
@RestController
public class DemoController {

  @Autowired
  FeignServiceImpl feignService;

  /**
   *以feign方式的调用
   */
    @GetMapping("/get001/{id}")
    public Domain getDomain01(@PathVariable("id") String id)
    {
        return feignService.getDomain01(id);  //service层服务调用
    }
    @GetMapping("/get002/{id}")
    public Domain getDomain02(@PathVariable("id") String id)
    {
      return feignService.getDomain02(id);//service层服务调用
    }

    @GetMapping("/get003")
    public Domain getDomain03(String userName, String pwd, String address)
    {
      return feignService.getDomain03(userName,pwd,address);//service层服务调用
    }

    @GetMapping("/get004")
    public Domain getDomain04(String userName, String pwd, String address)
    {
      return feignService.getDomain04(userName,pwd,address);//service层服务调用
    }

    @PostMapping("/post001")
    public Domain postDomain001(@RequestBody Domain domain){
      return feignService.postDomain001(domain);//service层服务调用
    }

    @PostMapping("/post002")
    public Domain postDomain002(@RequestBody Domain domain){
          return  feignService.postDomain002(domain);
    }
}

启动app2应用,执行 http://localhost:8901/get001/11 会得到如下

发起调用请求:

两个app-8801 打印出来的 

我们发现已经成功请求,并且实现了负载均衡。

大家注意我打印的信息:

app-8801--执行getDomian011操作  traceId=11ddc0da579a038a, spandId=2e798e6e1068b865, 
parantSpandId=11ddc0da579a038a, spanName=http:/domain/get001/11

后面我讲到《基于Sleuth的服务跟踪的实现》时,我向大家介绍。

4、请求压缩与日志配置

SpringCloud Feign 支持对请求与响应进行GZIP压缩,以减少通信过程中的性能损耗。 下面是开启压缩的配置:

feign.compression.request.enabled=true  #feign对压缩的支持
feign.compression.response.enabled=true #feign对压缩的支持
feign.compression.request.min-request-size=2048  #用于设置请求的最小阈值
feign.compression.request.mime-types=text/xml,application/xml,application/json #用于设置支持的媒体类型 
logging.level.com.example.app2.feign.App8801Feign=DEBUG  #将对 App8801Feign 的feign的客户端日志级别设置为只对DEBUG做出相应 

至此,对feign的基本使用已经结束, 后面我们还会碰到feign 与其他组件的配置使用,比如Hystrix与Sleuth。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值