Spring Cloud 随笔6——声明式服务调用:Spring Cloud Feign

背景:

Spring Cloud Ribbon:实现客户端负载均衡的服务调用

Spring Cloud Hystrix:通过断路由来保护微服务应用

       在实际使用中,我们会发现Ribbon和Hystrix几乎是同时出现使用的。那么,Spring Cloud Feign就是一个整合Spring Cloud Ribbon和Spring Cloud Hystrix的工具,除了提供这两者强大的功能之外,还提供了一种声明式的Web服务客户端定义方式。

      在使用Spring Cloud Ribbon时,通常都会利用它对RestTemplate的请求拦截来实现对以来服务的接口调用。而在Spring Cloud Feign的实现下,我们只需要创建一个接口并用注解的方式来配置它,即可完成对服务提供方接口的绑定,这样可以简化在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。

一、快速入门

@FeignClient(value = "hello-service")
@Service
public interface HelloService {
    @RequestMapping("/hello")
    String hello();
}

以上代码中就是通过@FeignClient注解来绑定服务提供者(hello-service)的接口;通过Spring MVC的注解@RequestMapping注解来绑定具体调用helllo-service服务提供的哪一个REST接口。

具体例子请参考:Spring Cloud (十)、声明式服务调用Feign(入门)

二、参数绑定

如:带有Request参数请求、带有Header信息的请求、带有RequestBody的请求以及请求响应体中是一个对象的请求:

服务提供者:hello-service

 /*带有Request参数的请求*/
    @RequestMapping("/hello1")
    public String hello(@RequestParam String name){
        return "hello "+name;
    }

    /*带有Header信息的请求*/
    @RequestMapping("/hello2")
    public User hello(@RequestHeader String name,@RequestHeader Integer age){
        return new User(name,age);
    }

    /*带有RequestBody的请求以及请求响应体是一个对象的请求*/
    @RequestMapping("/hello3")
    public String hello(@RequestBody User user){
        return "hello "+user.getName()+","+user.getAge();
    }

服务消费者:fegin-consume

    @RequestMapping("/hello1")
    String hello(@RequestParam("name") String name);

    @RequestMapping("/hello2")
    User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);

    @RequestMapping("/hello3")
    String hello(@RequestBody User user);

注意:服务消费者的@RequestParam、@RequestHeader注解必须通过value值来指定具体的参数名。

具体例子请参考:Spring Cloud (十一)、Feign参数绑定

三、继承特性

        继承特性帮助我们解决了复制相同代码的操作,以进一步减少了编码量。通过Spring Cloud Feign的继承特性来实现REST接口定义的复用。

优点:可以轻易地实现接口定义的共享

缺点:容易产生牵一发而动全身地后果

具体例子请参考:Spring Cloud (十二)、Feign的继承特性

四、Ribbon配置

对Ribbon的默认的配置主要是在DefaultClientConfigImpl类里面,我们搜索到这个类,然后查看默认配置。

1、全局配置:ribbon.=

ribbon.DEFAULT_CONNECT_TIMEOUT=500
ribbon.DEFAULT_READ_TIMEOUT=5000

2、指定服务配置.ribbon.key=value,其中就对应的是@@FeignClient注解中服务名 

hello-service.ribbon.ConnectTimeout=500
hello-service.ribbon.ReadTimeout=5000
hello-service.ribbon.OkToRetryOnAllOperations=true

五、Hystrix配置

对Hystrix的默认配置主要是在HystrixCommandProperties类里面,我们搜索到这个类,然后查看默认配置。

1、全局配置

      直接使用默认配置前缀hystrix.command.default就可以进行设置,比如设置全局的超时时间:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

      在对Hystrix进行配置之前,我们需要确认feign.hystrix.enabled参数没有被设置为false(默认值就为false),否则该参数设置会关闭Feign客户端的Hystrix支持。

2、禁用Hystrix

      feign.hystrix.enabled=false用来关闭Hystrix功能,这是全局的。如果只想针对某个服务客户端关闭Hystrix支持时,需要使用@Scope("prototype")注解为指定的客户端配置Feign.Builder实例,详细步骤如下:

(1)、构建一个关闭Hystrix的配置类

@Configuration
public class DisableHystrixConfiguration {
    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder(){
        return Feign.builder();
    }
}

(2)、在HelloService的@FeignClient注解中,通过configuration参数引入上面实现的配置类。

             疑问???:这里我发先就算不进行configuration参数引入实现的配置类也能将Hystrix支持功能进行关闭,有兴趣的可再次进行验证。

