服务拆分

服务拆分注意事项

服务拆分说起来很简单,一个单体架构我们按照功能模块进行拆分,变成多个服务就行了。比如这里四个模块我就拆成四个服务。
image.pngimage.png
当然我们在实际生产中,可能单个模块功能又越来越多,我们还会继续去拆。不过单体架构开发得多的同学容易产生一种思维的定式,容易犯一些错误。在这我给大家讲解一下。

比如说我现在有一个需求是查询订单。同时把订单里面关联的用户信息、商品信息都给他查出来。那如果是以前咱们的开发模式,我肯定是写一个方法去查订单。在订单查询的过程中,得到了用户i d 我再去数据库里把用户查出来,得到商品i d 我再去数据库里把商品查出来。那么这些功能全部写到订单的模块里。这种做法是完全违背了我们微服务的一个原则的。微服务拆分的目的就是单一职责,一个服务只做与自己相关的事儿。那你订单模块当然是做订单业务了,你为什么要做用户查询和商品查询呢?如果所有微服务都是我用到什么,我就查什么。那么这样一来拆分的意义何在呢?

而且你的用户模块在做这样的查询,用户查询上面订单模块也在做,是不是一种重复开发。所以我们微服务拆分的时候,一定要切记不能再像以前那样了,我们的每个微服务都不能去开发重复的业务。如果在你的微服务拆分的过程中出现了重复业务,这就证明你某些地方可能做的有问题。

那为了做好这样的限制,同时我们还会有一些要求:比如说我们要做到微服务的数据独立,每个微服务都会有自己的数据库。那么用户功能的数据库里就是存在用户相关的信息。那商品功能里面存的自然就是商品信息、订单模块里存的就是订单相关的信息。这个时候做订单相关业务时,想查一查用户信息,不好意思、没有。所以就从根源上杜绝去做这种耦合性的一种业务。
image.png


导入服务差分Demo

image.png
从业务角度我们已经能看到了,业务是解除了耦合的订单服务(只做订单功能)、用户查询服务。并且在数据层面我们也要去遵循这个规定,做好分离我们的订单业务。将来查询的表是叫做order 表、用户业务查询的表是叫做用户表。将来我们在实际生产部署时,一定会把它们部署到不同的数据库里。不过现在我们是自己做测试啊,我们就没有那么多机器。那我会准备两个不同的database 去存储这些表。

创建两个数据库cloud_user和cloud-order,然后导入下面两个文件。
cloud-order.sqlcloud-user.sql

打开idea压缩导入cloud-demo.zip,右下角会弹出显示全部服务提示框,然后点击服务就可以人运行
image.png

打开网页访问localhost:8080/order/101
image.png
image.png

打开网页访问localhost:8081/user/1
image.png
image.png


微服务远程调用

image.png


远程调用方式分析

image.png


微服务远程调用-查询订单

1)注册RestTemplate

在order-service的OrderApplication中注册RestTemplate。

  1. package cn.itcast.order;
  2. @MapperScan("cn.itcast.order.mapper")
  3. @SpringBootApplication
  4. public class OrderApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(OrderApplication.class, args);
  7. }
  8. /**
  9. * 创建RestTemplate并注入Spring容器
  10. * @return
  11. */
  12. @Bean
  13. public RestTemplate restTemplate(){
  14. return new RestTemplate();
  15. }
  16. }

2)服务远程调用RestTemplate

修改order-service中的OrderService的queryOrderByld]方法:

package cn.itcast.order.service;
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @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请求,实现远程调用
        User user = restTemplate.getForObject(url, User.class);
        //3.封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }
}

image.png


微服务调用方式

  • 基于RestTemplate发起的http请求实现远程调用
  • http请求做远程调用是与语言无关的调用,只要知道对方的ip、端口、接口路径、请求参数即可。

提供者与消费者

  • 服务提供者:一次业务中,被其它微服务调用的服务。(提供接口给其它微服务)
  • 服务消费者:一次业务中,调用其它微服务的服务。(调用其它微服务提供的接口)

image.png

服务A调用服务B,服务B调用服务C,那么服务B是什么角色?

所以说提供者与消费其实是相对的。一个服务既可以是提供者,又可以是消费者。