五、Feign详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/makyan/article/details/88641656

4.1. Feign是什么?

Feign是在RestTemplate基础上封装的,使用注解和接口来定义服务提供者以及服务提供者的接口,url风格是Rest。
简单点说,Feign 仅仅使用注解@FeignClient和接口(interface),就能定义依赖服务的接口,代替了RestTemplate的功能。

在上面讲解的Spring Cloud Ribbon中,服务消费者访问服务提供者,都是通过RestTemplate来对服务提供者的接口进行访问,
而RestTemplate已经实现了对HTTP请求的封装处理,形成了一套模版化的调用方法。在之前的例子中,
我们只是简单介绍了RestTemplate调用,但是在实际开发中,由于对服务依赖对调用可能不止于一处,
往往一个接口会被多处调用,所以我们通常都会针对各个微服务自行封装一些客户端来包装这些依赖服务的调用。
这个时候我们会发现,由于RestTemplate的封装,几乎每一个调用都是简单的模版化内容。

  1. Feign是什么?Feign是一个声明式的Rest 客户端,即它是在eureka的客户端使用的,url风格是Rest。
  2. Fegin在RestTemplate基础上做了进一步封装,由它来帮助我们定义和实现依赖服务接口的定义。
  3. 在Feign的实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。
    简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。
  4. Spring Cloud Feign具备可插拔的注解支持,包括Feign注解和JAX-RS注解。
    同时,为了适应Spring的广大用户,它在Netflix Feign的基础上扩展了对Spring MVC的注解支持。
  5. 另外,对于Feign自身的一些主要组件,比如编码器和解码器等,它也以可插拔的方式提供,在有需求等时候我们以方便扩张和替换它们。

4.2. Feign的基本使用

1、创建futurecloud-feign项目,添加Feign依赖


 <!--添加Feign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.0.2.RELEASE</version>
</dependency>

2、在主函数上添加@EnableFeignClient,启动Feign


@SpringBootApplication
@EnableEurekaClient //声明为eureka 客户端
@EnableFeignClients //启动Feign
public class FuturecloudFeignApplication
{
    @Bean  //相当于xml中的bean标签,主要是用于调用当前方法获取到指定对象
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
    public static void main( String[] args )
    {

        SpringApplication.run(FuturecloudFeignApplication.class,args);
    }
}

3、定义一个接口,指定依赖的服务,在接口中写依赖服务的接口


package com.futurecloud.feign;

import com.futurecloud.bean.User;
import feign.Param;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("futurecloud-user")   //通过注解指定依赖服务
public interface FeignInterface {

    /**
     * 1. 关于Feign中,GetMapping 和RequestMapping的使用问题
     * C版本的spring是不能写GetMapping的,必须用RequestMapping
     * 注意:必须添加@PathVariable("id") 注解
     */

    @GetMapping("/user/{id}")
    User getUser(@PathVariable("id") Long id);

    /**
     *2. 关于Feign中,传递参数的问题
     * 如果传递的是复杂参数,那么Feign不管你配置的是Get请求,都会议post方式发送请求。
     * 所以如果使用复杂参数(如对象),服务提供者也必须是post方式,服务消费者才可以正常访问。
     * 如果服务提供者必须使用get方式,那传递多个参数时,只能以普通方式传递。
     * @param user
     * @return
     */
    @GetMapping("/getObject")
    User getObject(User user);

    /**
     * 3. 关于注解RequestLine的使用
     * 注意:使用RequestLine的时候,参数必须使用Param注解
     * @param id
     * @return
     */
    @RequestLine("GET /find/user/{id}")
    User findUser(@Param("id") Long id);
}

4、在Feign的接口中定义依赖服务的接口时,需要注意的问题:


(1)关于Feign中,GetMapping 和RequestMapping的使用问题
Spring Cloud在Finchley版本以前,是不能写GetMapping的,必须用RequestMapping
(2)如果使用到@PathVariable ,必须指定其value
(3)关于Feign中,传递参数的问题
如果传递的是复杂参数,那么Feign不管你配置的是Get请求,都会以post方式发送请求。
所以如果使用复杂参数(如对象),服务提供者也必须是post方式,服务消费者才可以正常访问。
如果服务提供者必须使用get方式,那传递多个参数时,只能以普通方式传递。
(4)关于注解RequestLine的使用,@RequestLine是Feign的注解,使用RequestLine的时候,参数必须使用Param注解


