初识微服务

什么是微服务?

微服务是一种经过良好设计的分布式架构方案,微服务架构有以下特征:

  • 单一职责:微服务拆分力粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发。
  • 面向服务:微服务对外暴露业务接口。
  • 自治:团队独立、技术独立、数据独立、部署独立

微服务架构&单体架构

单体架构

将业务的所有功能集中在一个项目中开发,打成一个包部署。

优点:

架构简单、部署成本低
缺点:

耦合度高。

分布式架构

根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。

优点:

  • 降低服务耦合
  • 有利于服务升级拓展。

微服务技术栈

SpringCloud

SpringCloud是微服务架构落地的一套技术栈。它集成了微服务组件各种功能,并基于SpringBoot实现类这些组件的自动装配,从而提供了良好的开箱即用体验。

版本对应关系

SpringCloud、SpringBoot之间的版本对应关系

官网

SpringCloud、SpringBoot、Spring Cloud Alibaba之间的版本对应关系
查看网址

常用组件表

用途 组件名称
服务注册发现 eureka、nacos、consul
服务的负载均衡 ribbon、dubbo
服务的远程调用 openFeign、dubbo
服务熔断降级 hystrix、sentinel
服务网关 gateway、sentinel
服务配置统一管理 config-server、nacos、apollo
服务消息总线 bus
服务安全组件 security、Oauth2.0
服务监控 admin、jvm
链路追踪 sleuth + zipkin

服务拆分及远程调用

服务拆分的注意事项:

  • 不同微服务,不要重复开发相同业务。
  • 微服务数据独立,不要访问其他微服务的数据库
  • 微服务可以将自己的业务暴露为接口,供其他微服务调用

实例

数据准备

数据库cloud_user

sql 复制代码
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人',
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `tb_user` VALUES (1, '柳岩', '湖南省衡阳市');
INSERT INTO `tb_user` VALUES (2, '文二狗', '陕西省西安市');
INSERT INTO `tb_user` VALUES (3, '华沉鱼', '湖北省十堰市');
INSERT INTO `tb_user` VALUES (4, '张必沉', '天津市');
INSERT INTO `tb_user` VALUES (5, '郑爽爽', '辽宁省沈阳市大东区');
INSERT INTO `tb_user` VALUES (6, '范兵兵', '山东省青岛市');

数据库cloud_order

sql 复制代码
DROP TABLE IF EXISTS `tb_order`;
CREATE TABLE `tb_order`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',
  `user_id` bigint(20) NOT NULL COMMENT '用户id',
  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品名称',
  `price` bigint(20) NOT NULL COMMENT '商品价格',
  `num` int(10) NULL DEFAULT 0 COMMENT '商品数量',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of tb_order
-- ----------------------------
INSERT INTO `tb_order` VALUES (101, 1, 'Apple 苹果 iPhone 12 ', 699900, 1);
INSERT INTO `tb_order` VALUES (102, 2, '雅迪 yadea 新国标电动车', 209900, 1);
INSERT INTO `tb_order` VALUES (103, 3, '骆驼(CAMEL)休闲运动鞋女', 43900, 1);
INSERT INTO `tb_order` VALUES (104, 4, '小米10 双模5G 骁龙865', 359900, 1);
INSERT INTO `tb_order` VALUES (105, 5, 'OPPO Reno3 Pro 双模5G 视频双防抖', 299900, 1);
INSERT INTO `tb_order` VALUES (106, 6, '美的(Midea) 新能效 冷静星II ', 544900, 1);
INSERT INTO `tb_order` VALUES (107, 2, '西昊/SIHOO 人体工学电脑椅子', 79900, 1);
INSERT INTO `tb_order` VALUES (108, 3, '梵班(FAMDBANN)休闲男鞋', 31900, 1);
后端准备
配置文件application.yaml

order

yaml 复制代码
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: com.louis.user.pojo
  configuration:
    map-underscore-to-camel-case: true

user

