当前位置:   article > 正文

SpringCloud-Alibaba之入门_springalibabac

springalibabac

SpringCloud 是微服务一站式服务解决方案,微服务全家桶。它是微服务开发的主流技术栈。它采用了名称,而非数字版本号。

SpringCloud 和 SpringCloud Alibaba 目前是最主流的微服务框架组合。本笔记根据B站尚硅谷教程整理而成!

教程:https://www.bilibili.com/video/BV18E411x7eT

系统架构的演变

概述

  • 随着互联网的发展,网站应用的规模不断扩大,常规的应用架构已无法应对,分布式服务架构以及微服务架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

单体应用架构

  • web应用程序发展的早期,大部分web工程(包含前端页面,web层代码,service层代码,dao层代码)是将所有的功能模块,打包到一起并放在一个web容器中运行。

单体应用架构.png

  • 比如搭建一个电商系统:客户下订单,商品展示,用户管理。这种将所有功能度部署在一个web容器中运行的系统就叫做单体架构,目前也有人称为单体地狱。

  • 优点:

    • 所有的功能集成在一个项目工程中。
    • 项目架构简单,前期开发成本低,周期短,小型项目的首选。
  • 缺点:

    • 全部功能集成在一个工程中,对于大型项目不易开发、扩展和维护。
    • 系统性能只能通过扩展集群结点,成本高,有瓶颈。
    • 技术栈受限。
    • 代码耦合度很高。
    • 容错性差,比如用户管理出问题了,整个系统全部出问题,牵一发而动全身。

垂直应用架构

  • 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互补相干的几个应用,以提高效率。

垂直应用架构.png

  • 优点:

    • 项目架构简单,前期开发成本低,周期daunt,小型项目的首选。
    • 通过垂直拆分,原来的单体项目不至于无线扩大。
    • 不同的项目可采用不同的技术。
    • 针对不同的子工程优化。
    • 解决高并发问题。
    • 方便水平扩展,容错性好(相对于单体架构来说的,比如上图中的商品管理出问题了,对CMS系统和后台管理系统来说没影响)。
  • 缺点:

    • 全部功能集成在一个工程中,对于大型项目不易开发、扩展和维护。
    • 系统性能扩展只能通过扩展集群结点,成本高,有瓶颈。
    • 系统间相互独立,会产生session共享问题(可以使用Redis Cluster、SpringSession等技术解决)。
    • 重复的开发工作(比如上图中的用户管理功能在电商系统和后台管理系统中都有)。

分布式SOA架构

什么是SOA?

  • SOA,全称是Service-Oriented Architecture,即面向服务的架构。它可以根据需要通过网络对松散耦合的粗粒度应用组件(服务)进行分布式部署、组合和使用。一个服务通常以独立的形式存在于操作系统进程中。

  • 站在功能的角度,把业务逻辑抽象成可复用、可组装的服务,通过服务的编排实现业务的快速再生,目的是把原先固有的业务功能转变为通用的业务服务,实现业务逻辑的快速复用。

  • 通过上面的描述可以发现SOA有如下的特点:分布式、可重用、扩展灵活、松耦合。

SOA架构

  • 当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使得前端应用能够更快速的响应多变的市场需求。

分布式SOA架构.png

  • 优点:

    • 抽取公共的功能为服务,提高开发效率。
    • 对不同的服务进行集群化部署解决系统压力。
    • 基于ESB或Dubbo减少系统耦合。
  • 缺点:

    • 抽取服务的粒度较大。
    • 服务提供方和调用方接口耦合度较高。

微服务架构

微服务架构.png

  • 优点:

    • 通过服务的原子化拆分,以及微服务的独立打包、部署和升级,小团队的交付周期将会缩短,运维成本也将大幅度下降。
    • 微服务遵循单一原则。微服务之间采用RESTful等轻量级协议传输。
  • 缺点:

    • 微服务过多,服务治理成本高,不利于系统维护。
    • 分布式系统开发的技术成本高(容错、分布式事务等)。

