讲到这个肯定要提到微服务。
那么,什么叫做微服务:
微服务是一种用于构建应用的架构方案。微服务架构有别于更为传统的单体式方案,可将应用拆分成多个核心功能。每个功能都被称为一项服务,可以单独构建和部署,这意味着各项服务在工作(和出现故障)时不会相互影响。
简而言之:就是把一个复杂的项目拆分为多个核心功能,每个功能称之为一项服务。
其实,微服务当中的介绍也顺便说明了为什么需要使用微服务:无论是传统的 Servlet + JSP,还是 SSM,还是现在的 SpringBoot,它们都是单体应用,单体应用的优点很明显,就是简单,快捷,在一些小项目上面很方便。但是当项目大了以后,单体项目的劣势就越来越明显,比如改动影响大、风险高、部署成本高(全部重新部署)、无法快速扩容。
因此,微服务就这样出现了。讲完了微服务,我们再来看下SpringCloud给我们带来的是什么,也就是为什么要使用SpringCloud
Spring Cloud是一个集成了众多开源的框架,利用Spring Boot的开发便利性实现了服务治理、服务注册与发现、负载均衡、数据监控,REST API发布方式等,基本囊括了分布式框架所需要的所有功能。是一套易开放、易部署、易维护的分布式开发工具包。
这里面是一套解决方案:包括了注册中心、服务治理、负载均衡等等一系列的解决方案。
ps:下载地址在文末。
springboot | springCloud | spring Cloud Alibaba |
---|---|---|
2.3.2.RELEASE | Spring Cloud Hoxton.SR8 | 2.2.5.RELEASE |
注意:一定要注意这边的几个版本信息(springboot、springCloud、springCloud Alibaba)。
这里采用的是
管理包。哪个服务中需要使用,哪个服务就引入对应的依赖。这里
只是声明,不做导入。
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.2.RELEASEversion>
<relativePath/>
parent>
<groupId>com.cjgroupId>
<artifactId>cloudartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>cloudname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<spring-cloud.version>Hoxton.SR8spring-cloud.version>
<spring-cloud-alibaba.version>2.2.5.RELEASEspring-cloud-alibaba.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
下面我们还缺少2个服务,这里我就拿用户和订单的关系模型进行说明。
新建一个user子工程:
到现在为止,这边的cloud-user只是单独的项目,和父项目并不存在依赖关系,所以这里我们需要将两者改成有依赖关系
cloud-user的pom文件修改如下:
标签内容改为如下所示:
<parent>
<groupId>com.cjgroupId>
<artifactId>cloudartifactId>
<version>0.0.1-SNAPSHOTversion>
parent>
总的pom文件中增加
标签:
<modules>
<module>cloud-usermodule>
modules>
把CloudUserApplication类修改如下:
/**
* @author cj
*/
@RestController
@SpringBootApplication
public class CloudUserApplication {
public static void main(String[] args) {
SpringApplication.run(CloudUserApplication.class, args);
}
@GetMapping("/helloNacos")
public String helloNacos() {
System.out.println("当前实例------> A");
return "你好,nacos!";
}
}
到这里,其实没有结束,但是我们可以先把cloud-user这个工程启动起来看看效果。可能会有如下的报错,没关系,可以忽略,我们还没有配置对应的nacos注册中心(因为我们pom文件中引入了对应的依赖):
出现如下:
步骤重复一下。
nacos
我这里是下载的1.3.1版本
下载之后进入到bin文件目录,启动项目:
如下图所示启动成功
至此,nacos已经启动成功,我们可以访问地址:http://127.0.0.1:8848/nacos访问nacos的页面。
这边需要关注2个地方:一个是服务管理,也就是服务的注册和发现;一个是配置管理(每个服务的配置中心)
回到工程中,如何将工程配置成一个服务,并且注册到nacos,让其他服务能用使用?
@RestController
@SpringBootApplication
@EnableDiscoveryClient
public class CloudUserApplication {
public static void main(String[] args) {
SpringApplication.run(CloudUserApplication.class, args);
}
@GetMapping("/helloNacos")
public String helloNacos() {
System.out.println("当前实例------> A");
return "你好,nacos!";
}
}
这边需要注意的是:
创建配置文件名为bootstrap.yml,注意是bootstrap,而不是application。
原因如下(详情请查看:配置文件application.yml和bootstrap.yml的配置的不同)
Nacos同springcloud-config一样,在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动。springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application
pom文件内容:
spring:
application:
name: cloud-user
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
file-extension: yml
server-addr: 127.0.0.1:8848
profiles:
active: dev
新建配置中心如图所示:
解释一下:
Data ID它的定义规则是:
${prefix}-${spring.profiles.active}.${file-extension}
prefix 默认为 spring.application.name
的值,也可以通过配置项spring.cloud.nacos.config.prefix
来配置。
spring.profile.active
即为当前环境对应的 profile,可以通过配置项 spring.profile.active
来配置。
file-exetension
为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。
注意:当 spring.profile.active 为空时,对应的连接符 - 也将不存在
dataId 的拼接格式变成${prefix}.${file-extension}
然后对应下之前的yml配置,我们可以看出来,配置的文件名是:cloud-user-dev.yml
如下所示:
这里配置里面增加一个key-value,用来验证工程是否真的读到了配置。
到这里,nacos的配置基本完成,下面,我们就把之前cloud-user代码稍微改下,读取heheda的值:
/**
* @author cj
*/
@RestController
@SpringBootApplication
@EnableDiscoveryClient
public class CloudUserApplication {
public static void main(String[] args) {
SpringApplication.run(CloudUserApplication.class, args);
}
@Value("${heheda}")
private String config;
@GetMapping("/helloNacos")
public String helloNacos() {
System.out.println("当前实例------> A" + config);
return "你好,nacos!";
}
}
log输出:
至此,nacos的注册、发现以及配置中心现在都可以使用了。
需要了解的知识点:
@EnableDiscoveryClient
的使用。按照之前的服务注册和发现还有服务配置中心的说明,我们把cloud-order工程也按照上面步骤写一下。
我们现在想实现一下用户下单的功能。那么首先在cloud-order中新建一个controller,写一个makeOrder的方法:
/**
* 描述:
*
* @author caojing
* @create 2021-02-05-14:15
*/
@RestController
public class OrderController {
@GetMapping("/makeOrder")
public String makeOrder(@RequestParam("name") String userName) {
return userName + "下单成功";
}
}
/**
* @author cj
*/
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class CloudOrderApplication {
public static void main(String[] args) {
SpringApplication.run(CloudOrderApplication.class, args);
}
}
/**
* 描述:
*
* @author caojing
* @create 2021-02-05-14:20
*/
@FeignClient(name = "cloud-order")
public interface OrderRemoteClient1 {
@GetMapping("/makeOrder")
String makeOrder(@RequestParam("name") String userName);
}
注意:这里服务名不区分大小写 cloud-order=CLOUD-ORDER
@Autowired注入
@Autowired
private OrderRemoteClient1 orderRemoteClient1;
@GetMapping("/helloNacos")
public String helloNacos() {
System.out.println("当前实例------> A" + orderRemoteClient1.makeOrder("caojinger"));
return "你好,nacos!";
}
熔断机制:
一般在微服架构中,有一个组件角色叫熔断器。顾名思义,熔断器起的作用就是在特定的场景下关掉当前的通路,从而起到保护整个系统的效果。
在微服务架构中,一般我们的独立服务是比较多的,每个独立服务之间划分责任边界,并通过约定协议接口来进行通信。当我们的调用链路复杂依赖多时,很可能会发生雪崩效应。
假设有这么一个场景,有A, B, C, D四个独立服务,A会依赖B,C,D;当D发生负载过高或网络异常等导致响应过慢或超时时,很可能A会因此堆积过多的等待链接,从而导致A的状态也转为异常,后面依赖到A的其他服务跟着发生链式反应,这将会导致大面积的服务不可用。
新建TestFallBack
类:
@Component
public class TestFallBack implements OrderRemoteClient1 {
@Override
public String makeOrder(String userName) {
return "出错了";
}
}
OrderRemoteClient1
修改如下:
@FeignClient(name = "cloud-order",fallback = TestFallBack.class)
public interface OrderRemoteClient1 {
@GetMapping("/makeOrder")
String makeOrder(@RequestParam("name") String userName);
}
这样一个简单的熔断处理就完成了,为了模拟熔断机制,我们可以把order中的controller抛出异常 :
@GetMapping("/makeOrder")
public String makeOrder(@RequestParam("name") String userName) {
throw new RuntimeException("服务端测试异常!");
// return userName + "下单成功";
}
重新访问地址,这边可以看到 cloud-order模块中抛出了异常,但是在cloud-user中是正常返回,只不过返回的信息是TestFallBack
类中返回的信息,这样我们就可以阻止雪崩效应啦。
feign:
hystrix:
enabled: true
至此一个简单的springcloud项目已经搭建完成,但这样的项目远远没有达到开发的步骤,但万事开头难嘛,只要后续慢慢的完善,不断改进,总能达到开发的水平。
微服务之间的调用真的是这样的么?
楼主这种方式:是调用方来写feignClient还是服务方来写?你觉得应该谁来写?怎么写?
感兴趣的同学可以看下这篇文章:
Fegin在spring Cloud中的实际应用
对应的demo下载:
demo