1.什么是SpringCloud以及与SpringBoot的关系
SpringCloud是一系列框架的有序集合。SpringBoot为SpringCloud提供了代码实现环境,使用SpringBoot将其他组合有机融合到了SpringCloud的体系中了。所以说,SpringCloud是基于SpringBoot的微服务系统架构的一站式解决方案。
2.SpringCloud版本与SpringBoot版本关系
上面这个链接可以查看版本关系,必须对应版本才能正常启动
3.普通提供者消费者模式
1.创建提供者
我们新建一个模块,作为提供者。
添加上一些基本依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
我们在测试时使用jpa访问数据库,底层使用hibernate。
然后随便声明一个类,因为要使用jpa,所以使用@Entity声明这是一个实体对象,并使用@Id声明主键,使用@GeneratedValue(strategy = GenerationType.IDENTITY)说明主键自动递增(跟随数据库主键),@JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "fieldHandler"})说明忽略hibernate默认的延迟加载(因为如果不忽略,每次都是延迟加载的属性,如果没有查的属性则会返回空对象,导致返回给消费者时会封装数据失败)
@Data
@Entity
// 忽略延迟加载机制
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "fieldHandler"})
public class Depart {
// id跟随数据库主键,自动递增
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
}
创建一个接口,需要实现JpaRepository并设置两个泛型,第一个是实体类,第二个是主键的类型
public interface DepartRepository extends JpaRepository<Depart, Integer> {
}
定义service接口
public interface DepartService {
boolean saveDepart(Depart depart);
boolean removeDepartById(int id);
boolean modifyDepart(Depart depart);
Depart getDepartById(int id);
List<Depart> listAllDeparts();
}
定义serviceImpl
@Service
public class DepartServiceImpl implements DepartService {
@Autowired
private DepartRepository repository;
@Override
public boolean saveDepart(Depart depart) {
Depart obj = repository.save(depart);
if(obj != null){
return true;
}
return false;
}
@Override
public boolean removeDepartById(int id) {
if(repository.existsById(id)){
repository.deleteById(id);
return true;
}
return false;
}
@Override
public boolean modifyDepart(Depart depart) {
Depart obj = repository.save(depart);
if(obj != null){
return true;
}
return false;
}
@Override
public Depart getDepartById(int id) {
if(repository.existsById(id)){
return repository.getById(id);
}
Depart depart = new Depart();
depart.setName("no this depart");
return depart;
}
@Override
public List<Depart> listAllDeparts() {
return repository.findAll();
}
}
创建controller类,这里为了便于后期查看请求,直接将请求路径更直观书写出来
@RequestMapping("/provider/depart")
@RestController
public class DepartController {
@Autowired
private DepartService service;
@PostMapping("/save")
public boolean saveHandle(@RequestBody Depart depart){
return service.saveDepart(depart);
}
@DeleteMapping("/del/{id}")
public boolean deleteHandle(@PathVariable int id){
return service.removeDepartById(id);
}
@PutMapping("/update")
public boolean updateHandle(@RequestBody Depart depart){
return service.modifyDepart(depart);
}
@GetMapping("/get/{id}")
public Depart getHandle(@PathVariable int id){
return service.getDepartById(id);
}
@GetMapping("/list")
public List<Depart> listHandle(){
return service.listAllDeparts();
}
}
编写配置文件
server:
port: 8081
spring:
jpa:
# 指定是否在Spring容器启动时创建表,默认为false
generate-ddl: true
# 指定是否在控制台显示SQL语句,默认false
show-sql: true
# 指定应用重启时不重新更新表
hibernate:
ddl-auto: none
# 配置数据源
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///duolaimi?useUnicode=true&useSSL=false&characterEncoding=utf8
username: root
password: root
# 配置日志
logging:
# 控制台日志的输出格式
pattern:
console: level-%level %msg%n
level:
root: info
# 控制hibernate运行时的日志级别
org.hibernate: info
# 控制自己的代码运行时显示的日志级别
com.duolaimi: debug
# 在show-sql为true时显示SQL中的动态参数值
org.hibernate.type.descriptor.sql.BasicBinder: trace
#在show-sql为true时显示查询结果
org.hibernate.type.descriptor.sql.BasicExtractor: trace
这里主要配置了端口信息、jpa配置、数据源信息、日志格式及信息。
2.创建消费者
注入restTemplate
@Configuration
public class DepartConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
在控制器中注入restTemplate后即可调用方法
@RequestMapping("/consumer/depart")
@RestController
public class DepartController {
@Autowired
private RestTemplate template;
private static final String SERVICE_PROVIDER = "http://localhost:8081/provider/depart";
@PostMapping("/save")
public boolean saveHandle(@RequestBody Depart depart){
String url = SERVICE_PROVIDER + "/save";
return template.postForObject(url, depart, Boolean.class);
}
@GetMapping("/get/{id}")
public Depart getHandle(@PathVariable int id){
String url = SERVICE_PROVIDER + "/get/" + id;
return template.getForObject(url, Depart.class);
}
}
测试是否成功
4.普通提供者消费模式的问题
只能提供者与消费者一对一,如果出现提供者宕机,则消费者就再也访问不到了。
如何解决?
在springcloud中使用注册中心解决
5.注册中心
所有提供者将自己提供服务的名称及自己主机详情(IP、端口、版本等)写入到另一台主机中的一个列表中,这台主机称为服务注册中心,而这个表称为服务注册表。
所有消费者需要调用微服务时,其会从注册中心首先将服务注册表下载到本地,然后根据消费者本地设置好的负载均衡策略选择一个服务提供者进行调用。这个过程称为服务发现。
可以充当SpringCloud服务注册中心的服务器很多,如Zookeeper、Eureka、Consul等。Spring Cloud Alibaba中使用的注册中心为Alibaba的中间件Nacos。
6.Nacos
1.简介
一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
在windows环境中只要双击运行即可,默认端口是8848,默认账号密码是nacos/nacos
2.如何启动nacos?
因为现在是windows环境操作,所以在naocs的bin目录下,输入如下命令
startup.cmd -m standalone
其中参数-m表示模式,standalone表示单机模式启动,因为默认是集群模式启动,我们现在没有集群
注意,这里nacos版本的选择很重要,如果与springcloudAlibaba的版本不对应,则可能无法启动。
跟踪pom文件查看到,我当前使用的alibaba的版本是2021.0.4.0,最低需要nacos2.0.4,所以客户端需要2.0.4及以上版本才行。
3.使用nacos作为注册中心
我们参照官网设定好版本以及springcloud依赖和springcloudAlibaba的依赖
<properties>
<java.version>8</java.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version>
</properties>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
注意:这里nacos的坐标,中间有starter
然后添加配置信息:
spring:
# 微服务名称
application:
name: depart-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos注册中心地址
username: nacos
password: nacos
这里的配置信息主要是说明服务名称,nacos服务注册发现的地址,用户名和密码
注册成功后,我们可以在服务列表中找到刚刚注册的服务
我们将提供者和消费者都注册到注册中心中,然后使用负载均衡的方式来请求服务
这里,我们请求的服务地址不直接写死ip和端口,而是通过服务名代替。这里会自动查询nacos的ip和端口进行负载均衡。
但是要让他使用负载均衡,还有两点注意项:
1.配置restTemplate的时候,需要使用注解声明请求地址需要负载均衡
@Configuration
public class DepartConfig {
@LoadBalanced // 以负载均衡方式调用
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2.添加上loadbalance的pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
因为2+版本的nacos默认不使用ribbon做负载均衡了(低版本默认使用ribbon做负载均衡,就可以不用引入这个依赖)
如何获取nacos的一些信息?
可以注入DiscoveryClient对象,然后里面有很多查询信息的方法,如查看所有的服务
@Autowired
private DiscoveryClient client;
4.nacos的注册表缓存
服务在启动后,当发生调用时会自动从Nacos注册中心下载并缓存注册表到本地。所以,即使Nacos发生宕机,会发现消费者仍然是可以调用到提供者的。只不过此时已经不能再有服务进行注册了,服务中缓存的注册列表信息无法更新。
5.临时实例和持久实例
临时实例和持久实例的实例存储位置与健康检测机制是不同的
- 临时实例:默认情况。服务实例仅会注册在Nacos内存,不会持久化到Nacos磁盘。其健康检测机制为Client模式,即Client主动向Server上报其健康状态。默认心跳间隔为5秒。在15秒内Server未收到Client心跳,则会将其标记为“不健康”状态;在30秒内若收到了Client心跳,则重新恢复“健康”状态,否则该实例将从Server端内存清除。
- 持久实例:服务实例不仅会注册到Nacos内存,同时也会被持久化到Nacos磁盘。其健康检测机制为Server模式,即Server会主动去检测Client的健康状态,默认每20秒检测一次。健康检测失败后服务实例会被标记为“不健康”状态,但不会被清除,因为其是持久化在磁盘的。
默认情况是临时实例,如何设置成持久实例呢?
我们在配置文件中在如上位置,ephemeral属性设置为false(ephemeral:临时的)
注意:原来注册过临时实例的服务不能再被注册为持久实例,因为磁盘上有保存了部分临时实例的信息,除非重新改名,弄一个新的服务。
6.如何将数据持久化到外置mysql
修改nacos的配置文件:
开启如下配置:
设置自己nacos的连接地址,用户名和密码。
前提是要先执行nacos提供的数据库即表
数据库名我们可以指定为nacos_config。
7.nacos集群搭建
比如说我们创建三个集群环境,需要在每个nacos里面设置集群配置信息,集群配置信息三个保持一致,但是端口不一样,而且三个的地址必须是真实ip,不能是localhost或者127.0.0.1,端口号不能连续,因为系统启动时还要额外占用连续的端口号。
注意,双击打开时,默认集群环境并且是指定外部数据源的(mysql),如果想要使用内嵌数据库,则需要输入命令:startup.cmd -p embedded来指定使用内嵌数据库启动。
如果是集群模式开启的,则在代码连接配置中,需要指定多个集群端口:
8.nacos的CAP模式
CAP原则:
- C(Consistency):一致性
- A(Available):可用性
- P(Partition tolerance):分区容错性
默认情况下,nacos discovery集群的数据一致性采用的是AP(临时实例)模式。但也支持CP(持久实例)模式。若要转换为CP的,可以提交如下PUT请求,完成AP到CP的转换。
9.数据模型
nacos中的服务是由三元组唯一确定的:namespace、group与服务名称service。namespace与group的作用是相同的,用于划分不同的区域范围,隔离服务。namespace的默认值为public(公共命名空间为public,但是值默认为空串),group的默认值为DEFAULT_GROUP。
在配置文件中配置group和namespace属性即可
注意,这里的namespace必须是id值才能正常分配。
10.使用nacos作为配置中心
nacos配置中心概述:
集群中每一台主机的配置文件都是相同的,对配置文件的更新维护就成为了一个棘手的问题。此时就出现了配置中心,将集群中每个节点的配置文件交由配置中心统一管理。相关的产品很多,例如Spring Cloud Config、Zookeeper、Apollo、Disconf等。但Spring Cloud Alibaba官方推荐使用Nacos作为微服务的配置中心。
11.常见配置中心原理
spring cloud config:
其存在三大问题:
- 无法自动感知更新
- 存在羊群效应(跟风效应)
- 系统架构过于复杂
Apollo:
其Config Client可以自动感知配置文件的更新。但也存在两个不足:
- 系统架构复杂
- 配置文件支持类型较少,其只支持xml、text、properties,不支持json、yml
nacos配置中心:
- Config Client通知自动感知配置中心中相应配置文件的更新
- 架构简单
- 支持的配置文件类型较多(支持JSON与YML)
zookeeper配置中心:
zookeeper作为配置中心,其工作原理与前面的三种都不同。其没有第三方服务器去存储配置数据,而是将配置数据存放在自己的Znode中了。当配置中心中的配置数据发生了变化,ConfigClient也是可以自动感知到的(Watcher监听机制)。
12.一致性问题
- 配置中心:配置中心的配置数据一般都是持久化在第三方服务器的,例如DBMS、Git远程库等。由于这些配置中心Server中根本就不存放数据,所以它们的集群中就不存在数据一致性问题。但像Zookeeper,其作为配置中心,配置数据是存放在自己本地的,所以该集群中的节点是存在数据一致性问题的。Zookeeper集群对于数据一致性采用的是CP模式。
- 注册中心:作为注册中心,这些Server集群间是存在数据一致性问题的,他们采用的模式是不同的。Zookeeper(CP)、Eureka(AP)、Consul(AP)、Nacos(默认AP,也支持CP)
13.使用nacos作为配置中心具体操作
1.引入nacos配置中心依赖坐标
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2.在配置中心加入以下配置:
这样默认就会在配置中心中找depart-consumer.yml(默认命名空间、默认分组)
3.启动报错问题处理
单单这样配置启动的话,会提示以上错误,需要额外在配置文件中添加如下配置
最后,如果要开启动态更新配置,则需要在使用的类上加上@RefreshScopezhu
14.配置文件的扩展知识
1.共享配置文件:
以上两种方式都能实现共享配置,就是获取的配置文件不一定是spring.application.name里面的,但是共享的前提是需要在一个组里面
2.扩展配置
如果不是在一个组里面,可以使用扩展配置:extension-config
配置文件的加载顺序为:共享配置,扩展配置,当前服务配置。
若在三个配置中具有相同的属性设置,但他们具有不同的值,那么,后加载的会将先加载的给覆盖。
15.配置隔离
可以使用如下配置进行配置隔离:group和namespace
7.OpenFeign与负载均衡
1.OpenFeign简介
使用RestTemplate会将请求的url写死,显得不美观也不优雅。而OpenFeign可以将提供者提供的Restful服务伪装为接口进行消费,消费者只需使用“feign接口+注解”的方式即可直接调用提供者的Restful服务,而无需再使用RestTemplate。
2.OpenFeign与Ribbon
OpenFeign具有负载均衡功能,其可以对指定的微服务采用负载均衡方式进行消费、访问。之前老版本SpringCloud所集成的OpenFeign默认采用了Ribbon负载均衡器。但由于Netflex已不再维护Ribbon,所以从SpringCloud2021.x开始集成的OpenFeign中已彻底丢弃Ribbon,而是采用SpringCloud LoadBalancer作为负载均衡器。
3.使用OpenFeign
1.导入坐标:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.添加feign接口
@FeignClient(value = "depart-provider", path = "/provider/depart")
// 注意,新版不能使用下面这个注解了,老版本可以
// @RequestMapping("/provider/depart")
public interface DepartService {
@PostMapping("/save")
boolean saveDepart(@RequestBody Depart depart);
@DeleteMapping("/del/{id}")boolean removeDepartById(@PathVariable("id")int id);
@PutMapping("/update")
boolean modifyDepart(@RequestBody Depart depart);
@GetMapping("/get/{id}")Depart getDepartById(@PathVariable("id")int id);
@GetMapping("/list")
List<Depart> listAllDeparts();
}
这个接口上需要添加@FeignClient注解,并指定需要调取的服务名,这里可以指定通用前缀。
3.原来用template的地方,直接注入feign的接口进行调用即可
4.在启动类上需要加上@EnableFeignClients注解
如果不加这个注解,就无法识别@FeignClient接口(猜想加完这种@EnableXxx之后,会将对应注解的类或接口的实现类啥的加入spring容器中)
4.OpenFeign的超时设置
在以上配置中,在config下,如果是default,则是全局设置,如果是指定微服务名称,则是指定的设置。
5.OpenFeign的压缩设置
注意,这里为什么需要设置最小的请求大小呢?如果是很小的文件,反而会是越压越大的。
6.高版本设置负载均衡策略
以上代码基本固定,唯一要改的就是你指定策略的时候,new的对象会不同。
先声明一个类,也不需要使用注解声明这是配置类,只要使用@Bean将策略对象返回即可,然后启动类上需要加上@LoadBalancerClients注解,使用defaultConfiguration注解指定刚刚的类即可。
但是springcloud默认的负载均衡是使用loadbalancer的,策略太少,只有轮询和随机,所以正常企业开发会用dubbo比较多。
标签:精通,Java,SpringCloud,配置,nacos,public,depart,id,Depart From: https://blog.csdn.net/weixin_44466906/article/details/137059101