SOA和微服务的关系

  • SOA:面向服务的架构,是一种设计方法,其中包含多个服务,服务和服务之间通过相互依赖最终提供一系列的功能。一个服务通常以独立的形式存在于操作系统的进程之中。各个服务之间通过网络调用。

  • 微服务架构:其实和SOA架构类似,微服务是SOA架构上的升华,微服务架构强调的一个重点是"业务需要彻底的组件化和服务化",原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。

功能SOA微服务
组件大小大块业务逻辑单独任务或小块业务逻辑
耦合通常松耦合总是松耦合
公司架构任何类型小型,专注于功能交叉团队
管理着重中央管理着重分散管理
目标确保应用能够交互操作执行新功能、快速拓展开发团队

分布式核心知识

分布式的远程调用

  • RESTful。

  • RPC。

分布式中的CAP原理

  • 现如今,对于大多数大型互联网应用,分布式系统正变得越来越重要。分布式系统最大的难点,就是各个节点的状态如何同步。CAP定理是这方面的基本定理,也是理解分布式系统的起点。

  • CAP理论有Eirc Brewer在ACM研讨会上提出的,而后CAP被奉为分布式领域的重要理论。分布式系统的CAP理论,首先把分布式系统中的三个特性进行了如下的归纳。

CAP.png

  • C(Consistency,一致性):数据一致更新,所有数据的变化都是同步的。

  • A(Availability,可用性):在集群中一部分节点故障后,集群整体是否还能有影响客户端的读写请求。

  • P(Partition tolerance,分区容错性):某个节点的故障,并不影响整个系统的运行。

一个分布式系统里面,节点组成的网络本来应该是连通的。然而可能因为一些故障,使得有些节点之间不连通了,整个网络就分成了几块区域。数据就散布在了这些不连通的区域中。这就叫分区。

当你一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分就访问不到这个数据了。这时分区就是无法容忍的。

提高分区容忍性的办法就是一个数据项复制到多个节点上,那么出现分区之后,这一数据项就可能分布到各个区里。容忍性就提高了。

然而,要把数据复制到多个节点,就会带来一致性的问题,就是多个节点上面的数据可能是不一致的。要保证一致,每次写操作就都要等待全部节点写成功,而这等待又会带来可用性的问题。

总的来说就是,数据存在的节点越多,分区容忍性越高,但要复制更新的数据就越多,一致性就越难保证。为了保证一致性,更新所有节点数据所需要的时间就越长,可用性就会降低。

作者:邬江
链接:https://www.zhihu.com/question/54105974/answer/139037688
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

选择说明
CA放弃分区容错性,加强一致性和可用性,其实就是传统的关系型数据库的选择
AP放弃一致性(强一致性),追求分区容错性和可用性,这时很多分布式系统设计时的选择,比如很多NoSQL数据库就是如此
CP放弃可用性,追求一致性和分区容错性,基本不会选择,网络问题会直接让整个系统不可用,比如zookeeper就是CP
  • 需要明确一点的是,在一个分布式系统当中,分区容错性和可用性是最基本的需求,所以在分布式系统中,我们的系统最应该关注的是AP,通过补偿机制寻求数据的一致性。

常见微服务框架

SpringCloud

  • SpringCloud是一系列框架的有序集合。它利用SpringBoot的开发便利性巧妙的简化了分布式系统基础设施的开发,如服务发现注册配置中心消息中线负载均衡熔断器数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。SpringCloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考研的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

Apache的ServiceComb

  • Apache ServiceCombo是业界第一个Apache微服务顶级项目,是一个开源微服务解决方案,致力于帮助企业、用户和开发者将企业应用轻松微服务化上云,并实现对微服务应用的高效运维管理。其提供一站式开源微服务解决方案,融合SDK框架级、零入侵ServerMesh场景并支持多种语言。

ZeroC ICE

  • Zeroc ICE是Zeroc公司的杰作,继承了CORBA的血统,是新一代的面向对象的分布式系统中间件。作为一种微服务架构,它基于RPC框架发展而来,具有良好的性能和分布式能力。

