微服务远程调用

在微服务架构中,不同微服务都应该有自己独立的数据库以减少服务之间的冗余。而不同的服务之间可能需要共享数据。但拆分后的服务,它们的数据库是相互独立的,一个服务不可能去调用另一个服务的数据库,所以服务之间的信息共享成为一个问题。

为了解决服务之间的信息共享,微服务通过将业务暴露为接口,以供其它微服务使用。这种服务调用方式与用户调用服务的方式是相同的,都是通过URL来远程调用接口。

在微服务远程调用中,有一下两种角色:

  • 服务提供者(Provider):一次业务中,被其它微服务调用的服务。

    即提供接口给其它微服务的服务。

  • 服务消费者(Consumer):一次业务中,调用其它微服务的服务。

    即调用其它微服务提供的接口的服务。

服务的角色是相对而言的。抛开业务来讲,服务既可以是提供者也可以消费者。


RestTemplate 远程调用

在SpringCloud中,微服务的远程调用方式可以通过RestTemplate发起HTTP请求来调用。而HTTP请求做远程调用是与语言无关的调用,只要知道对方的ip、端口、接口路径、请求参数即可。

例如有两个服务,分别是用户服务和订单服务,订单服务在获取订单信息时需要将用户信息一同发送:

  1. 使用RestTemplate需要先进行注册(配置)。

    在订单服务模块(消费者)中新建一个配置并声明一个Bean:

    /**
     * 创建RestTemplate,并注入Spring容器
     */
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
    
  2. OrderService中注入RestTemplate,并通过RestTemplate远程调用用户服务模块:

    @Service
    public class OrderService {
    
        @Autowired
        private OrderMapper orderMapper;
        // 注入RestTemplate
        @Autowired
        private RestTemplate restTemplate;
    
        public Order queryOrderById(Long orderId) {
            // 1.查询订单
            Order order = orderMapper.findById(orderId);
            // 2.利用RestTemplate发起HTTP请求,查询用户信息
            // 2.1.URL路径
            String url = "http://localhost:8081/user/" + order.getUserId();
            // 2.2.发送HTTP(GET)请求,实现远程调用
            User user = restTemplate.getForObject(url, User.class);
            // 3.封装User到Order
            order.setUser(user);
            // 4.返回
            return order;
        }
    }
    

    RestTemplate.getForObject()RestTemplate调用HTTP-GET请求的方法,该方法接收一个字符串类型的URL参数,并可以通过.class来指定响应的类型。

    用户服务模块中相应的接口如下(假设服务的端口为本地8081端口):

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        /**
         * 根据用户ID获取用户信息
         * @param id 用户ID
         * @return 用户信息
         */
        @GetMapping("/{id}")
        public User queryById(@PathVariable("id") Long id) {
            return userService.queryById(id);
        }
    }
    

使用RestTemplate存在以下问题:

  • URL的硬编码问题。
  • 服务消费者该如何获取服务提供者的地址信息。
  • 如果有多个服务提供者,消费者该如何选择。
  • 消费者如何得知服务提供者的健康状态。

RestTemplate是Spring Cloud自带的,所以不用引入依赖。