4.3. Feign的自定义配置


  1. 自定义一个Feign 的Class配置文件

package com.futurecloud.custom;

import feign.Contract;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 类名不能跟注解名称相同
 * 方法不能在启动类所在的目录,否则会被@ComponentScan注解扫描到,引起冲突
 */
@Configuration
public class FeignCustomConfig {
    /**
     * 修改feign的配置:使用feign.Contract代替SpringMvcContract
     * 这将SpringMvc Contract 替换为feign.Contract.Default
     * 即将请求的注解RequestMapping替换成RequestLine
     * 注意:重写了这个配置,Feign中的接口访问方式必须使用@RequestLine
     * 不重写这个配置,Feign中的接口访问方式不能使用@RequestLine,
     * 否则就会报,没有定义HTTP的访问方式(GET,POST)
     * @return
     */
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

    /**
     * 修改feign的配置:配置访问eureka的用户名、密码
     * 如果Eureka添加了安全验证,则需要配置下面的用户名、密码.
     * feign才能正常访问eureka中的相关信息
     * @return
     */
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("user", "123");
    }

    /**
     * 设置日志
     * 对应的在yml配置文件中设置日志级别
     * @return
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        //设置日志
        return Logger.Level.FULL;
    }
}

  1. 修改Feign的接口,让Feign 使用自定义的配置文件

package com.futurecloud.feign.interfaces;

import com.futurecloud.custom.FeignCustomConfig;
import com.futurecloud.feign.bean.User;
import feign.Param;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
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.RequestMethod;

//指定自定义Feign配置FeignCustomConfig
@FeignClient(name = "futurecloud-user",configuration = FeignCustomConfig.class)   //通过注解指定依赖服务
public interface CustomFeignClient {

    /**
     * 1. 关于Feign中,GetMapping 和RequestMapping的使用问题
     *  Spring Cloud在C版本以前,是不能写GetMapping的,必须用RequestMapping。
     *  请求参数必须写在请求路径中
     * 注意:必须添加@PathVariable("id") 注解
     */

    @RequestLine("GET /user/{id}")  //@RequestLine:是feign的注解
   // @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
    User getUserById(@PathVariable("id") Long id);

    /**
     *2. 关于Feign中,传递参数的问题
     * 如果传递的是复杂参数,那么Feign不管你配置的是Get请求,都会议post方式发送请求。
     * 所以如果使用复杂参数(如对象),服务提供者也必须是post方式,服务消费者才可以正常访问。
     * 如果服务提供者必须使用get方式,那传递多个参数时,只能以普通方式传递。
     * @param id
     * @return
     */
    @RequestLine("GET /getUser/{id}") //@RequestLine:是feign的注解
    //@GetMapping("/getUser/{id}")
    User getUser(@PathVariable("id") Long id);

    /**
     * 3. 关于注解RequestLine的使用
     * 注意:使用RequestLine的时候,参数必须使用Param注解
     * 使用RequestLine注解的时候,请求方式GET或POST必须大写,后面是空格
     * @param id
     * @return
     */
    @RequestLine("POST /find/user/{id}") //@RequestLine:是feign的注解
   // @RequestMapping(value = "/find/user/{id}",method = RequestMethod.POST)
    User findUserById(@Param("id") Long id);
}

  1. application.yml配置文件

server:
  port: 8905
spring:
  application:
    name: futurecloud-feign-custom
#将此服务注册到eureka 服务上
eureka:
  client:
    serviceUrl:
      defaultZone: http://user:123@localhost:10000/eureka
  instance:
    prefer-ip-address: true  #将注册到eureka服务的实例使用ip地址

#Feign日志的配置
logging:
  level:
    com.futurecloud.feign.interfaces.CustomFeignClient: DEBUG

4.4. 用依赖服务的url代替Feign的接口中的name指定的服务名


在上面的Feign配置中,我们使用name指定了所依赖的服务


@FeignClient(name = "futurecloud-user",configuration = FeignCustomConfig.class) 

我们还可以使用url来制定依赖服务的服务提供者url,不使用name


@FeignClient(url = "http://localhost:10001",configuration = FeignCustomConfig.class)   //通过注解指定依赖服务

猜你喜欢

转载自blog.csdn.net/makyan/article/details/88641656