微服务中的相关概念

image-20210114105802870

服务注册和发现

  • 服务注册:服务实例将自身服务信息注册到注册中心。这部分服务信息包括服务所在主机IP和提供服务的Port,以及暴露服务自身状态以及访问协议等信息。

  • 服务发现:服务实例请求注册中心获取所依赖服务信息。服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去其你去它们提供的服务。

服务注册和发现.png

负载均衡

  • 负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。

负载均衡.png

熔断

  • 熔断这一概念来源于电子工程中的断路器。在互联网系统中,当下游服务因为访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫熔断。

熔断.jpg

链路追踪

  • 随着微服务架构的流行,服务按照不同的纬度进行拆分,一次请求往往需求涉及到多个服务。互联网应用构建在不同的软件模块上,这些软件模块,有可能是由不同的团队开发,可能使用不同的编程语言来实现、有可能部署在几千台服务器上,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪。

链路追踪.png

API网关

  • 随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接和各个微服务通信可能出现:

  • 客户端需要调用不同的URL地址,增加难度。

  • 在一定的场景下,存在跨域请求的问题。

  • 每个微服务都需要进行单独的身份认证。

  • 针对上面的问题,API网关顺势而生。

  • API网关直面意思是将所有API调用统一接入到API网关层,由网关层统一接入和输出。一个网关的基本功能有:统一接入、安全防护、协议适配、流量监管、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的业务逻辑处理,而API网关更专注于安全、流量和路由等问题。

API网关.png

SpringCloud

SpringCloud概述

  • Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基
    础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用
    Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家
    公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉
    了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具
    包 。

SpringCloud的架构

1597213783265

参考资料,尽量去官网

SpringCloud 官网:https://spring.io/projects/spring-cloud#learn

SpringCloud 官方文档:https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/

SpringBoot 官网:https://spring.io/projects/spring-boot#learn

SpringBoot 官方文档:https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/htmlsingle/

Spring Cloud中文文档:https://www.bookstack.cn/read/spring-cloud-docs/docs-index.md

SpringCloud中的核心组件

  • Spring Cloud的本质是在 Spring Boot 的基础上,增加了一堆微服务相关的规范,并对应用上下文
    (Application Context)进行了功能增强。既然 Spring Cloud 是规范,那么就需要去实现,目前
    Spring Cloud 规范已有 Spring官方,Spring Cloud Netflix,Spring Cloud Alibaba等实现。通过组件
    化的方式,Spring Cloud将这些实现整合到一起构成全家桶式的微服务技术栈。

  • Spring Cloud Netflix组件 :

组件名称作用
Eureka服务注册中心
Ribbon客户端负载均衡
Feign声明式服务调用
Hystrix客户端容错保护
ZuulAPI服务网关
  • Spring Cloud Alibaba组件 :
组件名称作用
Nacos服务注册中心
Sentinel客户端容错保护
  • Spring Cloud原生及其他组件 :
组件作用
Consul服务注册中心
Config分布式配置中心
GatewayAPI服务网关
Sleuth/Zipkin分布式链路追踪

SpringCloud的体系结构

SpringCloud架构.jpg

  • 从上图可以看出Spring Cloud各个组件相互配合,合作支持了一套完整的微服务架构。

  • 注册中心负责服务的注册与发现,很好将各服务连接起来。

  • 断路器负责监控服务之间的调用情况,连续多次失败进行熔断保护。

  • API网关负责转发所有对外的请求和服务。

  • 配置中心提供了统一的配置信息管理服务,可以实时的通知各个服务获取最新的配置信息 。

SpringCloud和SpringBoot的对应版本

版本选择:

  • 可以通过浏览器查看版本对应关系:https://start.spring.io/actuator/info
    • json信息可以通过工具格式化:https://tool.lu/
  • springboot gitub 源码地址:https://github.com/spring-projects/spring-boot/releases
  • springboot 官网查看版本:https://spring.io/projects/spring-boot#learn
  • springcloud 官网查看版本:https://spring.io/projects/spring-cloud#learn

