环境安装
JDK介绍:
Oracle从JDK9开始每半年发布一个新版本,新版本发布后,老版本就不再进行维护。但是会有几个长期维护的版本。
目前长期维护的版本有:
- JDK8
- JDK11
- JDK17
- JDK21
在JDK版本的选择上,尽量选择长期维护的版本。
为什么选择JDK17?
Spring Cloud是基于SpringBoot进行开发的:
- SpringBoot 3.X以下的版本,Spring官方已不再进行维护(还可以继续使用)
- SpringBoot 3.X的版本,使用的JDK版本基线为JDK17
- 鉴于JDK21是2023.09月发布的,很多功能还没有在生产环境验证,所以本课程选择使用JDK17来学习
项目工程介绍
背景:
实现一个电商平台(残次版,仅为演示SpringCloud内容)
拿京东举例,首页上就展示了许多功能。
我们该如何实现呢? 如果把这些功能全部写在⼀个服务⾥,这个服务将是巨⼤的。
巨多的会员,巨⼤的流量,微服务架构是最好的选择。
微服务应⽤开发的第⼀步,就是服务拆分,拆分后才能进⾏”各⾃开发“
服务拆分原则
1.单一职责原则
单一职责原则原本是面向对象设计中的一个基本原则,它指的是一个类应该专注于单一功能,不要存在多于一个导致类变更的原因。
在微服务架构中,一个微服务也应该只负责一个功能或业务领域,每个服务应该有清晰的定义和边界,只关注自己的特定业务领域。
组织团队也是,一个人专注做一件事情的效率远高于同时关注多件事情。
比如一个人同时管理和维护一份代码,要比多个人同时维护多份代码的效率高。
就像电商系统:
2.服务自治
服务自治是指每个微服务都应该具备高度自治的能力,即每个服务要能做到独立开发,独立测试,独立构建,独立部署,独立运行。
以上面的电商系统为例,每一个微服务应该有自己的存储,配置,在进行开发,构建,部署,运行和测试时,并不需要过多关注其他微服务的状态和数据。
⽐如企业管理 每个部分负责每个部⻔的事情, 并且尽可能少的受其他团队影响 研发部⻔只负责需求功能的开发, ⽽不负责需求⽂档的书写和UI的设计. 并且其他部⻔的⼈员变动, 流程变更, 也尽可能少的影响研发部⻔. 部⻔和部⻔之间尽可能⾃治。
这个原则并不是非常严格要求的,还是需要具体场景具体分析的。
3.单项依赖
微服务之间需要做到单项依赖,不能存在循环依赖,双向依赖。
循环依赖: A → B → C → A
双向依赖: A → B , B → A
如果有一些业务场景确实无法避免循环依赖或者双向依赖,可以考虑使用消息队列等其他方式去解决。
<aside> 💡
微服务架构并⽆标准架构, 合适的就是最好的, 不然架构师⼤会也不会各个系统架构百花⻬放 了. 在架构设计的过程中, 坚持 "合适优于业界领先", 避免"过度设计"(为了设计⽽设计). 罗⻢不是⼀天建成的, 很多业界领先⽅案并不是⼀群天才在某个时期⼀下⼦做出来的, ⽽是经 过数年的发展逐步完善. 业界领先的⽅案⼤多是"逼"出来的, 随着业务的发展, 量变导致质变, 新的问题出现了, 当前的⽅案⽆法满⾜需求, 需要⽤新的⽅案来解决. 通过不断的创新和尝试, 业界领先的⽅案才得以形成
</aside>
远程调用
比如说我现在有两个model工程,一个是订单服务(order-service),一个是商品服务(product-service),在订单查询订单信息的时候,根据订单里的产品ID,获取产品的详细信息。
**实现的思路:**order-service服务向product-service服务发送一个http请求,把得到的返回结果和订单融合在一起,返回给调用方。
实现方式: 采用Spring 提供的RestTemplate
实现http请求的方式有很多,可参考:https://zhuanlan.zhihu.com/p/670101467
1. 定义RestTemplate
@Configuration
public class BeanConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2.修改order-service中的OrderService
@Autowired
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public OrderInfo selectOrderById(Integer orderId){
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
String url = "<http://127.0.0.1:9090/product/>" + orderInfo.getProductId();
ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
}
RestTemplate 详细使⽤可参考: RestTemplate 最详解 - 程序员自由之路 - 博客园
RestTemplate(不发)
RestTemplate 是从 Spring3.0 开始⽀持的⼀个 HTTP 请求⼯具, 它是⼀个同步的 REST API 客⼾端, 提供了常⻅的REST请求⽅案的模版。
什么是REST?
REST(Representational State Transfer), 表现层资源状态转移.
REST是由HTTP的主要设计者Roy Fielding博⼠在2000年他的博⼠论⽂中提出来的⼀种软件架构⻛格.
这⾥⾯主要有三个概念:
- 资源: ⽹络上的所有事物都可以抽象为资源, 每个资源都有⼀个唯⼀的资源标识符(URI)
- 表现层: 资源的表现形式, ⽐如⽂本作为资源, 可以⽤txt格式表现, 也可以通过HTML, XML, JSON等 格式来表现, 甚⾄以⼆进制的格式表现.
- 状态转移: 访问URI, 也就是客⼾端和服务器的交互过程. 客⼾端⽤到的⼿段,只能是HTTP协议. 这 个过程中, 可能会涉及到数据状态的变化. ⽐如对数据的增删改查, 都是状态的转移.
REST 是⼀种设计⻛格, 指资源在⽹络中以某种表现形式进⾏状态转移.
简单来说: REST描述的是在⽹络中Client和Server的⼀种交互形式, REST本⾝不实⽤,实⽤的是如何设计 RESTful API(REST⻛格的⽹络接⼝)
什么是RESTful?
REST 是⼀种设计⻛格, 并没有⼀个明确的标准. 满⾜这种设计⻛格的程序或接⼝我们称之为RESTful(从
单词字⾯来看就是⼀个形容词). 所以RESTful API 就是满⾜REST架构⻛格的接⼝.
RESTful ⻛格⼤致有以下⼏个主要特征:
- 资源: 资源可以是⼀个图⽚, ⾳频, 视频或者JSON格式等⽹络上的⼀个实体, 除了⼀些⼆进制的资源 外普通的⽂本资源更多以JSON为载体、⾯向⽤⼾的⼀组数据(通常从数据库中查询⽽得到)
- 统⼀接⼝: 对资源的操作. ⽐如获取, 创建, 修改和删除. 这些操作正好对应HTTP协议提供的GET、 POST、PUT和DELETE⽅法. 换⾔⽽知,如果使⽤RESTful⻛格的接⼝, 从接⼝上你可能只能定位其 资源,但是⽆法知晓它具体进⾏了什么操作,需要具体了解其发⽣了什么操作动作要从其HTTP请 求⽅法类型上进⾏判断
⽐如同⼀个的URL: GET /blog/{blogId}:查询博客 DELETE /blog/{blogId}:删除博客
这些内容都是通过HTTP协议来呈现的. 所以RESTful是基于HTTP协议的.
RestTemplate 是Spring提供, 封装HTTP调⽤, 并强制使⽤RESTful⻛格. 它会处理HTTP连接和关闭, 只需要使⽤者提供资源的地址和参数即可.
RESTful实践
RESTful⻛格的API 固然很好很规范, 但⼤多数互联⽹公司并没有按照其规则来设计, 因为REST是⼀种⻛ 格,⽽不是⼀种约束或规则, 过于理想的RESTful API 会付出太多的成本. RESTful API 缺点:
- 操作⽅式繁琐, RESTful API通常根据GET, POST, PUT, DELETE 来区分对资源的操作动作. 但是 HTTP Method 并不可直接⻅到, 需要通过抓包等⼯具才能观察. 如果把动作放在URL上反⽽更加直 观, 更利于团队的理解和交流.
- ⼀些浏览器对GET, POST之外的请求⽀持不太友好, 需要额外处理.
- 过分强调资源. ⽽实际业务需求可能⽐较复杂, 并不能单纯使⽤增删改查就能满⾜需求, 强⾏使⽤ RESTful API会增加开发难度和成本.
所以, 在实际开发中, 如果业务需求和RESTful API不太匹配或者很⿇烦时, 也可以不⽤RESTful API. 如果使⽤场景和REST⻛格⽐较匹配, 就可以采⽤RESTful API.
总之: ⽆论哪种⻛格的API, 都是为了⽅便团队开发, 协商以及管理, 不能墨守成规. 尽信书不如⽆书, 尽信规范不如⽆规范.
项⽬存在问题
• 远程调⽤时, URL的IP和端⼝号是写死的, 如果更换IP, 需要修改代码
- 调⽤⽅如何可以不依赖服务提供⽅的IP?
- 多机部署, 如何分摊压⼒?
- 远程调⽤时, URL⾮常容易写错, ⽽且复⽤性不⾼, 如何优雅的实现远程调⽤
- 所有的服务都可以调⽤该接⼝, 是否有⻛险?
除此之外, 微服务架构还⾯临很多问题, 接下来我们学习如何使⽤Spring Cloud 来解决这些问题。