在Spring Cloud中调用服务有两种方式:RestTemplate 和 FeignClient。
先模拟一个简单的环境,有两个服务:
- 用户服务 app-user:127.0.0.1:8010
- 订单服务 app-order:127.0.0.1:8020
订单服务有个getUserOrders接口,用户服务需要调用这个接口。
RestTemplate方式
底层采用的是HttpClient(开发中基本上不用RestTemplate方式)
首先在调用方用户服务中,将RestTemplate注入到Spring容器中:
然后使用RestTemplate对象传入调用地址和返回类型,开始调用:
调用结果:
但是这种方式是直接通过地址调用,并没有经过注册中心,所以还有一种方式就是通过注册中心使用服务别名进行调用,不过得依赖Ribbon负载均衡器,那么就需要使用@LoadBalanced注解使RestTemplate拥有负载均衡的能力。
把访问地址换为别名形式:
再进行访问,也是没问题的:
ps:这里说明一下Eureka的调用的过程
订单服务启动的时候,会把当前服务信息注册到Eureka中,服务名称app-order,服务地址127.0.0.1:8010。用户服务在调用订单服务的时候,就会拿订单服务的名称app-order,去获取对应的调用地址127.0.0.1:8010,然后在本地使用HttpClient进行远程调用。
Feign客户端方式
首先引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在启动类,通过@EnableFeignClients注解开启扫描Feign客户端的功能:
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class AppUserApplication {
public static void main(String[] args) {
SpringApplication.run(AppUserApplication.class, args);
}
}
在调用方“用户服务”新建一个Feign客户端调用接口,使用@FeignClient注解来制定需要调用的服务名称,接口中的方法就以Spring MVC接口形式书写:
@FeignClient(name = "app-order")
public interface OrderApiFeign {
@RequestMapping("/getUserOrders")
String getOrder();
}
然后在调用的Controller中,直接调用Feign客户端中的接口就行了:
@RestController
public class UserController {
@Autowired
OrderApiFeign orderApiFeign;
@RequestMapping("/getOrder")
public String getOrder() {
return orderApiFeign.getOrder();
}
}
Feign客户端的关键机制就是动态代理,如果你对某个接口进行了@FeignClient注解声明,Feign就会针对这个接口创建一个动态代理对象,在调用这个接口的时候,其实就是调用这个接口的代理对象,代理对象根据@FeignClient注解中的name找到对应的服务,然后再根据@RequestMapping等其它注解的映射路径构造出请求地址,针对这个地址,再从本地实现RPC远程调用。