Feign-1 Feign的简介及基础使用

讨论声明式的REST Client Feign

7. Declarative REST Client: Feign

https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html

首先我们来看一下Feign是什么,Feign是一个声明式的web service的客户端,他让写web service的客户端更加的容易,

如果你想用Feign创建一个接口,然后添加一些注解,就OK了,他说他支持Feign的注解,JAX-RS的注解,大家知道JAX-RS

是什么吗,JAX-RS是JAVA API For RESTFul Service,说到JAX-RS就不得不说到另一个标准,它是一个WEB Service的

标准,JAX-WS,JAVA API For Web Service,这个大家可能都看过,就是之前的SOAP协议,WEB Service里面的一堆标准,

有了REST出来了,JAVA与时俱进,他又搞了一个REST Service的一个标准,它是一个标准,如果大家想深入了解JAX-RS

的话,你用这样的一个框架进行入门,叫jersey,JAX-RS的话,其实有一部分是参考了jersey的设计,当然cxf,他也是支持

JAX-RS标准的,Feign同样支持,可插拔的编码器和解码器,Spring Cloud为Feign添加了SpringMVC的注解,使用相同的

HttpMessageConverters,我们知道SpringMVC的Converter,说白了Spring Cloud扩展了Feign,支持了SpringMVC的注解,

在Spring Cloud使用Feign的时候,他整合了Ribbon和Eureka,以提供负载均衡的能力,首先他是一个声明式的HTTP的client,

如果你想使用它的话,创建一个接口,然后添加注解,最后他还整合了Ribbon和Eureka,他还可以使用SpringMVC的注解,降低了

我们的学习成本,否则不管我们要学Feign的注解,我们其实都是有额外的学习成本的,我们来看一下Feign的github

Feign is a declarative web service client. It makes writing web service clients easier. 

To use Feign create an interface and annotate it. It has pluggable annotation support including 

Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. 

Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters 

used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load 

balanced http client when using Feign.

https://github.com/OpenFeign/feign

它的URL最近发生了变化,其实他是netflix的产品,他被重定向到OpenFeign/feign,我们来看一下Feign的版本,

https://github.com/OpenFeign/feign/releases

它的版本迭代的非常的快,它的代码更新也是非常的频繁,这个东西很活跃,很有前途的,怎么样使用这个Feign呢,

7.1 How to Include Feign

光知道这个东西介绍的再好有什么用啊,我们怎么样用,在Spring Cloud或者SpringBoot里面,基本上会有一个

思维定式了,引入他的starter

To include Feign in your project use the starter with group org.springframework.

cloud and artifact id spring-cloud-starter-openfeign. See the Spring Cloud Project page 

for details on setting up your build system with the current Spring Cloud Release Train.

Example spring boot app

@SpringBootApplication
@EnableFeignClients
public class Application {

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

}

我们在启动类上加上@EnableFeignClients这个注解

StoreClient.java. 

@FeignClient("stores")
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);
}

这才是正题,创建一个接口,在接口上添加一个注解

localhost:8010/movie/1

timeout解释一下,可能是应用刚启动,因为它会从Eureka上拉,拉东西,它会把虚拟IP

@FeignClient("microservice-simple-provider-user")

转成真正的IP,所以他可能会造成一个超时,

localhost:8010/test/?id=1&username=zhangsan&age=20

{"id":1,"username":"zhangsan","name":null,"age":20,"balance":null}

localhost:7900/get-user/?id=1&username=zhangsan&age=20

localhost:8010/test-get/?id=1&username=zhangsan&age=20

feign.FeignException: status 405 reading UserFeignClient#getUser(User); content:

{
	"timestamp":1566720796075,
	"status":405,
	"error":"Method Not Allowed",
	"exception":"org.springframework.web.HttpRequestMethodNotSupportedException",
	"message":"Request method 'POST' not supported",
	"path":"/get-user"
}

你请求的方法是POST,

// 该请求不会成功,只要参数是复杂对象,即使指定了是GET方法,feign依然会以POST方法进行发送请求。
// 可能是我没找到相应的注解或使用方法错误。
@RequestMapping(value = "/get-user", method = RequestMethod.GET)
public User getUser(User user);
package com.learn.cloud.entity;

import java.math.BigDecimal;

public class User {
	
