Spring Cloud(四)Feign实现声明式REST调用

Feign简介

Feign是Netflix开发的声明式、模板化的HTTP客户端:

  • Feign可帮助我们更加便捷、优雅地调用HTTP API;
  • 在Spring Cloud中,使用Feign非常简单-----创建一个接口,并在类上添加一些注解,代码就完成了;
  • Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等;
  • Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了 Spring Cloud Ribbon 与 Spring Cloud Hystrix,从而让Feign的使用更加方便;

使用Feign

1:新建Spring Boot项目EurekaServer,添加依赖Eureka Server
2:启动类

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

3:配置文件application.yml

server:
  port: 8761                  
eureka:
  client:
    registerWithEureka: false    #是否将自己注册到Eureka Server,默认为True。由于当前应用就是Eureka Server,故false
    fetchRegistry: false         #是否从Eureka Server获取注册信息,默认True。因为这是一个单节点的Eureka Server,不需要同步其他的Eureka Server节点,故false
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

4:新建Spring Boot项目EurekaClient,添加依赖Eureka Client、Web
5:启动类

@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientApplication {

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

6:MyController- - -测试Feign调用会使用到

@RestController
public class MyController {
	@RequestMapping("/eureka/test")   
    public String test() 
	{
		return "Hello Feign";
	}
}

7:配置文件application.yml

server:
  port: 8020
spring:
  application:
    name: EurekaClinet
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true 

8:新建Spring Boot项目CloudFeignDemo,添加依赖Eureka Client、Web、OpenFeign
9:启动类

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class ServerFeignApplication {

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

10:配置文件application.yml

server:
  port: 8040
spring:
  application:
    name: FeignClinet
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

11:Feign接口

//指定需要调用的微服务名称
@FeignClient(name = "EurekaClinet")
public interface UserFeignClient {    //不需要实现
  @RequestMapping(value = "/eureka/test", method = RequestMethod.GET)
  public String test();
}

12:MyController

@RestController
public class MyController{
  @Autowired
  private UserFeignClient userFeignClient;

  @GetMapping("/testFeign")
  public String testFeign() {	  
    return this.userFeignClient.test();  //会去访问EurekaClinet的/eureka/test,前面已经定义过了
  }
  
  private static final Logger LOGGER = LoggerFactory.getLogger(MyController.class);
  @Autowired
  private LoadBalancerClient loadBalancerClient;
  @GetMapping("/log-user-instance")
  public void logUserInstance() {
    ServiceInstance serviceInstance = this.loadBalancerClient.choose("EurekaClinet");
    // 打印当前选择的是哪个节点
    MyController.LOGGER.info("{}:{}:{}", serviceInstance.getServiceId(), serviceInstance.getHost(), serviceInstance.getPort());
  }
}

12:项目结构
在这里插入图片描述

13:运行测试
启动项目EurekaServer
启动项目EurekaClient(以8020端口启动)
启动项目EurekaClient(以8030端口启动)
启动项目CloudFeignDemo
访问:http://localhost:8040/testFeign
在这里插入图片描述
访问:http://localhost:8040/log-user-instance,控制台打印信息:
在这里插入图片描述
可以看到,不但实现了声明式REST API调用,同时还实现了客户端的负载均衡!

自定义Feign配置

在Spring Cloud中Feign默认使用的契约是SpringMvcContract,因此它可以使用Spring MVC的注解。下面来自定义Feign的配置,让它使用Feign自带的注解进行工作:
1:项目ServerFeign添加Feign的配置类

@Configuration
public class FeignConfiguration {
  /**
   * 将契约改为feign原生的默认契约。这样就可以使用feign自带的注解了。
   * @return 默认的feign契约
   */
  @Bean
  public Contract feignContract() {
    return new feign.Contract.Default();
  }
}

2:修改Feign接口

@FeignClient(name = "EurekaClinet",configuration=FeignConfiguration.class)
public interface UserFeignClient {
  @RequestLine("GET /eureka/test")
  public String test();

}

3:项目结构
在这里插入图片描述

4:运行测试
结果与上面的一致!

Feign对压缩的支持

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

feign:
  compression:
    request:
      enabled: true  # 开启请求压缩
    response:
      enabled: true   # 开启响应压缩

对于请求的压缩,Feign还提供了更为详细的设置:

feign:
  compression:
    request:
      enabled: true  # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型,默认它们三
      min-request-size: 2048 # 设置触发压缩的大小下限,默认2048

该特性在Spring Cloud Camden SR4不生效。不知道以后会不会解决!

Feign的日志

Feign对日志的处理非常灵活,可为每个Feign客户端指定日志记录策略,每个Feign客户端都会创建一个logger。默认情况下,logger的名称是Feign接口的完整类名。需要注意的是,Feign的日志打印只会对DEBUG级别做出响应。
我们可为每个Feign客户端配置各自的Logging .Level对象,告诉Feign记录哪些日志。Logging .Level的值有以下选择:
这里写图片描述
1:修改ServerFeign配置类

@Configuration
public class FeignConfiguration {	
	  @Bean
	  Logger.Level feignLoggerLevel() {
	    return Logger.Level.FULL; //将日志级别设置为FULL
	  }
}

2:在Feign接口,指定配置类

@FeignClient(name = "EurekaClinet",configuration=FeignConfiguration.class)
public interface UserFeignClient {
	@RequestMapping(value = "/eureka/test", method = RequestMethod.GET)
	  public String test();
}

3:在application.yml添加

logging:
  level:  
    com.example.demo.UserFeignClient: DEBUG 
    # 将Feign接口的日志级别设置成DEBUG,全包名+类名

4:运行测试
启动项目EurekaServer
启动项目EurekaClient
启动项目CloudFeignDemo
访问:http://localhost:8040/testFeign,查看CloudFeignDemo项目控制台日志输出!
在这里插入图片描述
将日志Feign的日志级别改为BASIC,重启项目访问:http://localhost:8011/testFeign
在这里插入图片描述
此时,只打印了请求方法、请求的URL和相应的状态码和响应的时间!

当然也可以全使用配置的方式,application.yml添加:

logging:
  level:  
    com.example.demo.UserFeignClient: DEBUG # 将Feign接口的日志级别设置成DEBUG
feign:
  client:
    config:
      EurekaClinet:
        loggerLevel: FULL

使用Feign构造多参数请求

GET请求多参数的URL:
假设请求http://localhost:8040/testFeign/get?id=5&username=yangdong
Feign接口

@FeignClient(name = "EurekaClinet",configuration=FeignConfiguration.class)
public interface UserFeignClient { 
	@RequestMapping(value = "/eureka/test", method = RequestMethod.GET)
	public String testGet(@RequestParam("id") Long id,@RequestParam("username") String username);	
}

URL有几个参数,Feign接口中的方法就有几个参数!!!
CloudFeignDemo控制器MyController

  @GetMapping("/testFeign/get")
  public String testGet(@RequestParam("id") Long id,@RequestParam("username") String username) {
    return this.userFeignClient.testGet(id, username);
  }

EurekaClient控制器MyController

@RestController
public class MyController {		
	@RequestMapping("/eureka/test")
    public String test(@RequestParam("id") Long id,@RequestParam("username") String username) 
	{		
		return "Hello"+id+username;
	}
}

运行测试
访问:http://localhost:8040/testFeign/get?id=5&username=yangdong

访问流程为:CloudFeignDemo控制器MyController的testGet方法,获取到id参数与username参数。执行Feign接口的testGet方法,去访问EurekaClient控制器MyController的test方法。
在这里插入图片描述

常见问题总结

1:项目启动报错

Caused by: java.lang.IllegalStateException: Failed to introspect annotated methods on class org.springframework.cloud.openfeign.FeignClientsConfiguration
	at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:162) ~[spring-core-5.3.3.jar:5.3.3]
	at org.springframework.context.annotation.ConfigurationClassParser.retrieveBeanMethodMetadata(ConfigurationClassParser.java:403) ~[spring-context-5.3.3.jar:5.3.3]
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:326) ~[spring-context-5.3.3.jar:5.3.3]
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) ~[spring-context-5.3.3.jar:5.3.3]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:207) ~[spring-context-5.3.3.jar:5.3.3]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:175) ~[spring-context-5.3.3.jar:5.3.3]
	... 44 common frames omitted
