1. 微服务架构—SpringCloud
1.1 单体应用架构
将项目所有模块【功能】打成jar包或者war包,然后部署一个进程
优点:
- 部署简单:由于是完整的结构体,可以直接部署在一个服务器上即可
- 技术单一:项目不需要复杂的技术栈,往往一套熟悉的技术栈就可以完成开发
缺点:
- 系统启动慢,一个进程包含了所有的业务逻辑,涉及到的启动模块过多,导致系统的启动,重启时间周期过长
- 系统错误隔离性差、可用性差,任何一个模块的错误均可能造成整个系统的宕机;
- 可伸缩性差:系统的扩容只能只对这个应用进行扩容,无法结合业务模块的特点进行伸缩。
- 线上问题修复周期长:任何一个线上问题修复需要对整个应用系统进行全面升级。
- 跨语言程度差
- 不利于安全管理,所有开发人员都拥有全量代码。
1.2 微服务应用 70%
微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制【通常用HTTP资源API】,这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术
解读微服务特点:
1:微服务是一种项目架构思想(风格)2:微服务架构是一系列小服务的组合(组件化与多服务)
3:任何一个微服务,都是一个独立的进程(独立开发、独立维护、独立部署)
4:轻量级通信http协议(跨语言,跨平台) [接口编写]
5:服务粒度(围绕业务功能拆分-
6:去中心化管理
1.3 微服务架构的优势
一般用于大型项目,大企业
1.易于开发和维护
一个微服务只关注一个特定的业务功能,所以它的业务清晰、代码量较少。开发和维护单个微服务相对比较简单,整个应用是由若干个微服务构建而成,所以整个应用也会维持在可控状态;部署麻烦——开发人员进行容器化部署【docker】
⒉.单个微服务启动较快
单个微服务代码量较少,所以启动会比较快;
3.局部修改容易部署
单体应用只要有修改,就要重新部署整个应用,微服务解决了这样的问题。一般来说,对某个微服务进行修改,只需要重新部署这个服务即可;
4.技术栈不受限
在微服务中,我们可以结合项目业务及团队的特点,合理地选择技术栈.
5.按需伸缩
购物车---->购物车这个系统集群搭建
1.4 微服务架构的缺点,即挑战
这么多小服务,如何管理他们?
这么多小服务,他们之间如何通讯?
这么多小服务,客户端怎么访问他们?
这么多小服务,一旦出现问题了,应该如何自处理?
这么多小服务,一旦出现问题了,应该如何排错?
相应的组件可以解决上面的相应的挑战。----把这些组件和在一起称为springcloud
1.5 SpringCloud与微服务的关系
-
Springcloud为微服务思想提供了完美的解决方案
-
Springcloud是一些列框架的集合体(服务的注册与发现【注册中心】、服务间远程调用、服务降级、服务熔断、服务限流、分布式事务等)
-
springcloud就是一系列框架的集合,为了解决微服务的挑战。
springcloud有两个版本: springcloud netflix [停止更新] 和springcloud alibaba。
1.6 SpringCloud和SpringBoot的关系
- SpringBoot专注于快速方便的开发单个个体微服务。
- SpringCloud是关注全局的微服务协调、整理、治理的框架,它将SpringBoot开发的单体整合并管理起来。
- SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系
2. 如何搭建微服务框架
- 案例,如图示
创建一个商品微服务,一个订单微服务,通过购买添加订单
2.1 创建一个父工程并引入依赖
父工程仅创建一个maven工程即可
- 引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>springcloud_common</module>
<module>springcloud_product</module>
<module>springcloud_order</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<!--修改版本-->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zmq</groupId>
<artifactId>spring_cloud_parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--只要是父工程打包方式都是pom,可以把src目录删除-->
<!--因为父工程不负责代码编写,只负责子工程的管理-->
<packaging>pom</packaging>
<name>spring_cloud_parent</name>
<description>spring_cloud_parent</description>
<!-- 定义版本号 -->
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- springcloud的版本 -->
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
<!-- 阿里巴巴的版本 springboot springcloud springcloudalibaba 他们的版本必须对应
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
-->
<spring-cloud-alibaba.version>2.2.8.RELEASE</spring-cloud-alibaba.version>
</properties>
<!--
dependencyManagement: 只负责jar的管理不负责jar的下载。
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
可以选择将
src
目录删除在pom文件中添加打包方式为
pom
只要是父工程打包方式都是pom
添加相关依赖
相关依赖的版本有对应要求,在下面网址可以查看对应关系——SpringCloud、SpringCloud Alibaba、SpringBoot三者之间
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
2.2 创建一个公共模块
直接在父工程下创建模块即可
公共模块包含工具类、公共实体类【R】、实体类等
- 依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4</version>
</dependency>
</dependencies>
- 商品实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tbl_product")
public class Product {
@TableId(type= IdType.AUTO)
private Integer pid;
private String pname;
private BigDecimal price;
private Integer stock;
}
- 订单实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tbl_order")
public class Order {
@TableId(type = IdType.AUTO)
private Integer id;
private String orderNo;
private Integer productId;
private BigDecimal price; //因为double存在精度丢失问题
private String pname;
private Integer num;
private Integer userid;
private Integer status;
//订单创建时间--Date存在线程安全问题--默认按照驼峰命名
private LocalDateTime createTime;
}
- 价格使用BigDecimal类型,因为double存在精度丢失问题
- 时间类型使用LocalDateTime类型,因为Date存在线程安全问题
- mybatis-plus默认按照驼峰命名,以
_
为依据
2.3 创建商品微服务
直接在父工程下创建模块即可
- 引入依赖
<dependencies>
<!--公共依赖-->
<dependency>
<groupId>com.ykq</groupId>
<artifactId>qy174-springcloud-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--数据库的依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--springboot-web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 创建配置文件application.properties
# 商品微服务的端口8001~8009
server.port=8001
# 起服务名
spring.application.name=product
# 数据源
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud-product?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#mysql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis映射文件
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
- 在
com.zmq
下创建主启动类
@SpringBootApplication
@MapperScan("com.ykq.product.mapper")
public class ProductApp {
public static void main(String[] args) {
SpringApplication.run(ProductApp.class,args);
}
}
- mapper接口
public interface ProductMapper extends BaseMapper<Product> {
}
- service接口
public interface ProductService {
//根据商品id搜索商品
public Product getById(Integer pid);
}
- service接口实现类
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
@Override
public Product getById(Integer pid) {
Product product = productMapper.selectById(pid);
return product;
}
}
- controller持久类
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/getById/{pid}")
public Product getById(@PathVariable Integer pid) {
Product product = productService.getById(pid);
return product;
}
}
2.4 创建订单微服务
- 引入依赖
<dependencies>
<!--引入公共依赖-->
<dependency>
<groupId>com.zmq</groupId>
<artifactId>springcloud_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--数据库的依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--springboot-web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入糊涂工具,便于调用雪花算法创建唯一的订单编号-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
</dependencies>
引入
hutool-all
工具是为了使用雪花算法,生成唯一的订单编号
- 创建application.properties配置文件
#端口号
server.port=9001
#服务名
spring.application.name=order
#数据源
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud_order?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
#mysql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis映射文件
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
- 在
com.zmq
包下创建启动类
@SpringBootApplication
@MapperScan("com.zmq.mapper")
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class,args);
}
}
- mapper接口
@Repository
public interface OrderMapper extends BaseMapper<Order> {
}
- service接口
public interface OrderService {
//添加订单
public Order createOrder(Order order);
}
- service接口实现类
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Override
public Order createOrder(Order order) {
orderMapper.insert(order);
return order;
}
}
- controller控制类
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private RestTemplate restTemplate;
@PostMapping("/saveOrder")
public Order saveOrder(Integer pid, Integer num) {
Order order = new Order();
order.setOrderNo(IdUtil.getSnowflakeNextIdStr());//订单编号: 时间戳+随机数 雪花算法: 生成一个唯一的id
order.setNum(num);
order.setStatus(0);
order.setCreateTime(LocalDateTime.now());
order.setUserid(1);
order.setProductId(pid);
//根据商品id查询商品信息---远程调用商品微服务的接口。
// 基于Http协议调用。[1]可以自己封装HttpClient工具类【适合所有场景】 [2] spring框架提高了一个HttpClient的工具类【适合spring工程】RestTemplate。
//String url, Class<T> responseType, Object... uriVariables
Product product = restTemplate.getForObject("http://localhost:8001/product/getById/" + pid, Product.class);
if(product==null||product.getStock()<num){
throw new RuntimeException("商品不存在或库存不足");
}
order.setPname(product.getPname());
order.setPrice(product.getPrice());
Order order1 = orderService.createOrder(order);
return order1;
}
}
- config配置类
@Configuration
public class RestConfig {
@Bean //把方法的返回对象交于spring容器管理
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
远程调用商品微服务的接口——基于HTTP协议调用
两种实现方式
- 可以自己封装HttpClient工具类【适合所有场景】
- spring框架提高了一个HttpClient的工具类【适合spring工程】——RestTemplate
RestTemplate是一个执行HTTP请求的同步阻塞式工具类,它仅仅只是在 HTTP 客户端库(例如 JDK HttpURLConnection,Apache HttpComponents,okHttp 等)基础上,封装了更加简单易用的模板方法 API,方便程序员利用已提供的模板方法发起网络请求和处理,能很大程度上提升我们的开发效率