java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Feign覆写默认配置和Feign日志

关于Feign的覆写默认配置和Feign的日志

作者:刘先森驾到

这篇文章主要介绍了关于Feign的覆写默认配置和Feign的日志方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Feign的覆写默认配置

A central concept in Spring Cloud’s Feign support is that of the named client. Each feign client is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer using the @FeignClient annotation. Spring Cloud creates a new ensemble as anApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.

上面是官网的API文档中的说明,如下是我的翻译:

Spring Cloud的Feign支持的一个中心概念是命名客户端。

每个feign client是整体的一部分,它们一起工作以按需联系远程服务器,并且该整体具有一个名称,开发人员可以使用@FeignClient将其命名。

Spring Cloud根据需要使用FeignClientsConfiguration为每个命名的客户端创建一个新的整体作为ApplicationContext。

这包含(其他)feign.Decoder,feign.Encoder和feign.Contract。

Spring Cloud lets you take full control of the feign client by declaring additional configuration (on top of theFeignClientsConfiguration) using @FeignClient. Example:

@FeignClient(name = “stores”, configuration = FooConfiguration.class)
public interface StoreClient {
//..
}

上面文档说,通过使用额外的配置@FeignClient注解,可以使Spring Cloud让你完全的控制feign客户端。

并且官网还给出了例子,那么我们也按照它提供的例子来在我们的工程师运用起来。

将接口类UserFeignClient进行修改,如下修改后的代码:

@FeignClient(name = "microservice-provider-user", configuration = FooConfiguration.class)
public interface UserFeignClient {
    /**
     * 注意:要使用Feign的注解
     * <p>
     * <code>@RequestLine("GET /repos/{owner}/{repo}/contributors")</code>
     * <br>
     * <code>List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);</code>
     * 
     * @param id
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "/simple/{id}")
//  @RequestLine("GET /simple/{id}")
    public User findById(@PathVariable("id") Long id);
}

在配置FeignClient的configuration指定的值FooConfiguration,这个类是不存在的,这里我们需要新建,官网中也给我创建了这个类的代码,下面是我根据官网的代码和我实际需求修改后的:

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

完成之后,可以开始启动工程了,当我们在启动时,会报错,错误关键如下:

Caused by: java.lang.IllegalStateException: Method findById not annotated with HTTP method type (ex. GET, POST)

这里错误是说我们没有使用Http方法的注解导致的,但我们仔细检查下代码,我们使用的是@RequestMapping的注解方式,这里我也不知道怎么解释,可能是我没有深刻的理解吧,看了Feign 的GitHub的相关代码后,我发现了另一种注解方式:

interface GitHub {
  @RequestLine("GET /repos/{owner}/{repo}/contributors")
  List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}

好的,现在将@RequestMapping注解改成@RequestLine,以及参数也修改成@Param,修改后:

@FeignClient(name = "microservice-provider-user", configuration = FooConfiguration.class)
public interface UserFeignClient {
    /**
     * 注意:要使用Feign的注解
     * <p>
     * <code>@RequestLine("GET /repos/{owner}/{repo}/contributors")</code>
     * <br>
     * <code>List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);</code>
     * 
     * @param id
     * @return
     */
    @RequestLine("GET /simple/{id}")
    public User findById(@Param("id") Long id);
}

修改完成之后,再次重启服务,发现启动成功,而且可以访问接口了。

WARNING Previously, using the url attribute, did not require the name attribute. Using name is now required.

官网中有个这样的提醒:以前在使用URL属性时,不必要使用那么属性,但是在现在Feign中name属性就是必要的了。

它也给了例子,如下面代码:

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
    //..
}

现在我们也来在我们的工程中实际运用一下。

新建一个接口FeignClient2,代码如下:

@FeignClient(name = "xxx", url = "http://localhost:8761/", configuration = BeanConfiguration.class)
public interface FeignClient2 {
//  @RequestMapping(value = "/eureka/apps/{serviceName}")
    @RequestLine("GET /eureka/apps/{serviceName}")
    public String findServiceInfoEurekaByServieName(@Param("serviceName") String serviceName);
}

我们通过这个feign来获取eureka server下注册的实例信息,通过@FeignClient注解配置了name、url和configuration属性,这里那么我随便写的内容,因为这个仅仅表示这个feign的名称而已,url配置的是eureka server的地址,configuration我们这里配的一个需要新建的类BeanConfiguration。

大家肯定还有疑惑,这个BeanConfiguration类配置了是起什么作用的了?

