文章目录
一、预备
SpringBoot 的基础入门学习见博客。
如果只会增删改查,很容易被代码生成器取代 😭 。
说几个概念叭:
1、微服务
项目架构随着时间的演进,出现了三个:单体架构 --> SOA【是面向服务的架构,最经典的就是阿里的 Dubbo ,有一个 “中心” 的概念 --> 微服务。微服务具备的特性:
- 每个微服务可独立运行在自己的进程里。
- 一系列独立运行的微服务共同构建起了整个系统。
- 每个服务为独立的业务开发,一个微服务一般完成某个特定的功能,比如:订单管理、用户管理等。
- 微服务之间通过一些轻量的通信机制进行通信,例如通过 REST API 或者 RPC 的方式进行调用。
在 Java 里,可以这样理解:将子系统拆成一个一个的 jar 包运行就是微服务 😁。
2、缓存
缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。
缓存就是数据交换的缓冲区 Cache,当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。 由于缓存的运行速度比内存快得多,故缓存的作用就是帮助硬件更快地运行。
因为缓存往往使用的是 RAM(断电即掉的非永久储存),所以在用完后还是会把文件送到硬盘等存储器里永久存储。电脑里最大的缓存就是内存条了,最快的是 CPU上镶的 L1 和 L2 缓存,显卡(就是个显示图形的东东)的显存是给显卡运算芯片用的缓存,硬盘上也有 16M 或者 32M 的缓存。
比如说,用过的数据库里,Redis 是基于 内存 的,读写速度快,也可做持久化(等会儿会讲到 “持久化” ),但是内存空间有限,当数据量超过内存空间时,需扩充内存,但内存价格贵。
MySQL 基于磁盘 ,读写速度没有 Redis 快,但是不受空间容量限制,性价比高。
大多数的应用场景是 MySQL 主 +Redis 辅 ,MySQL 做为主存储,Redis 用于缓存,加快访问速度。需要高性能的地方使用 Redis,不需要高性能的地方使用 MySQL。存储数据在 MySQL 和 Redis 之间做同步。
3、通用Mapper 和 PageHelper
通用 Mapper 是 MyBatis 动态SQL 的封装包,用于增删改查,这样可以不用写 SQL 语句啦;PageHelper 是实现分页操作的,之前可以用 MyBatis 的 limit 实现分页操作,而有了 PageHelper ,只需要调用一个静态方法,把页码和每页显示多少条记录传进去,就可以自动分页。
4、持久化
狭义的理解,“持久化” 仅仅指把域对象永久保存到数据库中;广义的理解,“持久化” 包括和数据库相关的各种操作(持久化 就是 将有用的数据以某种技术保存起来,将来可以再次取出来应用,数据库技术,将内存数据以文件的形式 保存在永久介质中(磁盘等)都是持久化的例子)。
为什么要进行持久化呢?
- 通过持久化技术 可以减少访问数据库数据次数,增加应用程序执行速度;
- 代码重用性高,能够完成大部分数据库操作;
- 松散耦合,使持久化不依赖于底层数据库和上层业务逻辑实现,更换数据库时只需修改配置文件而不用修改代码。
电商行业的技术需要 新、范围广、分布式、高并发、集群、负载均衡、高可用、海量数据、业务复杂、系统安全。
5、电商模式
- B2B:Business to Business ,进行电子商务交易的供需双方都是商家(或企业、公司),他们使用了互联网的技术或者各种商务网络平台,完成商务交易的过程。比如 阿里巴巴。
- C2C:Consumer to Consumer,消费者个人之间的电子商务行为,比如消费者有一台电脑,通过网络交易,把它出售给另一个消费者。比如 淘宝,瓜子二手车。
- B2C:Business to Consumer,商对客, 直接面向消费者销售产品和服务业零售模式,比如 唯品会。
- C2B:Consumer to Business,消费者到企业,先有消费者需求产生,而后 企业生产,也就是说,先有消费者提出要求,然后生产企业按需求组织生产。比如 海尔商城。
- O2O:Online to Offline,在线离线/线上到线下,是指将线下的商务机会与互联网结合,让互联网成为线下交易的平台,既可涉及线上,又可以涉及线下。比如 美团。
- F2C:Factory to Consumer,从厂商到消费者。
- B2B2C:电子商务类型的网络购物商业模式,第一个 B 是指商品 或 服务的供应商,第二个 B 是从事电子商务的企业,C 是消费者,比如 京东商城 天猫商城。
我们现在要搭的微服务商城系统采用 B2C 模式。
页面预览
首页预览图:
搜索页面预览图:
商品详情页预览图:
(商品详情页因为数据变化的频率较低 ,但是访问量较高,所以需要使用的是静态页,提高扛并发能力,由 Thymeleaf生成。)
结算页预览图:
微信支付页预览图:
二、系统设计
这个商城属于 B2C 电商模式,运营商将自己的产品发布到网站上,会员注册后,在网站上将商品添加到购物车,并且下单,完成线上支付,用户还可以参与秒杀抢购。
网站采用前后端分离的方式,前端部分需要比如 Vue.js、NPM、webpack【打包工具】、Node.js【实现数据实时采集、分析】;后端部分需要比如 各大微服务的功能实现,通过 Swagger API 文档进行交互,这个文档是通过代码生成器一键生成的。具体的前端技术有 Vue.js、Node.js、Lua【编写软件插件,在本系统中用来实现缓存的更新操作】、Html5、ElementUI、Thymeleaf;运维技术有 Canal、Docker 容器部署、FastDFS、Eureka集群、Redis集群、Elasticsear集群;微服务技术栈有 SpringBoot、OAuth2.0【实现权限操作】、JWT【实现授权】、Spring AMQP【AMQP 是通信协议,可以进行异步通信】、SpringCloud;持久化技术有 Mybatis+通用 Mapper、SpringDataEs【操作Es索引库】、SpringDataRedis;数据库和消息队列有 MySQL、RabbitMQ、MySQL 读写分离;支付接口使用微信支付。
从架构图可以看到:
客户端要访问后台,需要先经过服务器的路由器,接下来,Nginx 用来负载均衡、限流,它可以扛 5w 并发(已经很高啦),Keepalived 是虚拟路由器,VIP 是虚拟 IP,路由器访问的是虚拟 IP,会绑定到虚拟路由器,虚拟 IP 只有一个,而 用户每次请求却不只是到一个路由器上,不是图示的上面的那个路由器,就是图示的下面的那个路由器,虚拟 IP 和 虚拟路由器是用来解决 Nginx 单点故障的问题的。
接下来,到了 Gateway 微服务网关,主要将用户请求路由到不同的微服务中去,微服务网关具有路由、限流、权限校验的作用,它需要由服务器(比如 Tomcat)发布,它能为后台的各个微服务提供保护,避免造成过大的压力。一个服务使用一个网关,网关最后要集群的。
接下来,就到了各个微服务,微服务之间通过 Feign 进行相互调用,这里可能会涉及到分布式事务。
三、框架搭建
1、环境准备
(1)VMWare Workstation Pro 安装 CentOS 7 镜像,联网步骤记录见 https://blog.csdn.net/weixin_41750142/article/details/111600095
(2)使用 MobaXterm 新建 SSH Session,连接虚拟机:
看看 Docker 安装的镜像:
看看 MySQL 里的数据库:
在 Navicat Premium 中新建连接:
来看看数据库:
2、项目结构介绍
整个项目结构是这样的:
可以看到, common 是工具类;common-db 是数据库连接会依赖的包;gateway 是网关;(网关的作用是实现路由管理,每个服务会有一个网关,微服务网关会集群,集群扛并发。)eureka 是注册中心;service 存放各个微服务工程,增删改查都是在这里的;service-api 是存放 Java Bean 和 feign 的,web 是做模板渲染工程的。整个项目结构符合 RESTFUL 风格,通过 json 进行交互。
3、公共工程搭建
(1)父工程搭建
先创建父工程 changgou-parent:
父工程是不需要写代码的,可以把 src 删除掉。因为之后需要用到 SpringBoot,所以把它的依赖导进来,父工程的 pom.xml :
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.changgou</groupId>
<artifactId>changgou-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<description>
畅购商城的父工程
</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!--打包的时候跳过测试-->
<skipTests>true</skipTests>
</properties>
<!--依赖包-->
<dependencies>
<!--鉴权-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!--测试包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
<!--swagger文档 可选的-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!--
http://localhost:9011/swagger-ui.html
-->
</dependencies>
<!--springcloud的版本控制-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
以下 5 个 公共工程打 pom 包,其他本项目中的工程打 jar 包 (默认就是 jar 包)
接下来就在 父工程下新建这 5 个公共工程(都要把 src 包删掉,打 pom 包)。
(2)Eureka 注册中心的搭建
(突然发现 Spring Cloud 0基础是不行的,😅去入了个门,见博客。)
新建 module,导入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
提供配置文件 application.yml:
server:
port: 7001
eureka:
instance:
hostname: 127.0.0.1
client:
register-with-eureka: false # 是否将自己注册到注册中心
fetch-registry: false # 是否获取自己信息
service-url:
defaultZone: http://${euraka.instance.host}:${server.port}/eureka/
spring:
application:
name: eureka
提供启动类:
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class,args);
}
}
看看运行结果:
(3)公共模块搭建
以后需要在公共模块中提供一些工具包。(项目搞得好不好 就看工具抽取有多少 🤣。)
新建 module ,名为 changgou-common并导入依赖:
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--微信支付-->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<!--httpclient支持-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
接下来,需要提供一些实体类,比如 加密用的、组件生成(IdWorker 雪花算法)等等,见代码里的 entity 包。
(4)数据访问工程搭建
接下来,需要提供一个 module ,名为 channgou-common-db,把数据库访问需要的包导进来,导入依赖:
<dependencies>
<!--对changgou-common的依赖-->
<dependency>
<groupId>com.changgou</groupId>
<artifactId>changgou-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--通用mapper起步依赖-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
<!--MySQL数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
四、商品微服务工程搭建
接下来我们要实现对数据库 goods 也就是商品 中各个表的增删改查操作。
先准备关于商品各个表映射的 POJO,前面提到过,service-api 是存放 Java Bean 的,所以,POJO 类也可以放在 changgou-service-api (需要导入 javax.persistence 依赖)中,在其中建个 module,名为 changgou-service-goods-api 。
可以看到,和数据库中的表是对应的:
在 changgou-service 中新增 module ,名为 changgou-service-goods ,顺便 channgou-common-db 依赖导入到 changgou-service 中( channgou-common-db 就是为了满足数据库访问的需求呀 ):
<dependency>
<groupId>com.changgou</groupId>
<artifactId>changgou-common-db</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
在 changgou-service-goods 中提供配置文件 application.yml :
server:
port: 18081
spring:
application:
name: goods
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.211.132:3306/changgou_goods?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
提供启动类,使用 开启 Eureka 客户端:
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class,args);
}
}
运行结果:
五、总结
(1) 在 Java 里,可以把微服务理解成 将子系统拆成一个一个的 jar 包运行。
(2)当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。
缓存比内存快,比 CPU 慢。
(3)通用 Mapper 是 MyBatis 动态SQL 的封装包,用于增删改查,都封装好了,所以我们不用自己写 SQL 语句。
PageHelper 是实现分页操作的,之前可以用 MyBatis 的 limit 实现分页操作,而有了 PageHelper ,只需要调用一个静态方法,把页码和每页显示多少条记录传进去,就可以自动分页。
(4)这个商城属于 B2C 电商模式,运营商将自己的产品发布到网站上,会员注册后,在网站上将商品添加到购物车,并且下单,完成线上支付,用户还可以参与秒杀抢购。
(5)整个项目框架中,common 是工具类;common-db 是数据库连接会依赖的包;gateway 是网关;eureka 是注册中心;service 存放各个微服务工程,增删改查都是在这里的;service-api 是存放 Java Bean 和 feign 的,web 是做模板渲染工程的。整个项目结构符合 RESTFUL 风格,通过 json 进行交互。
(6)搭建框架的步骤是 先建立父工程,然后导入依赖,再在各个模块中完善功能。