yaml 复制代码
server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: zkpk
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: com.louis.user.pojo
  configuration:
    map-underscore-to-camel-case: true
order-service
实体类

order

java 复制代码
@Data
public class Order {
    private Long id;
    private Long price;
    private String name;
    private Integer num;
    private Long userId;
    private User user;
}

user

java 复制代码
@Data
public class User {
    private Long id;
    private String username;
    private String address;
}
mapper
java 复制代码
public interface OrderMapper {

    @Select("select * from tb_order where id = #{id}")
    Order findById(Long id);
}
service
java 复制代码
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 4.返回
        return order;
    }
}
controller
java 复制代码
@RestController
@RequestMapping("order")
public class OrderController {

   @Autowired
   private OrderService orderService;

    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }
}
user-service
实体类

user

java 复制代码
@Data
public class User {
    private Long id;
    private String username;
    private String address;
}
mapper
java 复制代码
public interface UserMapper {
    
    @Select("select * from tb_user where id = #{id}")
    User findById(@Param("id") Long id);
}
service
java 复制代码
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id) {
        return userMapper.findById(id);
    }
}
controller
java 复制代码
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

主程序中使用@MapperScan("xxx")来扫描你的mapper文件,如:@MapperScan("cn.itcast.user.mapper")

测试

运行user

运行order

总结

由运行结果中可以看到,在order中不能显示对应user的数据,由于两个服务是相互分离的,并不清楚在另一个表中的数据信息。所以需要使用到远程调用方式(RestTemplate)。(在订单表服务模块使用java代码的方式向用户模块发起请求)

订单服务添加配置类
java 复制代码
package com.louis.order.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * 创建RestTemplate并注入容器
 * @author XRY
 * @date 2023年07月21日14:28
 */

@Configuration
public class Template {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
修改OrderService
java 复制代码
@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请求,查询用户
        //url路径
        String url = "http://localhost:8081/user/" + order.getUserId();
        System.out.println("url = " + url);
        //发送http请求,实现远程调用,不同的请求使用不同的xxxForObject,url和浏览器中输入是一样的
        User user = restTemplate.getForObject(url, User.class);
        order.setUser(user);
        // 4.返回
        return order;
    }
}
服务提供者和消费者

想要实现跨服务远程调用,就是发送一次http的请求,就涉及到了服务提供者和服务消费者。
服务提供者:一次业务中,被其他微服务调用的服务。(提供接口给其他微服务。)
服务消费者:一次业务中,调用其他微服务的服务。(调用其他微服务提供的接口)

在上面的示例中,order_service调用user_service的接口,所以order_service是服务消费者,而user_service是服务提供者。

提供者与消费者的角色是相对的,对于不同的业务来说,一个服务既可以是提供者也可以是消费者。

相关推荐
Lee川2 小时前
深度拆解:基于面向对象思维的“就地编辑”组件全模块解析
javascript·架构
勤劳打代码2 小时前
Flutter 架构日记 — 状态管理
flutter·架构·前端框架
AI攻城狮6 小时前
OpenClaw 里 TAVILY_API_KEY 明明写在 ~/.bashrc,为什么还是失效?一次完整排查与修复
人工智能·云原生·aigc
子兮曰7 小时前
后端字段又改了?我撸了一个 BFF 数据适配器,从此再也不怕接口“屎山”!
前端·javascript·架构
卓卓不是桌桌10 小时前
如何优雅地处理 iframe 跨域通信?这是我的开源方案
javascript·架构
Qlly10 小时前
DDD 架构为什么适合 MCP Server 开发?
人工智能·后端·架构
阿里云云原生1 天前
零配置部署顶级模型!函数计算一键解锁 Qwen3.5
云原生
AI攻城狮1 天前
Kimi Bot + OpenClaw 完整配置指南:5 步实现本地 AI Agent 集成
人工智能·云原生·aigc
用户881586910911 天前
AI Agent 协作系统架构设计与实践
架构
鹏北海1 天前
Qiankun 微前端实战踩坑历程
前端·架构