好的,这里就为大家答疑解惑,首先贴出该类的代码:

@Configuration
public class BeanConfiguration {
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("micheal", "123456");
    }
}

看到代码,也许大家可能就明白了,这个在请求时不需要输入用户名和密码就可以直接调用Eureka Server,因为Feign通过这个配置的configuration类为我们做了用户名和密码的权限认证了。

完成上面的内容了,接下来就是见证奇迹的时刻了。

启动服务,在Eureka Server中查看到注册成功了,我们就可以通过浏览器进行查看了。

Feign Logging 日志

A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.

application.yml
logging.level.project.user.UserClient: DEBUG

官网API说:为每个Feign 客户端创建日志,日志的默认名称为所创建的Feign客户端接口类的整个类名。Feign的日志仅仅只有在DEBUG级别时才会响应。

官网给我们提供了例子,按照官网提供的做法,现在来为我们对的工程配置Feign Logging。

以我们microservice-consumer-movie-feign-customizing工程为例,在配置文件application.yml进行Feign 日志配置,如下配置:

logging:
  level:
    com.spring.cloud.feign.UserFeignClient: DEBUG

com.spring.cloud.feign.UserFeignClient 是Feign Client接口类的完成类名。好了,完成了这个配置,是不是有点超激动想要一看是否真的能打印出日志了。

先不着急,我们接着查看官网API文档中的内容:

The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:

• NONE, No logging (DEFAULT).

• BASIC, Log only the request method and URL and the response status code and execution time.

• HEADERS, Log the basic information along with request and response headers.

• FULL, Log the headers, body, and metadata for both requests and responses.

For example, the following would set the Logger.Level to FULL:

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

官网给我们提供了一些日志级别的等级,这里就不一一翻译了。我们的重点是在上面所给的例子,上面例子说为日志设置为FULL级别的日志。

好,开始我们的配置,找到我们所配Feign 日志的客户端接口类,我们发现我们配值得configuration的类时FooConfiguration类,好我们将官网中的feignLoggerLevel方法添加到我们的FooConfiguration类中。

完成之后,我们启动工程,并先将日志清掉,再重新请求接口,发现确实打印出日志来了。

这里还需要补充一下:在配置文件application.yml中配置了Feign客户端日志之后,如果不在configuration类中添加日志级别的话,是不会打印出日志的。因为在官网API中有提到“NONE, no loggin(DEFAULT)”,就是说默认日志级别时NONE的。

Feign进行日志配置

在微服务项目中项目启动遇到 bug 时,很多方面的错误都有可能出现,比如参数错误,接口调用错误等,或者是想了解服务接口的使用量和性能。

首先 Feign 支持自定义日志的配置,配置 Feign 的日志信息是针对以上情况效率很高的一种解决方案。

Feign有四种类型的日志

列出两种在项目中配置Feign日志的方法

一:在配置文件中配置 Feign 的日志

feign:
  client:
    config:
      default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        loggerLevel: FULL #  日志级别

其中 default 表示全局配置日志,将 default 改为具体的服务名称,表示在调用这个服务的时候才会记录日志。

loggerLevel 表示日志的水平,包含 NONE、BASIC、HEADERS、FULL 四种级别的日志。

二:通过配置类的方式

声明一个类,取名为 FeignLoggerConfiguration。在类中声明一个 Logger.Level 对象并返回日志级别,这里设置级别为 BASIC ,通过 @Bean 注解将该方法设置为 IOC 容器的组件。

public class FeignLevelConfiguration {
    @Bean
    public Logger.Level logLevel(){
        return Logger.Level.BASIC;
    }
}

同样的可以设置全局配置和局部给某个服务配置。

全局配置:

在启动类的 @EnableFeignClients 注解中加上参数

defaultConfiguration = FeignLoggerConfiguration .class

这里的 FeignLoggerConfiguration.class要和配置的日志类一致。

局部配置:

在配置了 Feign 的服务接口上的注解 @FeignClient("要调用的服务名称") 加上参数

configuration = FeignLoggerConfiguration .class

这里设置调用的服务名称为 testservice ,则注解改为

@FeignClient(value = "testservice", configuration = FeignLoggerConfiguration .class) 

这里的 FeignLoggerConfiguration.class 就是上面的日志配置类。

同时,在优化 Feign 时可以从日志的级别入手,日志尽量使用 Basic 级别,因为打印日志太多会消耗 Feign 的性能。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文