@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class,configuration = DisableHystrixConfiguration.class)
@Service
public interface HelloService {
    @RequestMapping("/hello")
    String hello();

    @RequestMapping("/hello1")
    String hello(@RequestParam("name") String name);

    @RequestMapping("/hello2")
    User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);

    @RequestMapping("/hello3")
    String hello(@RequestBody User user);

}

       这时我们在我们请求的时候,服务降级逻辑就不会生效,因为此时已经关闭了Hystrix的支持功能。

3、指定命令配置

      hystrix.command.作为前缀,而默认情况下会采用Feign客户端中的方法名做为标识。比如:

hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000

以上配置中的hello就是以下中hello方法名。

@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class,configuration = DisableHystrixConfiguration.class)
@Service
public interface HelloService {
    @RequestMapping("/hello")
    String hello();

    @RequestMapping("/hello1")
    String hello(@RequestParam("name") String name);

    @RequestMapping("/hello2")
    User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);

    @RequestMapping("/hello3")
    String hello(@RequestBody User user);

}

需要注意的是,由于方法名很有可能重复,这个时候相同方法名的Hystrix配置会共用,所以在进行方法定义与配置的时候需要做好一定的规划。

4、服务降级配置

      (1)、只需要为Feign客户端的定义接口编写一个具体的接口实现类。其中每个重写方法的实现逻辑都可以用来定义相应的服务降级逻辑。

@Component
public class HelloServiceFallback implements HelloService {
    @Override
    public String hello() {
        return "error";
    }

    @Override
    public String hello(String name) {
        return "error";
    }

    @Override
    public User hello(String name, Integer age) {
        return new User("未知",0);
    }

    @Override
    public String hello(User user) {
        return "error";
    }
}

必须要使用@Component注解将其注入到容器中。

(2)、在服务绑定接口中,通过@FeignClient注解的fallback属性来指定对应的服务降级实现类。

@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class)
@Service
public interface HelloService {
    @RequestMapping("/hello")
    String hello();

    @RequestMapping("/hello1")
    String hello(@RequestParam("name") String name);

    @RequestMapping("/hello2")
    User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);

    @RequestMapping("/hello3")
    String hello(@RequestBody User user);

}

具体例子请参考:Spring Cloud (十三)、Feign服务降级配置

六、其他配置

1、请求压缩:Spring Cloud Feign支持对请求与响应进行GZIP压缩,以减少通信过程中的性能消耗。我们只需要通过下面两个参数设置,就能开启请求与响应的压缩功能:

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

     同时,我们还能对请求压缩做一些更细致的设置,比如下面的配置内容指定了压缩的请求数据类型,并设置了请求压缩的大小下限,只有超过这个大小的请求才会对其进行压缩。

feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

2、日志配置

      可以在application.properties配置文件中使用loggin.level.的参数配置格式来开启指定Feign客户端的DEBUG日志,其中为Feign客户端定义接口的完整路径,比如:

logging.level.com.example.feginconsume.Service.HelloService=debug

        但是,只是添加了如上的配置,还无法实现DEBUG日志的输出。这是由于Feign客户端默认的Logger.Level对象定义为NONE级别,该级别不会记录任何Feign调用过程的信息,所以我们要调整它的级别:

  针对全局的日志级别,可以在应用主类上添加Logger.Level的Bean创建,具体如下:

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeginConsumeApplication {

	@Bean
	Logger.Level feignLoggerLevel(){
		return Logger.Level.FULL;
	}

	public static void main(String[] args) {
		SpringApplication.run(FeginConsumeApplication.class, args);
	}

}

导入的日志包为import feign.Logger;

当然也可以通过实现配置类,然后在具体的Feign客户端来制定配置类以实现是否要调整不同的日志级别,比如下面的实现:

@Component
public class FullLogConfiguration {
    @Bean
    Logger.Level feignLoggetLevel(){
        return Logger.Level.HEADERS;
    }
}
@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class,configuration = FullLogConfiguration.class)
@Service
public interface HelloService {
   ...
}

疑问???:这里我发先就算不进行configuration参数引入实现的配置类也能将日志信息进行调整,有兴趣的可再次进行验证。

对于Feign的Logger级别主要有下面四类,可根据实际需要进行调整使用:

  • NONE:不记录任何信息
  • BASIC:紧记录请求方法,URL以及响应状态码和执行时间。
  • HEADERS:除了记录BASIC级别的信息之外,还会记录请求和响应的头信息。
  • FULL:记录所有请求与相应的明细,包括头信息、请求体、元数据等。

你可能感兴趣的:(Spring,Cloud随笔)