查看官网:https://spring.io/projects/spring-cloud#overview,拖到下面查看官方给出的版本对应关系。

例如以如下版本对应为例:

image-20210114111629747

image-20210114113919748

模拟微服务

工程步骤:

  • 1、New Project
  • 2、聚合总父工程名字
  • 3、Maven选版本
  • 4、工程名字
  • 5、字符编码
  • 6、注解生效激活
  • 7、java编译版本选8

开始构建

构建父工程 spring_cloud_atguigu_2020 ,后面的项目模块都在此工程中:

image-20210114115323061

image-20210114115903373

设置编码:Settings -> Editor-> File Encodings

image-20210114121248652

注解激活:

image-20210114121355674

选择java编译版本:

image-20210114121516653

文件过滤,可以不设置(这样就显示不出来这些文件了,有的文件看着有点烦):

image-20210114121800097

父工程 pom 配置

删掉 src 目录,只留 pom 文件

<?xml version="1.0" encoding="UTF-8"?>

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itjing.springcloud</groupId>
    <artifactId>spring_cloud_atguigu_2020</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--第一步-->
    <packaging>pom</packaging>

    <!-- 统一管理 jar 包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>5.1.47</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!-- 子模块继承之后,提供作用:锁定版本 + 子module不用写 groupId 和 version -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>3.0.0</version>
            </dependency>

            <!-- 下面三个基本是微服务架构的标配 -->
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud 阿里巴巴-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
                <scope>runtime</scope>
            </dependency>
            <!-- druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!--log4j-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

上面配置的解释:

首先要加

<packaging>pom</packaging>  
  • 1

聚合版本依赖,dependencyManagement声明依赖,并不实现引入,所以子项目还需要写要引入的依赖。

1597215801116

1597215611540

1597215639355

image-20210114123346331

第一个微服务架构

步骤:

  1. 建模块 module
  2. 改 pom
  3. 写yml
  4. 主启动
  5. 业务类

提供者

在父工程中新建子模块:cloud-provider-payment8001

建子模块后父工程变化

查看父工程 pom 文件变化,多了 modules标签

<modules>
    <module>cloud-provider-payment8001</module>
</modules>
  • 1
  • 2
  • 3
pom 文件
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring_cloud_atguigu_2020</artifactId>
        <groupId>com.itjing.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8001</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--图形化-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--mybatis整合spring依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
配置文件

在 resources 目录下新建 application.yml

# 端口号
server:
  port: 8001
spring:
  application:
    name: cloud-payment-service
  # 数据源
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
    
# mybatis 相关
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.itjing.springcloud.entities  # 所有Entity 别名类所在包
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
主启动类
package com.itjing.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class, args);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
业务类

五步:

  • 建表sql
  • entities
  • dao
  • service
  • controller
建库建表

创建数据库:springcloud2020,建表:payment

CREATE TABLE `payment` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `serial` varchar(200) DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
  • 1
  • 2
  • 3
  • 4
  • 5
实体类
package com.itjing.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
    private Long id;
    private String serial;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
Json封装体

真正做开发的时候,可以自定义枚举类处理,具体去查询百度学习。

