Spring Cloud Feign它基于Netflix Feign实现,整合了Spring Cloud Ribbon与Spring Cloud Hystrix,除了提供这两者的强大功能,它还提供了一种声明式的Web服务客户端定义方式。
1.下面首先创建一个Spring Boot基础工程取名为feign-consumer并在其pom.xml文件中加入spring-cloud-starter-eureka和spring-cloud-starter-feign依赖。
<?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><groupId>com.example</groupId><artifactId>feign-consumer</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>feign-consumer</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.5.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><spring-cloud.version>Finchley.SR1</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><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></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
2.在主类上添加@EnableFeignClients注解开启Spring Cloud Feign的支持功能:
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class FeignConsumerApplication {public static void main(String[] args) {SpringApplication.run(FeignConsumerApplication.class, args);}
}
3.定义HelloService接口,通过@FeignClient注解指定服务名来绑定服务,然后使用Spring MVC的注解来绑定具体该服务提供的REST接口。
@FeignClient("hello-service")//用于绑定名为hello-service服务
public interface HelloService {@RequestMapping("/hello")public String hello(String id);}
4.最后创建一个控制器来实现对Feign客户端的调用。使用@AutoWired直接注入HelloService实例,并在该控制器中直接调用hello-service服务发起的/hello接口的调用。
@RestController
public class ConsumerController {@AutowiredHelloService helloService;@GetMapping("/feign-consumer")public String helloConsumer(String id){return helloService.hello(id);}
}
5.修改application.properties文件:
spring.application.name=feign-consumer
server.port=9001eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
不过此时是没有参数绑定能力的所以没有打印id。
参数绑定
首先扩展一下服务提供者(hello-service)。
@RestController
public class HelloController {private final Logger logger=Logger.getLogger(getClass());@RequestMapping("/hello")public String index() throws InterruptedException {
// int sleepTime=new Random().nextInt(3000);
// logger.info("sleep:"+sleepTime);
// Thread.sleep(sleepTime);logger.info(new Date());return "Hello"+new Date()+"---"+new Random().nextInt();}@RequestMapping(value = "/hello1", method = RequestMethod.GET)public String hello1(@RequestParam String name) {return "hello " + name + "!";}@RequestMapping(value = "/hello2", method = RequestMethod.GET)public Map<String,Object> hello2(@RequestHeader String name, @RequestHeader String author, @RequestHeader Integer price) throws UnsupportedEncodingException {Map<String,Object> map = new HashMap<String,Object>();map.put("name",URLDecoder.decode(name));map.put("author",URLDecoder.decode(author));return map;}@RequestMapping(value = "/hello3", method = RequestMethod.POST)public String hello3(@RequestBody Map<String,Object> book) {return "书名为:" + book.get("name") + ";作者为:" + book.get("author");}@RequestMapping(value = "/hello4", method = RequestMethod.POST)public String hello4(@RequestBody User user) {return "用户名:" + user.getName() + ";年龄为:" + user.getAge();}
}
User类:
public class User {private String name;private Integer age;public User(){}public User(String name, Integer age){this.name=name;this.age=age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
然后在feign-consumer中也创建逾期一样的User类。
然后再HelloService接口中新增上述接口的绑定:
@FeignClient("hello-service")//用于绑定名为hello-service服务
public interface HelloService {@RequestMapping("/hello")public String hello();@RequestMapping(value = "/hello1", method = RequestMethod.GET)String hello(@RequestParam("name") String name);@RequestMapping(value = "/hello2", method = RequestMethod.GET)Map<String,Object> hello(@RequestHeader("name") String name, @RequestHeader("author") String author, @RequestHeader("price") Integer price);@RequestMapping(value = "/hello3", method = RequestMethod.POST)String hello(@RequestBody Map<String,Object> book);@RequestMapping(value = "/hello4", method = RequestMethod.POST)String hello(@RequestBody User user);
}
这里需要注意在绑定参数时,@RequestParam,@RequestHeader等可以指定参数名称的注解的value参数不能少。在Feign中绑定参数必须通过value来指定具体的参数名不然会抛出IlleglStateException异常,value属性不能为空。
最后控制器新增上述接口:
@RestController
public class ConsumerController {@AutowiredHelloService helloService;@GetMapping("/feign-consumer")public String helloConsumer(){return helloService.hello();}@RequestMapping("/hello1")public String hello1() {return helloService.hello("张三");}@RequestMapping(value = "/hello2")public Map<String,Object> hello2() throws UnsupportedEncodingException {Map<String,Object> book = helloService.hello(URLEncoder.encode("三国演义","UTF-8"), URLEncoder.encode("罗贯中","UTF-8"), 33);System.out.println(book);return book;}@RequestMapping("/hello3")public String hello3() {Map<String,Object> book = new HashMap<String,Object>();book.put("name","三国演义");book.put("author","罗贯中");return helloService.hello(book);}@RequestMapping("/hello4")public String hello4() {User user=new User("刘德华",99);return helloService.hello(user);}}