前言
前面我们使用的RestTemplate实现REST API调用,代码大致如下:
public User findById(@PathVariable Long id) { return restTemplate.getForObject("http://localhost:8084/" + id, User.class); }
由代码可知,我们是使用拼接字符串的方式构造URL的,该URL只有一个参数。但是,在现实中,URL中往往含有多个参数。这时候我们如果还用这种方式构造URL,那么就会非常痛苦。举个例子:
http://localhost:8010/search?name=zhangsan&username=account1&age=20
这里是有三个参数,要是有10个参数,那么代码会变得难以维护。
怎么解决?
Feign简介
Feign是Netflix开发的声明式,模板化的HTTP客户端,其灵感来自Retrofit,JAXRS-2.0以及WebSocket.Feign可帮助我们更加便捷,优雅的调用HTTP API。
在spring cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
spring cloud对Feign进行了增强,使Feign支持了springmvc注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
代码编写
1.我们复制前面的microservice-consumer-movie,将ArtifactId修改为microservice-consumer-movie-feign.
2.添加Feign的依赖。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
3.创建一个Feign接口,并添加@FeignClient注解。
@FeignClient("microservice-provider-user") public interface UserFeignClient { @RequestMapping(value="/{id}",method = RequestMethod.GET) public User findById(@PathVariable("id") Long id); }
这里解释一下:@FeignClient注解中的microservice-provider-user是一个任意的客户端名称,用于创建Ribbon负载均衡器。在本例中,使用了Eureka,所以Ribbon会把microservice-provider-user解析成Eureka Server服务注册表中的服务。
当然,你也可以使用url属性指定请求URL(URL可以是完整的URL或者主机名),例如:
@FeignClient(name="microservice-consumer-user",url="http://localhost:8000/")
4.修改Controller代码,让其调用Feign接口。
@RestController public class MovieController { // @Autowired // private RestTemplate restTemplate; @Autowired private UserFeignClient userFeignClient; @GetMapping("/user/{id}") public User findById(@PathVariable Long id) { // return restTemplate.getForObject("http://localhost:8081/" + id, User.class); return userFeignClient.findById(id); } }
5.修改启动类,为其添加@EnableFeignClients注解,如下:
@SpringBootApplication @EnableFeignClients public class ConsumerMovieApplication { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ConsumerMovieApplication.class, args); } }
这样,我们的电影微服务就可以用Feign去调用用户微服务的API了。
测试
启动microservice-discovery-eureka.
启动2个或更多microservice-provider-user实例。
启动microservice-consumer-movie-feign.
多次访问http://localhost:8082/user/1,返回结果。
{"id":1,"username":"account1","name":"张三","age":20,"balance":98.23}
两个用户微服务实例都会打印如下日志:
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.balance as balance3_0_0_, user0_.name as name4_0_0_, user0_.username as username5_0_0_ from user user0_ where user0_.id=? 2019-04-19 19:23:42.249 TRACE 7464 --- [nio-8084-exec-7] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [1] 2019-04-19 19:23:42.251 TRACE 7464 --- [nio-8084-exec-7] o.h.type.descriptor.sql.BasicExtractor : extracted value ([age2_0_0_] : [INTEGER]) - [20] 2019-04-19 19:23:42.251 TRACE 7464 --- [nio-8084-exec-7] o.h.type.descriptor.sql.BasicExtractor : extracted value ([balance3_0_0_] : [NUMERIC]) - [98.23] 2019-04-19 19:23:42.251 TRACE 7464 --- [nio-8084-exec-7] o.h.type.descriptor.sql.BasicExtractor : extracted value ([name4_0_0_] : [VARCHAR]) - [张三] 2019-04-19 19:23:42.251 TRACE 7464 --- [nio-8084-exec-7] o.h.type.descriptor.sql.BasicExtractor : extracted value ([username5_0_0_] : [VARCHAR]) - [account1]
以上结果说明,我们不但实现了声明式REST API调用,同时还实现了客户端侧的负载均衡。
代码下载地址:https://gitee.com/fengyuduke/my_open_resources/blob/master/microservice-consumer-movie-feign.zip