首页 > 编程语言 >Java从坚持到精通-SpringCloud(持续更新中)

Java从坚持到精通-SpringCloud(持续更新中)

时间:2024-03-30 17:32:45浏览次数:32  
标签:精通 Java SpringCloud 配置 nacos public depart id Depart

1.什么是SpringCloud以及与SpringBoot的关系

SpringCloud是一系列框架的有序集合。SpringBoot为SpringCloud提供了代码实现环境,使用SpringBoot将其他组合有机融合到了SpringCloud的体系中了。所以说,SpringCloud是基于SpringBoot的微服务系统架构的一站式解决方案。

2.SpringCloud版本与SpringBoot版本关系

版本发布说明 | Spring Cloud Alibaba

上面这个链接可以查看版本关系,必须对应版本才能正常启动

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

相关文章

  • Java基础 UDP协议下,收发数据的代码实现
    一、发送数据步骤:1.创建DatagramSocket对象,负责利用UDP协议往外发送数据(DatagramSocket中既有发送的方法,也有接收的方法)2.把数据打包(DatagramPacket)。把所有数据放到DatagramPacket当中3.发送数据4.释放资源 代码实现:publicstaticvoidmain(String[]args)throwsE......
  • 一文搞懂Javaweb的响应状态码
    一、状态码大类状态码分类说明1xx响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它2xx成功——表示请求已经被成功接收,处理已完成3xx重定向——重定向到其它地方:它让客户端再发起一个请求以完成整个处理。4xx客户端......
  • JavaScript笔记 09
    目录01DOM操作事件的体验02获取元素对象的五种方式03事件中this指向问题04循环绑定事件05DOM节点对象的常用操作  06点亮盒子的案例07节点访问关系08设置和获取节点内容的属性09以上内容的小总结 01DOM操作事件的体验        js本身是受......
  • java:包装类
    java是面向对象的编程语言,而基本数据类型并不是对象,于是java对基本数据类型包装了对应的类,如int-Integer、char-Character等,这些类称之为包装类。一、包装类用于泛型何为泛型?实例化一个对象,就是开辟一块空间用于存储对象的属性,Java是强类型编程语言,在声明属性时,需要指定属性......
  • Java(2) ----- 异常、多线程、同步安全、死锁、并发包、Lambda表达式、Stream流
    异常方法默认都可以自动抛出运行时异常!自定义异常:(1)自定义编译时异常1、定义一个异常类继承Exception2、重写构造器3、在出现异常的地方用thrownew自定义对象抛出4、编译时异常是编译阶段就报错,提醒跟家强烈,一定需要处理!(2)自定义运行时异常1、定义一个异常类继承RunTimeE......
  • 30 天精通 RxJS (04):什么是 Observable ?
    要理解Observable之前,我们必须先谈谈两个设计模式(DesignPattern),IteratorPattern跟ObserverPattern。今天这篇文章会带大家快速的了解这两个设计模式,并解释这两个Pattern跟Observable之间的关系!ObserverPatternObserverPattern其实很常遇到,在许多API的设计......
  • 【全开源】JAVA上门家政服务系统源码微信小程序+微信公众号+APP+H5_博纳软云
    上门家政服务系统源码微信小程序——让便捷服务触手可及在现代社会,家政服务的需求日益增长,而如何快速、便捷地找到优质的家政服务成为了许多家庭关注的焦点。为此,我们推出了上门家政服务系统源码微信小程序,让便捷服务触手可及。这款微信小程序不仅集成了丰富的家政服务资源,还......
  • 【全开源】JAVA语聊大厅+陪玩系统语音聊天APP系统源码_博纳软云
    JAVA语聊大厅+陪玩系统语音聊天APP系统源码,融合了先进的JAVA技术和独特的陪玩系统,为用户带来了全新的语音社交体验。该系统源码不仅具备JAVA语言的高效稳定特性,还通过陪玩系统的引入,让用户在享受语音聊天的乐趣之余,更能找到心仪的玩伴,一同畅游在精彩的游戏世界。在语聊大厅中,......
  • 基于JavaWeb的家居商城系统的设计与实现论文
    摘要随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于家居商城系统当然也不能排除在外,随着网络技术的不断成熟,带动了家居商城系统,它彻底改变了过去传统的管理方式,不仅使服务管理难度变低了,还提升了管理的灵活性。这种个性化的平......
  • 【JavaScript系列】-- 对象
    今天我们将探讨JavaScript中的一个强大工具—-对象。对象就像生活中的各种工具,帮助你更好地组织和管理信息。在实际开发中,可以使用对象来表示用户信息、处理表单数据等。01、什么是对象JavaScript对象是一种包含属性和方法的数据类型,可视为一个多功能盒子,用于存放各种数据。在......