Spring Cloud Feign 介绍

Feign是一个声明式的Web服务客户端。这使得Web服务客户端的写入更加方便 要使用Feign创建一个界面并对其进行注释。它具有可插拔注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud添加了对Spring MVC注释的支持,并在Spring Web中使用默认使用的HttpMessageConverters。Spring Cloud集成Ribbon和Eureka以在使用Feign时提供负载均衡的http客户端。

说白了,就是封装了Http调用流程,微服务之间调用API更加方便!

Feign 设计图

springcloud socket请求 springcloud请求调用流程_spring

 使用Feign实现服务之间调用

Feign子项目搭建

接着上一篇再创建一个子项目consumer-feign

springcloud socket请求 springcloud请求调用流程_spring_02

pom文件

引入feign所需的jar包即可

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

yml配置

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8800/eureka/,http://localhost:8810/eureka/
server:
  tomcat:
    uri-encoding: UTF-8
  port: 10002
#  servlet:
#    context-path: /gbq_consumer
spring:
  main:
    allow-bean-definition-overriding: true  #避免相同名字的Feign注册会导致重复注册
  application:
    name: consumer-feign

启动类

@SpringBootApplication
@EnableFeignClients
//@EnableDiscoveryClient
public class ConsumerFeignApplication {

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

}

Controller

@RestController
public class HiController {

    @Autowired
    private GetHello getHello;

    @GetMapping("/hi")
    public String sayHello(String name){
        return getHello.sayHello(name);
    }

    @GetMapping("/test")
    public User getPostUser(User user){
        return getHello.getPostUser(user);
    }

    @GetMapping("/getUser")
    public User getUser(User user){
        return getHello.getUser(user);
    }
}

此处写了三个方法,为的就是踩坑,填坑!具体坑我已经在代码注释中写明了!

GetHello接口类

@FeignClient(name = "provider",path = "gbq_provider")
//@FeignClient(name = "provider")
public interface GetHello {

    //坑一
    //@GetMapping 不支持
    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    String sayHello(@RequestParam("name")String name);

    //坑二 传递参数必须使用对应注解
    @RequestMapping(value = "/getPostUser",method = RequestMethod.POST)
    User getPostUser(@RequestBody User user);

    //坑三 传递参数为复杂参数是请求方式即便设置为get,但仍然以post请求发送
    @RequestMapping(value = "/getUser",method = RequestMethod.GET)
    User getUser(@RequestBody User user);
}

User类

public class User {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

provider的Controller类

也就之前文章中创建的provider,provider-copy俩个子项目,为了一会更好的体现feign和ribbon整合实现负载均衡,所以俩个项目的Controller和上一篇一样,写一样的方法。

注意注释

@RestController
public class HelloController {

    @Value("${server.port}")
    private int port;

    @Resource
    private HelloService helloService;

    @GetMapping("/hello")
    public String sayHello(String name){
        return "你好,cloud"+"name:"+name+"port:"+port;
    }

    @PostMapping("/getPostUser")
    public User getPostUser(@RequestBody User user){
        return user;
    }
    
    /**
     * 此处就可以看到,我是使用get请求发送,却用了post接收
    **/
    @PostMapping("/getUser")  
    public User getUser(@RequestBody User user){
        return user;
    }
}

启动

springcloud socket请求 springcloud请求调用流程_ide_03

 此处因为我启动了俩个相同名称的提供者服务,也就是provider,provider-copy,请求的时候,会按照顺序请求!

springcloud socket请求 springcloud请求调用流程_spring_04

springcloud socket请求 springcloud请求调用流程_ide_05

 这几个请求之间建议好好对比一下,你也可以在Feign调用接口类里边,多尝试不同请求方式,以及不同的参数格式,发送请求!

上一篇文章提到一个坑,就是配置了context-path或者server-path之后,就请求不到了,而feign解决了这个问题

@FeignClient(name = "provider",path = "gbq_provider") //配置这个path就可以了

feign结合ribbon进行服务之间调用

其实这个很简单。

feign结合ribbon子项目搭建

直接复制一份feign。

pom文件

加入ribbon即可

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

yml配置

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8800/eureka/,http://localhost:8810/eureka/
server:
  tomcat:
    uri-encoding: UTF-8
  port: 10003
#  servlet:
#    context-path: /gbq_consumer
spring:
  main:
    allow-bean-definition-overriding: true  #避免相同名字的Feign注册会导致重复注册
  application:
    name: consumer-feign-ribbon

启动类

@SpringBootApplication
@EnableFeignClients
//@EnableDiscoveryClient
public class ConsumerFeignRibbonApplication {

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

    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }

    /**
     * 配置随机负载策略,需要配置属性service-B.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
     */
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }

}

其他类和feign子项目一样

启动

springcloud socket请求 springcloud请求调用流程_ide_06

同样实现了负载均衡!