SpringCloud
1. Spring Cloud 是什么?
在学习本课程之前,读者有必要先了解一下 Spring Cloud
Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的开发便利性简化了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。Spring Cloud 并不重复造轮子,而是将市面上开发得比较好的模块集成进去,进行封装,从而减少了各模块的开发成本。换句话说:Spring Cloud 提供了构建分布式系统所需的“全家桶”。
Spring Cloud 现状:
目前,国内使用 Spring Cloud 技术的公司并不多见,不是因为 Spring Cloud 不好,主要原因有以下几点:Spring Cloud 中文文档较少,出现问题网上没有太多的解决方案。
国内创业型公司技术老大大多是阿里系员工,而阿里系多采用 Dubbo 来构建微服务架构。
大型公司基本都有自己的分布式解决方案,而中小型公司的架构很多用不上微服务,所以没有采用 Spring Cloud 的必要性。
但是,微服务架构是一个趋势,而 Spring Cloud 是微服务解决方案的佼佼者,这也是作者写本系列课程的意义所在。
Spring Cloud 优缺点:
其主要优点有:集大成者,Spring Cloud 包含了微服务架构的方方面面。
约定优于配置,基于注解,没有配置文件。
轻量级组件,Spring Cloud 整合的组件大多比较轻量级,且都是各自领域的佼佼者。
开发简便,Spring Cloud 对各个组件进行了大量的封装,从而简化了开发。
开发灵活,Spring Cloud 的组件都是解耦的,开发人员可以灵活按需选择组件。
接下来,我们看下它的缺点:项目结构复杂,每一个组件或者每一个服务都需要创建一个项目。
部署门槛高,项目部署需要配合 Docker 等容器技术进行集群部署,而要想深入了解 Docker,学习成本高。
Spring Cloud 的优势是显而易见的。因此对于想研究微服务架构的同学来说,学习 Spring Cloud 是一个不错的选择。
2. 架构
2.1 集中式架构
优点:
系统开发速度快维护成本低
适用于并发要求较低的系统
缺点:
代码耦合度高,后期维护困难
无法针对不同模块进行针对性优化无法水平扩展
单点容错率低,并发能力差
2.2 分布式服务
优点:
将基础服务进行了抽取,系统间相互调用,提高了代码复用和开发效率
缺点:
系统间耦合度变高,调用关系错综复杂,难以维护
3. SpringCloud入门
3.1 父子工程的创建
3.1.1 创建父工程
【注:父子工程的创建为了演示子模块与子模块之间的调用】
【注:以及子模块如何注册到nacos中】
创建一个springboot的工程作为父工程:【这里的springboot版本使用的是2.4.2】
【注:父工程中可以什么都不用勾选】
【注:注意版本一定要对照】:
构建好后在pom文件中加入版本控制器:
<properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>2020.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version> </properties>
<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>
【注:这只是个父类工程,所以可以将src包删除,当然不删也行】
3.1.2 创建子工程
创建两个子类maven项目:分别为【test-serve】【test-comm】
test-comm项目
【注:此项目为子类特有的公共项目,子类共同具有的都可以放在这个公共模块中】
因为我们要实现两个模块之间的调用,所以这里就以通过订单来查询商品信息
在此项目中添加依赖:
<!-- lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
声明一个商品实体类和一个固定返回格式的Result
Prodect商品实体类:
@Data @AllArgsConstructor @NoArgsConstructor @ToString public class Prodect { private Integer sid; private String sname; private Double price; private Integer snumber; }
Result固定返回格式:
@Data @AllArgsConstructor @NoArgsConstructor public class result { private int code; private String msg; private Object data; }
test-serve项目
【注:此项目用来管理子子类项目】
此项目pom文件依赖需要:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.3.2.RELEASE</version> </dependency>
在此项目中继续创建两个maven子项目:【serve-pro】 //查询商品信息服务模块
在此项目中继续创建两个maven子项目:【serve-order】 //订单查询商品信息服务模块
serve-pro:
在此服务模块中的pom文件加入公共服务模块依赖:
<!-- 注入公共模块依赖--> <dependency> <groupId>com.aaa</groupId> <artifactId>test-comm</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
在此服务模块中的main包下创建java包创建com.aaa包创建controller层创建ProdectController类
main -> java -> com.aaa -> controller -> ProdectController
在ProdectController中:
@RestController public class ProdectController { @RequestMapping("/sep/{sid}") public result SeleProdect(@PathVariable Integer sid){ if(sid == 7){ Prodect prodect = new Prodect(7,"娃哈哈",5.6,20); return new result(200,"查询成功",prodect); }else if (sid == 8){ Prodect prodect = new Prodect(8,"李宁风刃9000",599.0,10); return new result(200,"查询成功",prodect); } Prodect prodect = new Prodect(8,"到特大姐夫700",890.0,15); return new result(200,"查询成功",prodect); } }
【注:为了方便,这里就不连接数据库了,用的是固定数据】
在此项目中继续创建application.properties配置文件修改端口输入:
server.port=8081
在此项目继续创建主启动类:
【注:主启动类一定要在com.aaa包下】
@SpringBootApplication public class ServeProdect { public static void main(String[] args) { SpringApplication.run(ServeProdect.class,args); } }
serve-order:
在此服务模块中的pom文件加入公共服务模块依赖:
<!-- 注入公共模块依赖--> <dependency> <groupId>com.aaa</groupId> <artifactId>test-comm</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
在此服务模块中的main包下创建java包创建com.aaa包创建controller层创建ProdectController类
main -> java -> com.aaa -> controller -> OrderController
在OrderController中:
@RestController public class OrderController { @Autowired private RestTemplate restTemplate; //根据订单号查询商品(模拟) @RequestMapping("/seleor/{eid}") public result SeleOrder(@PathVariable Integer eid){ //通过订单查询模块将参数传递给商品信息模块且将结果返回 result forObject = restTemplate.getForObject("http://localhost:8081/sep/" + eid, result.class); //将返回的结果通过objectMapper中的convertValue()方法转换成商品信息对象 Prodect Object data = forObject.getData(); ObjectMapper objectMapper = new ObjectMapper(); Prodect prodect = objectMapper.convertValue(data, Prodect.class); return new result(200,"商品信息查询成功",prodect); } }
在此项目中继续创建application.properties配置文件修改端口输入:
server.port=8082
在此项目继续创建主启动类:
【注:主启动类一定要在com.aaa包下】
@SpringBootApplication public class ServeOrder { public static void main(String[] args) { SpringApplication.run(ServeOrder.class,args); } @Bean public RestTemplate getrestTemplate(){//这个是为了可以将两个服务模块之间的调用 return new RestTemplate(); } }
3.2 nacos模块注册
这个需要软件nacos软件来启动服务
所需nacos百度云链接:https://pan.baidu.com/s/1uG2t3Mzbnp8T13ZTFegMkQ 提取码:6666
【注:这个可以在windowns中直接解压】
解压后进入目录中的bin目录
在此目录中进入cmd:
输入:
startup.cmd -m standalone
来启动nacos
浏览器输入 localhost:8848
首先会进入登录页面
账号和密码都是nacos
登录进入
直接点击此处发现是空很正常
这里需要对子服务模块进行nacos配置才会注册进来
需要在【test-serve项目】中添加所需nacos依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在所需要注册的服务模块中的application配置文件中配置:
serve-pro:
在此服务模块中的application配置文件中配置:
spring.application.name=prodect #设置注册中心的地址 spring.cloud.nacos.discovery.server-addr=localhost:8848
在所需要注册的服务模块中的application配置文件中配置:
serve-order:
在此服务模块中的application配置文件中配置:
spring.application.name=order #设置注册中心的地址 spring.cloud.nacos.discovery.server-addr=localhost:8848
全部配置完后serve-po、serve-order 两个子模块需启动,如果已经启动需要重启
再次进入nacos网页刷新:
测试成功,两个子服务模块已经注册进来!!
4. 负载均衡
4.1 自定义策略
【注:这个已经过时,但是还是要简单测试一下】
在test-serve项目下将serve-pro子服务模块复制一份为serve-po2
在serve-po2下修改一下application配置文件:
server.port=8083
【注:这里只修改端口就行】
再次到ProdectController中:小修改一下代码以便一会测试区分:
到test-serve项目下的pom文件中添加负载均衡所需依赖
//负载均衡 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
到serve-order子服务模块下的OrderController中:
@RestController public class OrderController { @Autowired private RestTemplate restTemplate; //将负载均衡注入 @Resource private LoadBalancerClient loadBalancerClient; //根据订单号查询商品(模拟) @RequestMapping("/seleor/{eid}") public result SeleOrder(@PathVariable Integer eid){ //负载均衡 ServiceInstance prodect1 = loadBalancerClient.choose("prodect"); String host = prodect1.getHost(); int port = prodect1.getPort(); String url = "http://"+host+":"+port+"/sep/"+eid; result forObject = restTemplate.getForObject(url, result.class); Object data = forObject.getData(); ObjectMapper objectMapper = new ObjectMapper(); Prodect prodect = objectMapper.convertValue(data, Prodect.class); return new result(200,"商品信息查询成功",prodect); } }
4.2 OpenFeign
4.2.1 OpenFeign策略(轮询算法)
到test-serve项目下的pom文件中添加openfeign所需依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
在调用者的主启动类上加上:
@EnableFeignClients
注解
这里serve_order模块属于调用者,所以在其主启动类上加上开启OpenFeign注解
【注:serve_order是订单模块,serve_po是商品信息模块,以订单查询商品信息,所以serve_order是调用者一方】
在serve_order模块下的com.aaa包下创建feign包中创建ProdectServiceFeign接口类
serve_order -> com.aaa -> feign -> ProdectServiceFeign
@FeignClient("prodect") public interface OrderService { @RequestMapping("/sep/{eid}") public result getSeleOrder(@PathVariable Integer eid); }
在serve_order模块下的OrderController类中:
@RestController public class OrderController { //将刚才写好的Serveice接口注入进来 @Autowired private OrderService orderService; //根据订单号查询商品(模拟) @RequestMapping("/seleor/{eid}") public result SeleOrder(@PathVariable Integer eid){ //OpenFeign result forObject = orderService.getSeleOrder(eid); Object data = forObject.getData(); ObjectMapper objectMapper = new ObjectMapper(); Prodect prodect = objectMapper.convertValue(data, Prodect.class); return new result(200,"商品信息查询成功",prodect); } }
4.2.2 OpenFeign自定义策略(随机算法)
在serve_order模块下的com.aaa包下创建config包中创建
LoadBalancerConfig
接口类serve_order -> com.aaa -> config->
LoadBalancerConfig
public class LoadBalancerConfig { @Bean ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); //loadbalancer.client.name // 对应的需要进行负载均衡的名字是什么 System.out.println("======"+name); // product return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }
在调用者的主启动类上加上:
@LoadBalancerClient(value = "prodect",configuration = LoadBalancerConfig.class)
注解
这里serve_order模块属于调用者,所以在其主启动类上加上开启OpenFeign注解
【注:serve_order是订单模块,serve_po是商品信息模块,以订单查询商品信息,所以serve_order是调用者一方】
4.3 sentinel
【注:当子服务模块中被调用者其中一个出现异常时,这时我们该如何?】
【注:那么openfeign为我们提供一个兜底策略,就算哪怕子服务模块其中一个出现异常也不会直接向客户返回500这些信息】
到test-serve项目下的pom文件中添加sentinel所需依赖:
<!-- sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
随后在application配置文件中开启openfeign对sentinel的支持
#??openfeign ?sentinel??? feign.sentinel.enabled=true
到serve_order模块下的Serveice层创建一个ProdectServiceim实现类
serve_order -> Service -> ProdectServiceim
@Service public class ProdectService implements OrderService{ @Override public result getSeleOrder(Integer eid) { if (eid == 7){ Prodect prodect = new Prodect(6,"百岁山",5.6,20); return new result(200,"查询成功",prodect); }else if (eid == 8){ Prodect prodect = new Prodect(5,"361度跑鞋",52.6,10); return new result(200,"查询成功",prodect); } return null; } }
【注:这里实现的是4.2.1下写的OrderService接口】
【注:写这个目的为如果子服务模块出现异常,那么sentinel会自动转到这里,从这里代替出异常的服务模块】
那么我们将serve-pro子服务模块下的ProdectController中的内容故意让他报异常进行测试:
运行测试:
两次请求结果皆不报异常,sentinel启动成功
说明sentinel兜底成功!!!
以上便是SpringCloud中的内容,如有漏缺请在下方留言告知,我会及时补充