Spring Cloud微服务解决方案④:Feign的使用

Feign是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign.

demo下载地址:https://download.csdn.net/download/qq_22075041/10851487在microservice-consumer-movie-feign模块里面。

首先我们需要在pom上加Feign的依赖

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

在启动类上加一个注解@EnableFeignClients申明一下

然后就是关于服务调用了 如下:

package com.itmuch.cloud.feign;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.itmuch.cloud.entity.User;
//加一个注解,"microservice-provider-user"是服务的虚拟IP
@FeignClient("microservice-provider-user")
public interface UserFeignClient {
  @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
  public User findById(@PathVariable("id") Long id); // 两个坑:1. @GetMapping不支持   2. @PathVariable得设置value

  @RequestMapping(value = "/user", method = RequestMethod.POST)
  public User postUser(@RequestBody User user);

  // 该请求不会成功,只要参数是复杂对象,即使指定了是GET方法,feign依然会以POST方法进行发送请求。可能是我没找到相应的注解或使用方法错误。
  @RequestMapping(value = "/get-user", method = RequestMethod.GET)
  public User getUser(User user);
}

以上就是一个feign的简单使用。注意他有几个坑点。

下面我要自定义feign配置 怎么做呢,源代码对应microservice-consumer-movie-feign-customizing模块。

package com.itmuch.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import feign.Contract;
import feign.Logger;

@Configuration
public class Configuration1 {
  @Bean
  public Contract feignContract() {
    return new feign.Contract.Default();
  }

  @Bean
  Logger.Level feignLoggerLevel() {
    return Logger.Level.FULL;//控制台会输出debug日志
  }
}

以上的代码 我们自定义了feign的Contract实现为fengin的默认实现,还有日志级别(还需要在配置文件中加如下一行代码)

//com.itmuch.cloud.feign.UserFeignClient类的日志为debug
logging: level: com.itmuch.cloud.feign.UserFeignClient: DEBUG

注意上一篇文章讲到的警告@Configuration注解不能放在@ComponentScan、@SpringBootApplication包以及子包下得问题,此处依然会存在,解决方案请看上一篇。

然后在UserFeignClient类上面的@FeignClient注解加一个属性 configuration = Configuration1.class。

package com.itmuch.cloud.feign;

import org.springframework.cloud.netflix.feign.FeignClient;

import com.itmuch.cloud.entity.User;
import com.itmuch.config.Configuration1;

import feign.Param;
import feign.RequestLine;

@FeignClient(name = "microservice-provider-user", configuration = Configuration1.class)
public interface UserFeignClient {
  //Configuration1类定义了feign的默认实现,他默认实现就是这么写的 下面俩行代码
  @RequestLine("GET /simple/{id}")
  public User findById(@Param("id") Long id);
}

以上就实现了feign的自定义配置。官方说的@FeignClient就是一个子容器(就像是Spring和SpringMVC容器的关系),当然里面还还包含很多东西,感兴趣自行研究。

但是有时候UserFeignClient类是这样定义的,但是我UserFeignClient2、3、4的自定义配置不想用feign的刚才的配置啊,我又写了一个Configuration2。加入了basic认证的bean。

package com.itmuch.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import feign.auth.BasicAuthRequestInterceptor;

@Configuration
public class Configuration2 {
  @Bean
  public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
    return new BasicAuthRequestInterceptor("user", "password123");
  }
}

然后看我的FeignClient2这样写:

package com.itmuch.cloud.feign;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.itmuch.config.Configuration2;

@FeignClient(name = "xxxx", url = "http://localhost:8761/", configuration = Configuration2.class)
//xxxx就相当于http://localhost:8761/的别名
public interface FeignClient2 {
  //注意下面我们使用的Contract实现是springMVC的实现 不再是feign的。
  @RequestMapping(value = "/eureka/apps/{serviceName}")
  public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName);
}

除了此外feign还支持gzip等等,深入的话请查看官方文档

题外话:有时候在第一次请求时报超时异常,是因为hystrix,他是一个断路器,后面的文章会讲到,他默认第一次响应时间超过1秒则中断,那么解决方案就是在配置文件里面延长他的响应时间,或者禁用超时,或者直接禁用hystrix。

# hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
# 或者:
# hystrix.command.default.execution.timeout.enabled: false
# 或者:
feign.hystrix.enabled: false ## 索性禁用feign的hystrix

# 超时的issue:https://github.com/spring-cloud/spring-cloud-netflix/issues/768
# 超时的解决方案: http://stackoverflow.com/questions/27375557/hystrix-command-fails-with-timed-out-and-no-fallback-available
# hystrix配置: https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.thread.timeoutInMilliseconds

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页