SpringCloud项目(五)Feign 声明式HTTP客户端

作者:陆金龙    发表时间:2019-08-02 11:19   

关键词Feign,Feign负载均衡

Feign自带负载均衡。

 

面向接口调用微服务,相对于RestTemplate代码更优雅,也更符合MVC的开发习惯。

Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API

 

Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix。创建一个接口并用注解方式配置它即可完成服务提供方的接口绑定简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量

3.5.1 创建工程

创建一个maven module工程klblog-consumer-feign(消费者),Packaging选择jar。

3.5.2 配置pom.xml

参照klblog-consumer的pom.xml配置,多一个feign的依赖项

<!-- feign依赖项 -->

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-feign</artifactId>

</dependency>

全部的依赖项如下;

<dependencies>

<!-- 引入自定义的common通用包,包含entity和util -->

<dependency>

<groupId>com.klfront.klblog</groupId>

<artifactId>klblog-common</artifactId>

<version>${project.version}</version>

</dependency>

 

<!--web的场景,自动引入了web模块开发需要的相关jar包 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

 

<!-- feign依赖项 -->

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-feign</artifactId>

</dependency>

<!-- ribbon相关 -->

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-eureka</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-ribbon</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-config</artifactId>

</dependency>

 

<!-- 修改后立即生效,热部署 -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>springloaded</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-devtools</artifactId>

</dependency>

</dependencies>

 

3.5.3 配置application.yml

参照klblog-consumer的配置,多一个feign的依赖项

feign:

  hystrix:

    enabled: true

全部配置项:

server:

  port: 80

  

feign:

  hystrix:

    enabled: true

      

eureka:

  client:

    register-with-eureka: false

    service-url:

     defaultZone: http://eureka8051.com:8051/eureka/,http://eureka8052.com:8052/eureka/

3.5.4 主启动类

与klblog-consumer相比,没有@RibbonClient注解,要添加@EnableFeignClients和@ComponentScan两个注解。

@SpringBootApplication

@EnableEurekaClient

@EnableFeignClients(basePackages= {"com.klfront.klblog"})

@ComponentScan("com.klfront.klblog")

public class ConsumerFeignMainApplication

{

public static void main(String[] args)

{

SpringApplication.run(ConsumerFeignMainApplication.class, args);

}

}

3.5.5 FeignClient服务

创建一个接口com.klfront.klblog.feignclient.FeignClientService

通过注解@FeignClient(value = "KLBLOG-PROVIDER")绑定KLBLOG-PROVIDER微服务。

定义与KLBLOG-PROVIDER中相对应的接口。Controller通过调用FeignClientService 的接口,即可访问到provider工程提供的相应接口。

 

@FeignClient(value = "KLBLOG-PROVIDER")

public interface FeignClientService {

@RequestMapping(value="/category/discovery", method = RequestMethod.GET)

public Object discovery();

 

@GetMapping("/category/rootlist")

public List<Category> getRootList();

 

@GetMapping("/category/sublist/{parentId}")

public List<Category> getSubList(@PathVariable("parentId") String parentId);

}

3.5.6 Controller中调用FeignClientService的接口

CategoryConsumerController中与klblog-consumer工程不同,不再使用RestTemplate来访问接口,而是使用FeignClientService。

 

@RestController

@RequestMapping("/category")

public class CategoryConsumerController {

@Autowired

private FeignClientService service;

 

@GetMapping(value = "/discovery")

public Object discovery() {

return this.service.discovery();

}

 

@GetMapping("/rootlist")

public List<Category> getRootList() {

return this.service.getRootList();

}

 

@GetMapping("/sublist/{parentId}")

public List<Category> getSubList(@PathVariable("parentId") String parentId){

return this.service.getSubList(parentId);

}

}

 

可见,Feign的方案访问provider的服务接口,效果与klblog-consumer工程相同。

但Controller中不使用RestTemplate且不用拼接url。直接调用Service的接口,更符合MVC控制器调用服务接口的开发习惯,代码更优雅、便捷。

3.6.7 超时问题及超时设置

调试的时候,响应慢一点,经常出现错误 feignClientService#getSubList(String) timed-out and no fallback available

原因 默认的超时时间较短。使用Feign调用接口分两层,ribbon的调用和hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间

解决方案 在application yml文件添加以下

ribbon:

  ReadTimeout: 10000  

  ConnectTimeout: 10000

  

hystrix:

  command:

      default:

        execution:

          isolation:

            thread:

              timeoutInMilliseconds: 10000

3.5.8 经常的数据库报错

### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 1,030,048 milliseconds ago.  The last packet sent successfully to the server was 19,208 milliseconds ago.

就将自己的云服务器上的jdbc连接ip改成域名连接:

 url: jdbc:mysql://www.klfront.com:3306/klblog?useUnicode=true&characterEncoding=utf8