Feign入门实战(完整版)

9 Feign学习

9.1 Feign简介

Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。Feign可帮助我们更加快捷、优雅地调用HTTP API。

在Spring Cloud中,使用Feign非常简单,创建一个接口,并在接口上添加一些注解,代码就完成了。

Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
Spring Cloud 对Feign进行了增强,是Feign支持了SpringMVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。

9.2为服务消费者整合Feign

前面我们使用RestTemplate(通过整合Ribbon实现负载均衡)调用Restful API,下面我们使用Feign,实现声明式的RESTful API调用。

9.2.1 准备项目

复制项目microservice-consumer-movie,修改名字microservice-consumer-movie-feign,将artifactId修改为microservice-consumer-movie-feign

9.2.2 添加Feign的依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
9.2.3 创建一个Feign接口

创建一个Feign接口并添加@FeignClient注解

@FeignClient(name="user-provider")
public interface UserFeignClient {
    @GetMapping("/user/{id}")
    User getById(@PathVariable("id") Integer id);
}

@FeignClient注解中的name属性是一个任意的客户端名称,用于创建Ribbon负载均衡器。

在本例中,由于使用了Eureka,所以Ribbon会把microservice-provider-user解析成Eureka Server服务注册表中的服务。

当然,如果不使用Eureka,可以使用url属性指定请求的URL

9.2.4 修改controller

修改MovieController,让其调用Feign

@RestController
@Slf4j
public class MovieController {
    @Resource
    private UserFeignClient userFeignClient;

    @GetMapping("/user/{id}")
    public User findById(@PathVariable Integer id) {
        return userFeignClient.getById(id);
    }

}
9.2.5 修改启动类

添加@EnableFeignClients注解

@SpringBootApplication
@EnableFeignClients
public class MovieApplication {

    public static void main(String[] args) {
        SpringApplication.run(MovieApplication.class, args);
    }
}
9.2.6 启动测试
先启动注册中心Eureka-server

然后启动两个提供者 microservice-provider-user

java -jar microservice-provider-user-1.0-SNAPSHOT.jar
java -Dserver.port=9999 -jar microservice-provider-user-1.0-SNAPSHOT.jar

注意:服务提供者使用单机注册中心,不是集群

然后启动服务消费者
访问controller 进行测试(microservice-consumer-moive-feign)

可以看到,程序不但实现了声明式的REST APT调用,同时还实现了客户端侧的负载均衡。

9.3 自定义Feign配置

许多场景下,我们需要自定义Feign的配置,例如配置日志级别、定义拦截器等。

Spring cloud允许使用Java代码或者自定义Feign的配置,两者是等价的。

9.3.1 使用java代码自定义Feign的配置

在Spring Cloud中,Feign的默认配置类是FeignClientsConfiguration,该类定义了Feign默认使用的编码器、解码器、所使用的契约等。

Spring Cloud允许通过注解@FeignClient的Configuration属性自定义Feign的配置,自定义的配置优先级比FeignClientsConfiguration的优先级高。

在spring cloud 中,feign默认的契约是SpringMvcContract,因此他可以使用SpringMVC的注解。

下面来自定义Feign的注解,让它使用Feign自带的注解进行工作。

9.3.1.1 准备工作

复制microservice-consumer-movie-feign 成microservice-consumer-movie-feign-custom
修改artifactId 为microservice-consumer-movie-feign-custom

9.3.1.2 edu.xja.config包中加入配置类
/**
 * 该类为Feign的配置类
 * 注意:该类可以不写@Configuration注解,如果加了@configuration注解,那么该类不能放在主应用程序上下文@ComponentScan所扫描的包中
 */
public class FeignConfig {
    /**
     * 将契约改为feign原生的默认契约。这样就可以使用feign自带的注解了。
     * @return 默认的原生契约
     */
    @Bean
    public Contract feignContract(){
        return new Contract.Default();
    }
}
9.3.1.3 修改edu.xja.feign下面的UserFeignClient
@FeignClient(name="user-provider",configuration = FeignConfig.class)
public interface UserFeignClient {
    /**
     * 使用feign自带的注解@RequestLine
     * @param id
     * @return
     */
    @RequestLine("GET /user/{id}")
    User getById(@Param("id") Integer id);
}

类似的,还可以自定义Feign的编码器、解码器、日志打印,甚至为Feign添加拦截器。

启动测试

先启动注册中心
再启动两个用户服务
再启动microservice-consumer-movie-feign-custom
访问movieController测试
9.3.2 使用全局配置

注解@EnableFeignClients为我们提供了defaultConfiguration属性,用来指定默认的配置类。

比如:
@EnableFeignClients(defaultConfiguration=DefaultRibbonConfig.class)

9.3.3 使用属性自定义配置
9.3.3.1 配置指定名称的Feign Client

对于指定名称的Feign Client(本例中Feign Client的名称为feign2),配置如下:

feign:
  client:
    config:
      user-provider:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: full
        encoder: feign.form.spring.SpringFormEncoder
        requestInterceptors:
          - com.example.feign2.interceptor.RequestHeaderInterceptor
9.3.3.1 通用配置(client 是feign下面的,由于markdown导致前面空格丢失)
feign:
client:
 config:
   default:
     connectTimeout: 5000
     readTimeout: 5000
     loggerLevel: full
     encoder: feign.form.spring.SpringFormEncoder
     requestInterceptors:
       - com.example.feign2.interceptor.RequestHeaderInterceptor

属性配置的方式比java代码配置方式优先级高。

9.5 Feign对压缩的支持