Caused by: java.lang.IllegalStateException: Failed to introspect Class [org.springframework.cloud.openfeign.FeignClientsConfiguration] from ClassLoader [sun.misc.Launcher$AppClassLoader@18b4aac2]
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481) ~[spring-core-5.3.3.jar:5.3.3]
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:455) ~[spring-core-5.3.3.jar:5.3.3]
	at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:151) ~[spring-core-5.3.3.jar:5.3.3]
	... 49 common frames omitted
Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/Module
	at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_221]
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_221]
	at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_221]
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463) ~[spring-core-5.3.3.jar:5.3.3]
	... 51 common frames omitted

如果项目启动报上述错误的话,则说明项目没有引入Eureka Client依赖!

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

pom.xml引入重启即可!

2:项目启动后就自动关闭

2021-01-20 15:11:56.281  INFO 5020 --- [           main] o.s.c.n.e.s.EurekaServiceRegistry        : Registering application FEIGNCLINET with eureka with status UP
2021-01-20 15:11:56.282  INFO 5020 --- [           main] com.netflix.discovery.DiscoveryClient    : Saw local status change event StatusChangeEvent [timestamp=1611126716282, current=UP, previous=STARTING]
2021-01-20 15:11:56.285  INFO 5020 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_FEIGNCLINET/DESKTOP-MC17MVP:FeignClinet:8040: registering service...
2021-01-20 15:11:56.305  INFO 5020 --- [           main] c.e.demo.CloudFeignDemoApplication       : Started CloudFeignDemoApplication in 7.665 seconds (JVM running for 9.408)
2021-01-20 15:11:56.319  INFO 5020 --- [extShutdownHook] o.s.c.n.e.s.EurekaServiceRegistry        : Unregistering application FEIGNCLINET with eureka with status DOWN
2021-01-20 15:11:56.319  INFO 5020 --- [extShutdownHook] com.netflix.discovery.DiscoveryClient    : Saw local status change event StatusChangeEvent [timestamp=1611126716319, current=DOWN, previous=UP]
2021-01-20 15:11:56.329  INFO 5020 --- [extShutdownHook] com.netflix.discovery.DiscoveryClient    : Shutting down DiscoveryClient ...
2021-01-20 15:11:56.377  INFO 5020 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_FEIGNCLINET/DESKTOP-MC17MVP:FeignClinet:8040 - registration status: 204
2021-01-20 15:11:56.377  INFO 5020 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_FEIGNCLINET/DESKTOP-MC17MVP:FeignClinet:8040: registering service...
2021-01-20 15:11:56.390  INFO 5020 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_FEIGNCLINET/DESKTOP-MC17MVP:FeignClinet:8040 - registration status: 204
2021-01-20 15:11:56.393  INFO 5020 --- [extShutdownHook] com.netflix.discovery.DiscoveryClient    : Unregistering ...
2021-01-20 15:11:56.396  INFO 5020 --- [extShutdownHook] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_FEIGNCLINET/DESKTOP-MC17MVP:FeignClinet:8040 - deregister  status: 200
2021-01-20 15:11:56.406  INFO 5020 --- [extShutdownHook] com.netflix.discovery.DiscoveryClient    : Completed shut down of DiscoveryClient

Process finished with exit code 0

如果项目启动如上所述的话,则说明项目没有引入Web依赖!

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

pom.xml引入重启即可!

参考书籍:Spring Cloud与Docker微服务架构实战
以上只是学习所做的笔记,以供日后参考!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值