  public User(Long id, String name) {
	super();
	this.id = id;
	this.name = name;
  }

  public User() {
	super();
 }

  private Long id;

  private String username;

  private String name;

  private Short age;

  private BigDecimal balance;

  public Long getId() {
    return this.id;
  }

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

  public String getUsername() {
    return this.username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getName() {
    return this.name;
  }

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

  public Short getAge() {
    return this.age;
  }

  public void setAge(Short age) {
    this.age = age;
  }

  public BigDecimal getBalance() {
    return this.balance;
  }

  public void setBalance(BigDecimal balance) {
    this.balance = balance;
  }
}
package com.learn.cloud.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.collect.Lists;
import com.learn.cloud.entity.User;
import com.learn.cloud.mapper.UserMapper;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;

@RestController
public class UserController {

  @Autowired
  private UserMapper userMapper;
  
  @Autowired
  private EurekaClient eurekaClient;
  
  @Autowired
  private DiscoveryClient discoveryClient;

  @GetMapping("/simple/{id}")
  public User findById(@PathVariable Long id) {
    return this.userMapper.getUserById(id);
  }
  
  @GetMapping("/eureka-instance")
  public String serviceUrl() {
    InstanceInfo instance = this.eurekaClient.getNextServerFromEureka("MICROSERVICE-SIMPLE-PROVIDER-USER", false);
    return instance.getHomePageUrl();
  }
  
  @GetMapping("/instance-info")
  public ServiceInstance showInfo() {
    ServiceInstance localServiceInstance = this.discoveryClient.getLocalServiceInstance();
    return localServiceInstance;
  }
  
  @PostMapping("/user")
  public User postUser(@RequestBody User user) {
    return user;
  }

  // 该请求不会成功
  @GetMapping("/get-user")
  public User getUser(User user) {
    return user;
  }

  @GetMapping("list-all")
  public List<User> listAll() {
    ArrayList<User> list = Lists.newArrayList();
    User user = new User(1L, "zhangsan");
    User user2 = new User(2L, "zhangsan");
    User user3 = new User(3L, "zhangsan");
    list.add(user);
    list.add(user2);
    list.add(user3);
    return list;

  }
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<artifactId>microservice-consumer-movie-feign</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>microservice-simple-consumer-movie</name>
	<description>Demo project for Spring Boot</description>

  <parent>
    <groupId>cn.learn</groupId>
    <artifactId>microcloud02</artifactId>
    <version>0.0.1</version>
  </parent>
  
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-feign</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>
#debug=true
server.port=8010

eureka.client.serviceUrl.defaultZone=http://admin:1234@10.40.8.152:8761/eureka

spring.application.name=microservice-consumer-movie-ribbon
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
eureka.client.healthcheck.enabled=true
spring.redis.host=10.40.8.152
spring.redis.password=1234
spring.redis.port=6379

#stores.ribbon.listOfServers=10.40.8.144:7900
package com.learn.cloud.feign;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.learn.cloud.entity.User;

@FeignClient("microservice-simple-provider-user")
public interface UserFeignClient {
	
	  @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
	  // 两个坑:1. @GetMapping不支持   2. @PathVariable得设置value
	  public User findById(@PathVariable("id") Long id); 
	
	  @RequestMapping(value = "/user", method = RequestMethod.POST)
	  public User postUser(@RequestBody User user);
	
	  // 该请求不会成功,只要参数是复杂对象,即使指定了是GET方法,feign依然会以POST方法进行发送请求。可能是我没找到相应的注解或使用方法错误。
	  @RequestMapping(value = "/get-user", method = RequestMethod.GET)
	  public User getUser(User user);
  
}
package com.learn.cloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.learn.cloud.entity.User;
import com.learn.cloud.feign.UserFeignClient;

@RestController
public class MovieController {

  @Autowired
  private UserFeignClient userFeignClient;

  @GetMapping("/movie/{id}")
  public User findById(@PathVariable Long id) {
    return this.userFeignClient.findById(id);
  }

  @GetMapping("/test")
  public User testPost(User user) {
    return this.userFeignClient.postUser(user);
  }

  @GetMapping("/test-get")
  public User testGet(User user) {
    return this.userFeignClient.getUser(user);
  }
}

package com.learn.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ConsumerMovieFeignApplication {

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

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值