在一些场景下,可能需要对请求和响应进行压缩,此时可使用以下属性启用Feign的压缩功能。

feign.compression.request.enabled=true
feign.compression.response.enabled=true

如果写在yml文件也可以,idea有自动提示

9.6 Feign日志

在很多场景下,需要了解Feign处理请求的具体细节,那么如何满足这种需求呢?

Feign对日志的处理非常灵活,可为每个Feign客户端指定日志记录策略,每个Feign客户端都会创建一个logger。默认情况下,logger的名称是Feign接口的完整类名。需要注意的是,Feign的日志打印只会对DEBUG级别做出响应。

我们可以每个Feign客户端配置各自的Logger.Level对象,告诉Feign记录哪些日志。Logger.Level的值有以下选择:

NONE: 不记录任何日志(默认值)
BASIC: 仅记录请求方法、URL、响应状态代码以及执行时间。
HEADERS: 记录basic级别的基础上,记录请求和响应的header。
FULL: 记录请求和响应的header、body和元数据。

9.6.1 使用编码方式设置日志级别

复制工程microservice-consumer-movie-feign到microservice-consumer-movie-feign-log

编写Feign配置类

// 如果在主启动类下,改配置注解@Configuration可以注释
@Configuration
public class FeignLogConfiguration {
  @Bean
  Logger.Level feignLoggerLevel() {
    return Logger.Level.BASIC;
  }
}

注意把config放到扫描范围的外面

疑问:如果放到扫描范围内,加@Configuration和不加的区别

我的理解是,feign 也会扫描配置文件,

修改Feign接口,指定配置类

@FeignClient(name = “user-provider", configuration = FeignLogConfiguration.class)
public interface UserFeignClient {
  @RequestMapping(value = "/{id}", method = RequestMethod.GET)
  public User findById(@PathVariable("id") Long id);
}

修改application.yml,指定Feign接口的日志级别为DEBUG

logging:
  level:
    edu.xja.feign.UserClientFeign: DEBUG # 将Feign接口的日志级别设置成DEBUG,因为Feign的Logger.Level只对DEBUG作出响应。

启动测试

9.6.2 使用属性配置日志级别
feign:
 client:
   config:
     user-provider:
         loggerLevel: headers

logging:
 level:
   edu.xja.feign.UserClientFeign: DEBUG # 将Feign接口的日志级别设置成DEBUG,因为Feign的Logger.Level只对DEBUG作出响应。

9.7 使用Feign构造多参数请求

之前的示例我们的请求的参数只有一个,那么Feign如何构造多参数请求呢?

9.7.1 GET请求多参数的URL

假设url中包含多个参数,比如http://user-provider/user/get?ID=1&username=zhangsan

用户服务提供端

UserDao加入方法:

/**
 * 根据用户名和年龄获取用户
 * @param username
 * @param age
 * @return
 */
User getByUsernameAndAge(String username,Integer age);

User.xml 加入

<select id="getByUsernameAndAge" resultType="User">
    select
      id,username, age, name,balance
    from t_user
    where username = #{username} and age=#{age}
</select>

UserService和UserServiceImpl 分别加入方法,自己加入

UserController 中加入方法

@GetMapping("/getByUsernameAndAge")
public User getByUsernameAndAge(User user) {
    return userService.getByUsernameAndAge(user.getUsername(),user.getAge());
}

修改microservice-consumer-movie-feign工程中的UserClientFeign类,加入下面代码

错误写法(requestBody只能是post方法)

@GetMapping("/user/getByUsernameAndAge")
User getByUsernameAndAge(@RequestBody User user);

MovieController中加入方法用于测试

@GetMapping("/getByUsernameAndAge")
public  User getByUsernameAndAge(){
    User user=new User();
    user.setUsername("zhaoliu");
    user.setAge(20);
    return userClientFeign.getByUsernameAndAge(user);
}

启动相关服务测试

启动注册中心eureka-server

启动服务提供者 microservice-provider-user

启动服务消费者 microservice-consumer-movie-feign

浏览器器访问: 进行测试

正确写法:

  • get方式参数注解只有:@PathVariable和@RequestParam
  • post方式参数注解只有:@RequestBody,如果不写,默认这一个,服务提供者必须也是@RequestBody,不然接收不到参数
  • 如果其他方式,可以自定义,比如文件上传

方法一:

@GetMapping("/user/getByUsernameAndAge")
User getByUsernameAndAge1(@RequestParam("username") String username,@RequestParam("age") int age);
@GetMapping("/getByUsernameAndAge1")
public  User getByUsernameAndAge1(){
    return userClientFeign.getByUsernameAndAge1("zhaoliu",20);
}

方法二:

多参数的URL也可以使用Map构建。当目标url参数非常多时,可以使用这种方式简化Feign接口的编写。

@GetMapping("/user/getByUsernameAndAge")
User getByUsernameAndAge2(@RequestParam Map<String,Object> userMap);
@GetMapping("/getByUsernameAndAge2")
public  User getByUsernameAndAge2(){
    Map<String,Object> map=new HashMap<>();
    map.put("username","zhaoliu");
    map.put("age",20);
    return userClientFeign.getByUsernameAndAge2(map);
}
9.7.2 POST请求包含多个参数
@PostMapping("/user/add")
int addUser(@RequestBody User user);

Controller里加入

@PostMapping("/add")
public int getByUsernameAndAge2(@RequestBody User user){
    return userClientFeign.addUser(user);
}

再次强调,被调用方,也就是服务提供者,入参也是被@RequestBody修饰

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值