package com.itjing.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 如果前后端分离,这个是提供给前端信息和数据的类
 *
 * @param <T>
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {

    private Integer code;
    private String messgae;
    private T data;

    /**
     * 查询为空的时候使用的构造器
     *
     * @param code
     * @param messgae
     */
    public CommonResult(Integer code, String messgae) {
        this(code, messgae, null);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
Dao 接口
package com.itjing.springcloud.dao;

import com.itjing.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface PaymentDao {
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
Mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itjing.springcloud.dao.PaymentDao">

    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial) values (#{serial})
    </insert>

    <!--养成好习惯,使用结果映射,因为可能会由于下划线,驼峰命名造成不必要的错误-->
    <resultMap id="BaseReslutMap" type="com.itjing.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseReslutMap">
        select id,serial from payment where id = #{id}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
Service接口及其实现类
package com.itjing.springcloud.service;

import com.itjing.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Param;

public interface PaymentService {
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
package com.itjing.springcloud.service.impl;

import com.itjing.springcloud.dao.PaymentDao;
import com.itjing.springcloud.entities.Payment;
import com.itjing.springcloud.service.PaymentService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class PaymentServiceImpl implements PaymentService {

    @Resource
    private PaymentDao paymentDao;


    @Override
    public int create(Payment payment) {
        return paymentDao.create(payment);
    }

    @Override
    public Payment getPaymentById(Long id) {
        return paymentDao.getPaymentById(id);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
Controller控制器
package com.itjing.springcloud.controller;

import com.itjing.springcloud.entities.CommonResult;
import com.itjing.springcloud.entities.Payment;
import com.itjing.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController   //必须是这个注解,因为是模拟前后端分离的 restful风格的请求,要求每个方法返回 json
@Slf4j
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    @PostMapping(value = "/payment/payments")
    public CommonResult create(Payment payment) {
        int result = paymentService.create(payment);
        log.info("****插入结果:" + result);
        if (result > 0) {
            return new CommonResult(200, "插入数据库成功", result);
        }
        return new CommonResult(444, "插入数据库失败", null);
    }

    @GetMapping(value = "/payment/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        Payment result = paymentService.getPaymentById(id);
        log.info("****查询结果:" + result);
        if(result != null){
            return new CommonResult(200, "查询成功", result);
        }
        return new CommonResult(444, "没有对应id的记录", null);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
测试

使用 postman 工具进行测试,自测通过!

SpringBoot热部署的流程

pom文件中导入 spring-boot-devtools依赖:
(或者创建springboot工程时,勾选devtools选项,会自动在pom中加入依赖)
<!--SpringBoot热部署配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
继续在父工程的 pom.xml 中添加插件:
<build>
     <plugins>
     <plugin>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-maven-plugin</artifactId>
         <!--SpringBoot热部署时配置 -->
         <configuration>
          <fork>true</fork>
                  <addResources>true</addResources>
         </configuration>
         <!--SpringBoot热部署时配置 -->
    </plugin>
     </plugins>
</build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
设置application.properties
#配置项目热部署
spring.devtools.restart.enabled=true
  • 1
  • 2
在idea中设置自动编译

1.打开Settings,设置当前项目自动编译,搜索Compiler,勾选Build project automatically

2.打开Other Settings ,设置新建的项目都自动编译,搜索Compliler,勾选Build project automatically

3.按住ctrl + shift + alt + /,出现如下图所示界面,点击Registry…

4.点击进入后,勾选compiler.automake.allow.when.app.running后关闭即可

重启IDEA!

通过以上步骤,就完成了SpringBoot项目的热部署功能!!!

消费者

步骤参考提供者。

创建子模块:cloud-consumer-order80

消费者现在只模拟调用提供者的Controller方法,没有持久层配置,只有Controller和实体类

当然也要配置主启动类和启动端口

pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring_cloud_atguigu_2020</artifactId>
        <groupId>com.itjing.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-order80</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--图形化-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
配置文件
server:
  port: 80

spring:
  application:
    name: cloud-order-service
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
主启动类
package com.itjing.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain80.class, args);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
业务类
实体类

将 提供者 中的 CommonResult 和 Payment 拷贝过来,创建

服务调用概述
  • 在用户下单的时候需要调用商品微服务获取商品数据,那么应该需要怎么做呢?商品微服务提供了供人调用的HTTP接口,所以下订单的时候使用HTTP请求的相关工具类完成,如常见的HttpClient、OkHttp,当然也可以使用Spring提供的RestTemplate
RestTemplate介绍
  • Spring框架提供的RestTemplate类可用于在应用中调用RESTful服务,它简化了和HTTP服务的通信方式,统一了RESTful的标准,封装了HTTP的链接,我们只需要传入URL和返回值类型即可。相较于之前常用的HttpClient、OkHttp等,RestTemplate是一种更加优雅的调用RESTful服务的方式。

  • 在Spring应用程序中访问第三方REST服务和Spring的RestTemplate类有关。RestTemplate类的设计原则和许多其他Spring模块类(例如JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。

  • RestTemplate默认依赖JDK提供HTTP连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为如Apache HttpComponents、Netty或OkHttp等其他HTTP库。

  • 考虑到RestTemplate类是为调用REST服务而设计的,因此他的主要方法和REST的基础紧密相连就不足为奇,后者是HTTP协议的方法:HEAD、GET、POST、PUT、DELETE和OPTIONS。例如,RestTemplate类具有headForHeaders()、getForObject()等方法。

向Spring容器中注册RestTemplate
package com.itjing.springcloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
Controller控制器
package com.itjing.springcloud.controller;

import com.itjing.springcloud.entities.CommonResult;
import com.itjing.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderController {

    //远程调用的 地址
    public static final String PAYMENT_URL = "http://localhost:8001";


    @Resource
    private RestTemplate restTemplate;

    @PostMapping("consumer/payment/create")
    public CommonResult<Payment> create(Payment payment) {
        /**
         param1 请求地址,param2 请求参数, param3 返回类型
         */
        return restTemplate.postForObject(PAYMENT_URL + "/payment/payments", payment, CommonResult.class);
    }

    @GetMapping("consumer/payment/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        return restTemplate.getForObject(PAYMENT_URL + "/payment/" + id, CommonResult.class);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
测试

启动 服务提供者:cloud-provider-payment8001

启动服务消费者:cloud-consumer-order80

这时候右下角会弹出 Run Dashboard 提示,我们应该让它显示出来,以后微服务多了,我们需要它管理。

访问消费者的接口进行测试!

发现执行添加操作的时候,数据库中的数据为 null,是因为之前的 服务提供者中 没有加 @RequestBody 注解

//	注意这里的 @RequestBody  是必须要写的,虽然 MVC可以自动封装参数成为对象,
//  但是当消费者项目调用,它传参是 payment 整个实例对象传过来的, 即Json数据,因此需要写这个注解
 public CommonResult create(@RequestBody Payment payment){...}
  • 1
  • 2
  • 3

工程重构

上面的两个子模块,有多次重复的导入jar,和重复的 Entity 实体类

可以把多余的部分,加入到一个独立的模块中,将这个模块打包,并提供给需要使用的 module 。

1、新建一个 cloud-api-commons 子模块

2、将 entities 包里面的实体类复制到这个子模块中,将所需依赖引入 pom 文件中。如下:

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring_cloud_atguigu_2020</artifactId>
        <groupId>com.itjing.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-api-commons</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- 这个是新添加的,这里因为该模块后期要使用到,所以先引用 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>
        <!--
             关于这个hutool 是个功能强大的工具包,官网:https://hutool.cn/
        -->
    </dependencies>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

3、将此项目打包 install 到 maven仓库

先 clean,再 install

image-20210114161310033

4、改造提供者和消费者,将 提供者 和 消费者 两个项目中的 entities 包删除。

5、将 打包到 maven 仓库的 cloud-api-commons 模块,引入到 提供者 和 消费者的 pom 文件中,如下所示

<!-- 引入自己定义的api通用包-->
<dependency>
    <groupId>com.itjing.springcloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>${project.version}</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

分析模拟微服务中存在的问题

  • 服务调用者将微服务的请求路径硬编码到Java代码中。

  • 不能对微服务负载均衡的调用,因为请求路径的URL硬编码了。

  • 服务多起来,对前端调用不友好,需要加入API网关。

  • 微服务多起来的话,如果每次都需要重新修改配置文件,很麻烦,需要配置的统一管理。

  • 链路追踪。

  • 系统容错。

  • ……

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号