黑马程序员ssm总结[大全版本,有对应pdf+源码](spring->springmvc-->springboot-->maven高级->cloud微服务)

前言

pdf+源码(大全),对应视频:https://www.bilibili.com/video/BV1VJ411X7xX?p=20&vd_source=0e4ada3d15f80172cb72c52e0fcabd05
自我感觉黑马课程比官方文档好,新手友好,强推!
看文档必看视频效率高,理解更透,一遍看不懂,反复看!
有问题,欢迎与我讨论: qq:1657019234
黑马程序员ssm资料(从spring–>springmvc–>springboot–>maven高级->cloud微服务)

耦合性可以是低耦合性(或称为松散耦合),也可以是高耦合性(或称为紧密耦合)。以下列出一些耦合性的分类,从高到低依序排列:

  • 内容耦合(content coupling,耦合度最高):也称为病态耦合(pathological coupling)当一个模块直接使用另一个模块的内部数据,或通过非正常入口而转入另一个模块内部。
  • 共用耦合/公共耦合(common coupling):也称为全局耦合(global coupling.)指通过一个公共数据环境相互作用的那些模块间的耦合。公共耦合的复杂程序随耦合模块的个数增加而增加。
  • 外部耦合(external coupling):发生在二个模块共用一个外加的数据格式、通信协议或是设备界面,基本上和模块和外部工具及设备的沟通有关。
  • 控制耦合(control coupling):指一个模块调用另一个模块时,传递的是控制变量(如开关、标志等),被调模块通过该控制变量的值有选择地执行块内某一功能;
  • 特征耦合/标记耦合(stamp coupling):也称为数据结构耦合,是指几个模块共享一个复杂的数据结构,如高级语言中的数组名、记录名、文件名等这些名字即标记,其实传递的是这个数据结构的地址;
  • 数据耦合/数据耦合(data coupling):是指模块借由传入值共享数据,每一个数据都是最基本的数据,而且只分享这些数据(例如传递一个整数给计算平方根的函数)。
  • 消息耦合(message coupling,是无耦合之外,耦合度最低的耦合):可以借由以下二个方式达成:状态的去中心化(例如在对象中),组件间利用传入值或消息传递 (计算机科学)来通信。
  • 无耦合:模块完全不和其他模块交换信息。

降低耦合度的方法

1、少使用类的继承,多用接口隐藏实现的细节。 java面向对象编程引入接口除了支持多态外, 隐藏实现细节也是其中一个目的。
  2、模块的功能化分尽可能的单一,道理也很简单,功能单一的模块供其它模块调用的机会就少。(其实这是高内聚的一种说法,高内聚低耦合一般同时出现,为了限制篇幅,我们将在以后的版期中讨论)。
  3、遵循一个定义只在一个地方出现。
  4、少使用全局变量。
  5、类属性和方法的声明少用public,多用private关键字,
  6、多用设计模式,比如采用MVC的设计模式就可以降低界面与业务逻辑的耦合度。
  7、尽量不用“硬编码”的方式写程序,同时也尽量避免直接用SQL语句操作数据库。
  8、最后当然就是避免直接操作或调用其它模块或类(内容耦合);如果模块间必须存在耦合,原则上尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,避免使用内容耦合。

紧密耦合的系统在开发阶段有以下的缺点:

  1. 一个模块的修改会产生涟漪效应,其他模块也需随之修改。
  2. 由于模块之间的相依性,模块的组合会需要更多的精力及时间。
  3. 由于一个模块有许多的相依模块,模块的可复用性低。 [2]

spring核心容器

本章是core&bean的原理讲解

5min复习视频:核心容器总结

在这里插入图片描述

Spring就提出了一个解决方案:

  • 使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
  • 即:使用消息耦合(耦合度最低的耦合),去中心化,
  1. IOC(Inversion of Control)控制反转

(1)什么是控制反转呢?

  • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。

2.DI的注入方法

  • setter注入(比构造器注入更常用,推荐,我们一般只用构造器注入)<property>(又分为

    • 引用类型注入<property name=“bookDao” ref=“bookDao”>)

    • 简单类型(int…String)注入<property name=“msg” ref=“我的类型是自动检测的,看要被注入的变量的类型”>)

    • 集合类型注入

      <property name="names">
          <list>
              <value>xxx</value>
              <ref bean="dataSource"/>
          <list>
      </property>
      
  • 构造器注入<constructor-arg>

IoC基础上,需要绑定两个Bean之间的依赖关系,需要DI进行绑定,<property>的形式

3.bean的生命周期scope: <bean id=“bookDao” class=“com.itheima.dao.impl.BookDaoImpl” init-method=“init” destroy-method=“destory”/ …>当然,还有很多别的scope生命周期属性

在这里插入图片描述


spring注解开发(正片开始)

spring3.0升级了

纯注释开发,使用一个添加了 @configuration的config配置类来进行配置

spring注解开发总结

  • 普通配置类注入:在这里插入图片描述

  • 第三方配置类注入

在这里插入图片描述

在这里插入图片描述


spring整合mybatis

看看就行

可以看到,在老师给的项目中,shiro( shiro是apache的是一个分布式权限管理的框架,实现 用户认证、用户授权)

和 cors(用于允许跨域请求)

出于安全原因,浏览器禁止AJAX调用当前来源之外的资源,跨域资源共享(CORS)是由大多数浏览器实施的W3C规范,使您可以灵活地指定对哪种跨域请求进行授权。
从Spring Framework 4.2开始,开箱即用地支持CORS。 CORS请求(包括带有OPTIONS方法的预检请求)将自动分派到各种已注册的HandlerMappings。

二者采取了类似的配置类形式

spring整合Junit

看看就行

在这里插入图片描述


AOP:用于不改变原代码基础上 进行功能增强

  • 概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式
  • 作用:在不惊动原始设计的基础上为方法进行功能增强
  • 核心概念
    • 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
    • 连接点(JoinPoint):在SpringAOP中,理解为任意方法的执行
    • 切入点(Pointcut):匹配连接点的式子,也是具有共性功能的方法描述
    • 通知(Advice):若干个方法的共性功能,在切入点处执行,最终体现为一个方法
    • 切面(Aspect):描述通知与切入点的对应关系
    • 目标对象(Target):被代理的原始对象成为目标对象

切入点表达式:

  • 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)

    execution(* com.itheima.service.*Service.*(..))
    
  • 切入点表达式描述通配符:

    • 作用:用于快速描述,范围描述
    • *:匹配任意符号(常用)
    • .. :匹配多个连续的任意符号(常用)
    • +:匹配子类类型
  • 切入点表达式书写技巧

    1.按标准规范开发
    2.查询操作的返回值建议使用*匹配
    3.减少使用…的形式描述包
    4.对接口进行描述,使用*表示模块名,例如UserService的匹配描述为*Service
    5.方法名书写保留动词,例如get,使用*表示名词,例如getById匹配描述为getBy*
    6.参数根据实际情况灵活调整


Spring事务

  • 保障一系列的数据库操作同成功同失败
  • Spring事务作用:在数据层或**业务层**保障一系列的数据库操作同成功同失败
  • Spring为了管理事务,提供了一个平台事务管理器PlatformTransactionManager:

在这里插入图片描述

进行提交与回滚,事务(转账操作中:A钱-,B钱+)作为一个整体,一旦部分执行不成功,能够整个回滚,从而确保若:A-成功,B+失败后,A,B都将回滚,恢复原状态

在这里插入图片描述

在这里插入图片描述

(springboot中,连SpringMvcConfig都没了,使用,@EnableWebMvc也不会用了)

REST风格(只是一种风格,不是一种规范,可以不遵守,但由于采用的人多,已经接近于一种规范):

在这里插入图片描述

Restful风格:基于Rest风格,进一步简化:

@ResponseBody

@RestController

@RequestMapping

在这里插入图片描述

PostMan请求管理规范:

在这里插入图片描述

使用Restful风格进行开发的一个示例:

在这里插入图片描述

如果直接访问前端界面:localhost/pages/books.html,报错:

在这里插入图片描述

浏览器:

因:浏览器访问使用get方法,由spring处理,spring认为你没有这一接口.确实,它本来也不是接口,而是一个页面.

法:spring放行,让tomcat处理;即:实现一个过滤器(filter)静态页面,tomcat直接处理,动态请求springMVC处理

拦截器

在这里插入图片描述

拦截器(Intercepter)是一种动态拦截方法调用的机制,在springMVC中动态拦截 控制器 方法的执行

  • 在指定方法的前后执行预先设定的代码
  • 阻止原始方法的执行

拦截器与过滤器的区别:

  • filter属于servlet技术,intercepter属于SpringMVC技术
  • filter对所有访问进行增强,intercepter仅对SpringMVC的访问进行增强

Maven分模块开发:

idea的maven相关功能只能确保书写的时候不报错,不能保证运行的时候不报错

通过install,实现本地安装

pom项目默认的打包方式:<packaging>jar</packaging>

pom项目web项目的打包方式:<packaging>war</packaging>

pom项目聚合项目的打包方式:<packaging>pom</packaging>

  • maven冲突:

在这里插入图片描述

发生冲突时,maven会有一些规则来选用依赖

依赖冲突可能会导致某个依赖使用了你不想使用的版本(这个版本可能会导致运行错误)

  • 可选依赖和排除依赖

    <!--可选依赖是隐藏当前工程所依赖的资源,隐藏后对应资源将不具有依赖传递-->
    <optional>true</optional>
    
    <!--排除依赖是隐藏当前资源对应的依赖关系-->
    <exclusions>
        <exclusion>
            <groupId>com.itheima</groupId>
            <artifactId>maven_03_pojo</artifactId>
        </exclusion>
    </exclusions>
    
  • maven多环境开发:(profile)

在这里插入图片描述

pro,dev,test多环境不同,如何配置多环境开发,以供选用?

  • 使用聚合统一管理项目

    步骤1:创建一个空的maven项目

    步骤2:将项目的打包方式改为pom

    步骤3:pom.xml添加所要管理的项目

    步骤4:使用聚合统一管理项目

    <?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.itheima</groupId>
        <artifactId>maven_01_parent</artifactId>
        <version>1.0-RELEASE</version>
        <packaging>pom</packaging>
        
        <!--设置管理的模块名称-->
        <modules>
            <module>../maven_02_ssm</module>
            <module>../maven_03_pojo</module>
            <module>../maven_04_dao</module>
        </modules>
    </project>
    
  • 继承:解决重复配置问题

<!--配置当前工程继承自parent工程-->
<parent>
    <groupId>com.itheima</groupId>
    <artifactId>maven_01_parent</artifactId>
    <version>1.0-RELEASE</version>
    <!--设置父项目pom.xml位置路径-->
    <relativePath>../maven_01_parent/pom.xml</relativePath>
</parent>

<dependencyManagement>标签不真正引入jar包,而是配置可供子项目选择的jar包依赖

子项目要想使用它所提供的这些jar包,需要自己添加依赖,并且不需要指定<version>

  • 属性:即在pom.xml中配置属性变量,更改一处时,其他地方跟着更改

    定义:

    <!--定义属性-->
    <properties>
        <spring.version>5.2.10.RELEASE</spring.version>
        <junit.version>4.12</junit.version>
        <mybatis-spring.version>1.3.0</mybatis-spring.version>
    </properties>
    

    使用:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    

    文件加载 属性:配置文件(如jdbc.properties文件)中的属性,也让Maven进行管理

    需要设置maven过滤文件范围

    详见 maven高级.md

  • 私服

使用nexus能建立私服仓库(小团队开发):nexus server端建立私服仓库–>本地maven setting.xml完成私服地址配置(至此,能访问私服了)–>项目pom.xml,添加 <distributionManagement> 配置当前工程保存(部署)在私服中的具体位置–>maven deploy指令部署

(下载不需要部署)


springboot

(前期都是基础,了解原理;springboot开始进入实用)

一个经典Controller处理前端请求:

@RestController
@RequestMapping("/books")
public class BookController {

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("id ==> "+id);
        return "hello , spring boot!";
    }
}

SpringBoot 程序如何修改呢?SpringBoot 提供了多种属性配置方式,加载顺序由上往下,因而如下三文件,最终:server:port:82

今后统一使用application.yml

  • application.properties

    server.port=80
    
  • application.yml

    server:
    	port: 81
    
  • application.yaml

    server:
    	port: 82
    

注意:SpringBoot 程序的配置文件名必须是 application ,只是后缀名不同而已。


  • mybatis

mybatis-plus真的能省很多力,但老师已经用了mybatis了,那算了!

mybatis也有了自动代码生成器(毕竟国外uu们不使用mp(mybatis-plus),用不到这么好的代码生成器[笑]),老师就用了,参照:

MyBatis代码自动生成器Mybatis-Generator使用教程

核心:

1.mybatis-generator.xml文件(文章中为mybatis-generator-cfg.xml,老师项目中为:mybatis-generator.xml)

2.pom里面添加mybatis-generator的plugin配置。加载plugins

3.添加运行配置、运行文件(对了记得吧application.properties后缀改为yml

3是为了使用maven运行maven插件 mybatis-generator:generate -e指令

注意:不需要担心 自写mapper(xml文件)代码被覆盖, 高于mybatis1.3.7的版本都不会覆盖 ,参见自写mapper(xml文件)代码被覆盖

必须尽快弄好,或者想别的方法让单老师先开始!

  1. 新建springboot+mybatis项目(pom)(此时pom插件已经配好)
  2. 新建bean,entity,dao–>mapper自动生成–>controller(老师为了实现登录,使用了一些别的插件)
  3. 不需要配置跨域请求(来自不同端口的请求)(没有使用vue,vue是动态应用,而我们目前页面是static!请求来自同一端口!)
  4. 过程中,application.yml文件配置(项目配置,mysql配置,mybatis的数据源),mybatis-generator文件配置
  5. 不断添加插件,不断添加pom.xml

在这里插入图片描述

(都在mybatis-generator.xml中配置完成,且生成连带实体类!!!)


Unknown system variable ‘query_cache_size‘ 的解决方法 方法二亲测有效!

当前,需要解决映射不成功的问题(mybatis理解不深!),以箭头为 映射成功的标志

  1. 了解mybatis映射机制,正常来说,不需要mybatis-generator.xml也能生成箭头(视箭头为映射成功的标志)

    尝试,更改mybatis-generator.xml的dao目录(覆盖也没关系!)

    依旧没问题

    映射机制:

    1.引入mybatis依赖(pom.xml)

    2.property.yml文件,配置mybatis映射关系(如果)

  2. 使用mybatis-generator.xml生成的都有箭头

    必然不是spring配置错误,而是mybatis理解不深刻!

    尝试:删除某一文件,重配!

    依旧没问题

批量注入过程中,发现@Repository改为使用@Mapper注入成功了!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xBg2o0NB-1656345257363)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220626155525255.png)

o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task.

java.lang.NoClassDefFoundError: com/alibaba/fastjson/util/IdentityHashMap

Maven中的scope总结

  1. compile
    不声明scope元素的情况下的默认值;compile表示被依赖包需要参与当前项目的编译,包括后续的测试,运行周期也参与其中,是一个比较强的依赖;打包的时候通常需要包含进去。

  2. runtime
    runtimecompile比较相似,区别在于runtime 跳过了编译阶段,打包的时候通常需要包含进去。

  3. import
    import 只能在pom文件的中使用,从而引入其他的pom文件中引入依赖,如:在Spring boot 项目的POM文件中,我们可以通过在POM文件中继承 Spring-boot-starter-parent来引用Srping boot默认依赖的jar包

因而,也难怪,之前依赖使用import出现了不生效的情况!

在这里插入图片描述


分析:

当前版本:较为合理,pom中的依赖是,结合:老师原项目+nacos-discover示例项目得到的(虽说去除了哥的那几个依赖,这是我最担心的!如果出现相关报错,将删除哥的文件)

  • fastjson找不到:

    依赖冲突:

    当前fastjson版本无问题!2.1依然足矣!

    搜:

    1.External Libraries中并未发现相关依赖的Jar包–>有,非

  • 必然是某些配置错误,因此,进行了配置文件置零操作,与老师当初保持一致(现下所处阶段:不如张俊杰当初,但他引入了大量不靠谱依赖,我这靠谱)

    • spring-boot-starter-web 版本 不一致,有风险!(低于)

nacos配置中心(cloud-alibaba)

配置管理的必要性:

同一份程序在不同的环境(开发,测试,生产)、不同的集群(如不同的数据中心)经常需要有不同的

配置,所以需要有完善的环境、集群配置管理

在微服务架构中,当系统从一个单体应用,被拆分成分布式系统上一个个服务节点后,配置文件也必须跟着迁移

(分割),这样配置就分散了,不仅如此,分散中还包含着冗余,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lp7d1a0R-1656345257365)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627173947910.png)

配置中心的服务流程如下:

1、用户在配置中心更新配置信息。

2、服务A和服务B及时得到配置更新通知,从配置中心获取配置。

总得来说,配置中心就是一种统一管理各种应用配置的基础服务组件。

在系统架构中,配置中心是整个微服务基础架构体系中的一个组件,如下图,它的功能看上去并不起眼,无非就是

配置的管理和存取,但它是整个微服务架构中不可或缺的一环

总而言之,在传统巨型单体应用纷纷转向细粒度微服务架构的历史进程中,配置中心是微服务化不可缺少的一个系

统组件,在这种背景下中心化的配置服务即配置中心应运而生

通过配置中心,我们实现了:

  • 合格的配置中心需要满足如下特性:
  • 配置项容易读取和修改
  • 分布式环境下应用配置的可管理性,即提供远程管理配置的能力
  • 支持对配置的修改的检视以把控风险
  • 可以查看配置修改的历史记录
  • 不同部署环境下应用配置的隔离性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4f1Y4G9C-1656345257366)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627173914565.png)

问:nacos配置中心的配置是动态的,我们的微服务已经跑起来后,是如何派上用场的?懂了,只是集中管理,但是需要:重新跑!

示例服务中,配置只是进行打印,如何 将配置派上用场?

一般来说,spring boot的配置将在application.yml(也可以是application.properties)文件中编写,

由于使用外部 配置中心,必须将原先的application.yml重命名为bootstrap.yml,bootstrap.yml如下所示:

spring.cloud.nacos.confifig.server-addr 指定了Nacos Server的网络地址和端口号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMr6Bfog-1656345257367)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627174121228.png)

如此,外部(nacos)配置中心派上了用场

通过自定义扩展的 Data Id 配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件

结论:实现简单,后期可以整,暂时没必要!!!


nacos服务发现

笔记摘自:黑马程序员 nacos-服务发现.pdf

负载均衡,引入 服务发现的目的

先导: Spring Cloud服务协作流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4rTyo5f-1656345257368)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627183219988.png)

(1)在微服务启动时,会向服务发现中心上报自身实例信息,这里ServiceB 包含多个实例。

每个实例包括:

IP地址、端口号信息。

北京市昌平区建材城西路金燕龙办公楼一层 电话:400-618-9090(2)微服务会定期从Nacos Server(服务发现中心)获取服务实例列表。

(3)当ServiceA调用ServiceB时,ribbon组件从本地服务实例列表中查找ServiceB的实例,如获取了多个实例如

Instance1、Instance2。这时ribbon会通过用户所配置的负载均衡策略从中选择一个实例。

(4)最终,Feign组件会通过ribbon选取的实例发送http请求。

采用Feign+Ribbon的整合方式,是由Feign完成远程调用的整个流程。而Feign集成了Ribbon,Feign使用Ribbon

完成调用实例的负载均衡。

考察核心:光凭zuul网关配置,能否实现负载均衡?(而非在 service微服务互相调用过程中,通过feign实现!)

(负载均衡的两个环节:1.通过feign(调用ribbon组件)微服务直接互相调用(客户端负载均衡,微服务是nacos客户端 nacos server是服务端) 2.通过zuul 网关配置,端口转发(服务端负载均衡,通过nginx实现的一样是服务端负载均衡;zuul和nginx往往是一起使用的!) )

ribbon根据负载均衡策略负责选择示例,feign会通过ribbon来选择实例进而发送请求(feign集成来ribbon)

(本文档,似乎一直在集中阐述 客户端负载均衡!)


没有nacos服务注册中心时,微服务调用

在微服务架构中,如果没有nacos服务注册中心,如何进行微服务之间互相调用(通信)?

Service B暴露接口供Service A调用:

@SpringBootApplication 
@RestController 
public class SpringRestProviderBootstrap { 
    public static void main(String[] args) { 
        SpringApplication.run(SpringRestProviderBootstrap.class, args); 
    }
    
@GetMapping(value = "/service") //暴露服务 
public String service(){ 
    return "provider invoke"; 
} 
}

配置文件:

server.port = 56010

Service A去调用Service B

@SpringBootApplication 
@RestController 
public class SpringRestConsumerBootstrap 
{ public static void main(String[] args) {
    SpringApplication.run(SpringRestConsumerBootstrap.class, args); 
}
 
@Value("${provider.address}") 
private String providerAddress; 
 
@GetMapping(value = "/service") 
public String service(){ 
    RestTemplate restTemplate = new RestTemplate(); //调用服务 
    String providerResult = restTemplate.getForObject("http://" + providerAddress + 				   "/service",String.class); return "consumer invoke | " + providerResult; 
} 
}

RestTemplate工具类,spring提供的一个HTTP请求工具

在服务的调用过程中,使用到了一个工具,叫做 RestTemplate,RestTemplate 是由 Spring 提供的一个 HTTP 请求工具。在上文的案例中,开发者也可以不使用 RestTemplate ,使用 Java 自带的 HttpUrlConnection 或者经典的网络访问框架 HttpClient 也可以完成上文的案例,只是在 Spring 项目中,使用 RestTemplate 显然更方便一些。在传统的项目架构中,因为不涉及到服务之间的调用,大家对 RestTemplate 的使用可能比较少

总结:

关键: application.yml中配置provider.address属性,拼凑出地址后,使用restTemplate.getForObject方法进行调用!

但是,微服务可能是部署在云环境的,服务实例的网络位置或许是动态分配的。另外,每一个服务一般会有多个实

例来做负载均衡,由于宕机或升级,服务实例网络地址会经常动态改变。再者,每一个服务也可能应对临时访问压

力增加新的服务节点。正如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pK72PVE8-1656345257369)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627192149824.png)


nacos服务注册的实现

(服务发现(让服务之间互相感知)与管理问题)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9PJda5TR-1656345257369)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627192235974.png)

(1)在每个服务启动时会向服务发现中心上报自己的网络位置。这样,在服务发现中心内部会形成一个服务注册

服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库。

(2)服务发现客户端会定期从服务发现中心同步服务注册表 ,并缓存在客户端。

(3)当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地

址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。

总结一下,在微服务环境中,由于服务运行实例的网络地址是不断动态变化的,服务实例数量的动态变化 ,因此无

法使用固定的配置文件来记录服务提供方的网络地址,必须使用动态的服务发现机制用于实现微服务间的相互感

。各服务实例会上报自己的网络地址,这样服务中心就形成了一个完整的服务注册表,各服务实例会通过服务发

现中心来获取访问目标服务的网络地址,从而实现服务发现的机制。

服务注册的实现极其简单:

(下面这个例子是从 海马程序员-服务发现中,摘出来的部分代码,像@EnableFeignClients如果仅为实现服务注册而不实现feign调用其他微服务,那它是多余的)

(为了更深刻理解,看源文档 nacos-服务发现.pdf (文档视频中有,我的博客中也有) or 黑马nacos-服务发现 视频)

  1. application.yml配置

    server: 
    	port: 56020 #启动端口 命令行注入 
    	
    spring: 
    	application: 
    		name: quickstart‐consumer 
    	cloud: 
    		nacos: 
    			discovery: 
    				server‐addr: 127.0.0.1:8848
    

    2.Provider(生产者)远程代理定义

@SpringBootApplication 
@EnableDiscoveryClient 
@EnableFeignClients #开启FeignClient,如果只是实现服务注册,不使用feign调用其他微服务的话,就没必要了
public class NacosConsumerApp { 
    public static void main(String[] args) { 
        SpringApplication.run(NacosConsumerApp.class, args); 
    } 
}

Note: @EnableDiscoveryClient 在spring cloud项目中表明此项目是一个注册发现客户端,这里注册服务发

现使用的是Nacos

Note: @EnableFeignClients 开启FeignClient

可以说,实现服务注册,只需要: @EnableDiscoveryClient 就行!!!


有了nacos服务注册中心时,利用feign(ribbon)进行微服务调用

spring(boot)使用feign需在pom.xml中加入依赖:

<dependency> 
	<groupId>org.springframework.cloud</groupId> 
	<artifactId>spring‐cloud‐starter‐openfeign</artifactId> 
</dependency>

参考前面 没有nacos服务注册中心时,微服务调用 的ServiceA调用ServiceB的例子,我们有了 在服务注册后 使用Feign实现这个过程,代码如下:

Service B暴露"/service"服务端点,如下:

@SpringBootApplication 
@RestController
public class SpringRestProviderBootstrap { 
    public static void main(String[] args) 
    { 
        SpringApplication.run(SpringRestProviderBootstrap.class, args); 
    }
@GetMapping(value = "/service") 

//暴露服务 
public String service(){ return "provider invoke"; } }

Service A中,通过Feign调用Service B方式如下:

(1)声明Feign客户端

@FeignClient(value = "serviceB") 
public interface ServiceBAgent { 

    /** 
    * 根据用户名查询账号信息 
    * @param username 用户名 
    * @return 账号信息 
    */ 
//Feign英文表意为“假装,伪装,变形”,此处正是将HTTP报文请求方式 伪装为简单的java接口(内部,未通过TTTP)调用方式
@GetMapping(value = "/service") 
public String service(); }

Feign是Netflflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。Feign

的英文表意为“假装,伪装,变形”, 可以理解为将HTTP报文请求方式伪装为简单的java接口调用方式。

(2)业务调用

@Autowired 
private ServiceBAgent serviceBAgent.; 
//....略 
serviceBAgent.service();
//....略
  • 在 声明Feign客户端 之后,Feign会根据**@FeignClient注解使用java的动态代理技术生成代理类**,在这里我们

指定@FeignClient value为serviceB,则说明这个类的远程目标为spring cloud的服务名称为serviceB的微服

务。

  • serviceB的具体访问地址,Feign会交由ribbon获取,若该服务有多个实例地址,ribbon会采用指定的负载均

    衡策略选取实例。 (Feign默认集成了Ribbon,可以直接使用)

    可通过下面方式在spring boot 配置文件中修改默认的负载均衡策略:

    account‐service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
    

    account-service 是调用的服务的名称,后面的组成部分是固定的。

  • Feign兼容spring的web注解(如:@GetMapping),它会分析声明Feign客户端方法中的Spring注解,得出

    Http请求method、参数信息以及返回信息结构。

  • 当业务调用Feign客户端方法时,会调用代理类,根据以上分析结果,由代理类完成实际的参数封装、远程

    http请求,返回结果封装等操作。


  • 综合架构演示:

由于Feign是基于Http Restful的调用,在高并发下的性能不够理想,我们将RPC方案从feign切换为Dubbo, 将Spring Cloud与阿里系的若干组件完美集成()

系统架构图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5hEqqxd-1656345257370)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627201408150.png)

  • service-api的作用:

    优劣:

    取舍:

  • Service2配置(纯生产者):

    package com.itheima.microservice.service2.service; 
    @org.apache.dubbo.config.annotation.Service 
    public class ProviderServiceImpl implements ProviderService { 
       @Override 
       public String service() { 
           return "Provider invoke"; 
       } 
    }
    

    其中, @org.apache.dubbo.config.annotation.Service 是 Dubbo 服务注解,仅声明该 Java 服务(本地)实现

    为 Dubbo 服务。 因此,下一步需要将其配置 Dubbo 服务(远程)。

    配置 Dubbo 服务

    在暴露 Dubbo 服务方面,推荐开发人员外部化配置的方式,即指定 Java 服务实现类的扫描基准包

    Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注 @DubboComponentScan 来实现基准包扫描。

    同时,Dubbo 远程服务需要暴露网络端口,并设定通讯协议,完整的 YAML 配置如下所示:

    server: port: ${port:56040} #启动端口 命令行注入 
    spring: application: 
    	name: service2 
    	main: 
    		allow‐bean‐definition‐overriding: true # Spring Boot 2.1 需要设定 
    	cloud: 
    		nacos: 
    			discovery: 
    				server‐addr: 127.0.0.1:8848 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 
    				cluster‐name: DEFAULT 
    			config: server‐addr: 127.0.0.1:8848 # 配置中心地址 
    				file‐extension: yaml 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 # 开发环境 
    				group: NACOS_MICROSERVICE_GROUP # xx业务组 
    				dubbo: 
    					scan: # dubbo 服务扫描基准包 
    					base‐packages: com.itheima.microservice protocol: # dubbo 协议 
    					name: dubbo # dubbo 协议端口( ‐1 表示自增端口,从 20880 开始) 
    					port: ${dubbo_port:20891} 
    			registry: 
    				address: nacos://127.0.0.1:8848 
    			application: 
    				qos‐enable: false 
    			consumer: 
    				check: false
    

    核心:

    标注 @DubboComponentScan 来实现基准包扫描;Dubbo 远程服务需要暴露网络端口

    • dubbo.scan.base-packages : 指定 Dubbo 服务实现类的扫描基准包,将@org.apache.dubbo.confifig.annotation.Service注解标注的service暴露为dubbo服务

    • dubbo.protocol : Dubbo 服务暴露的协议配置,其中子属性 name 为协议名称, port 为dubbo协议端口 可以指定多协议,如:dubbo.protocol.rmi.port=1099

    • dubbo.registry : Dubbo 服务注册中心配置,其中子属性 address 的值 “nacos://127.0.0.1:8848”,说明dubbo服务注册到nacos ,相当于原生dubbo的xml配置中的 <dubbo:registry address=“10.20.153.10:9090” />

    启动服务提供方应用

    Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别,如下所示:

    @SpringBootApplication 
    @EnableDiscoveryClient 
    public class Service2Bootstrap { 
    	public static void main(String[] args) { 
            SpringApplication.run(Service2Bootstrap.class, args); 
        }
    }
    
  • Service1配置(生产者&消费者):

    实现dubbo服务

    package com.itheima.microservice.service1.service; 
    @org.apache.dubbo.config.annotation.Service  
    //能替换成 import org.apache.dubbo.config.annotation   @Service
    public class ConsumerServiceImpl implements ConsumerService { 
        @Override
        public String service() { 
            return "Consumer invoke " ; 
        } 
    }
    

    使用@org.apache.dubbo.confifig.annotation.Service标记dubbo服务

    bootstrap.yml配置文件与Service2一致

    pom.xml引入 spring-cloud-starter-dubbo依赖,它会根据接口生成代理对象

    <dependency> 
    	<groupId>com.alibaba.cloud</groupId> 
    	<artifactId>spring‐cloud‐starter‐dubbo</artifactId> 
    </dependency>
    

    实现Service1调用Service2

    @org.apache.dubbo.config.annotation.Service 
    public class ConsumerServiceImpl implements ConsumerService { 
        @Reference 
        ProviderService providerService; 
        public String service() { 
            return "Consumer invoke | "+providerService.service(); 
        } 
    }
    

    关键:

    使用@Reference 注入 代理对象! (引入的dubbo依赖只在此处使用,引导类处不会像feign的使用一样有@EnableFeignClients注释)

    Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别(引导类处不会像feign的使用一样有@EnableFeignClients注释)

  • Application1配置:

    实现 application1调用Service1

    @RestController 
    public class Application1Controller { 
        @org.apache.dubbo.config.annotation.Reference 
        private ConsumerService consumerService; 
        
        @GetMapping("/service") 
        public String service(){ 
            return "test" + consumerService.service(); 
        } 
    }
    

    测试: 请求:http://localhost:56020/application1/service

    consumerService正常生成代理对象,service1被调用。

  • zuul配置:

    原来的单体架构,所有的服务都是本地的,UI可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在

    独立的虚拟机上的 Java进程了。客户端UI如何访问?他的后台有N个服务,前台就需要记住管理N个服务,一个服

    务下线/更新/升级,前台就要重新部署,这明显不服务我们拆分的理念,特别当前台是移动应用的时候,通常业务

    变化的节奏更快。另外,N个小服务的调用也是一个不小的网络开销。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VujOFLBE-1656345257371)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627233329623.png)

    • Zuul网关的作用:

    • 提供统一服务入口,让微服务对前台透明

    • 聚合后台的服务,节省流量,提升性能

    • 提供安全,过滤,流控等API管理功能

    Spring Cloud Zuul是整合Netflflix公司的Zuul开源项目实现的微服务网关,它实现了请求路由、负载均衡、校验过

    等 功能。

    • Zuul与Nginx怎么配合使用?

    Zuul与Nginx在实际项目中需要配合使用,如下图,Nginx的作用是反向代理、负载均衡,Zuul的作用是保障微服

    务的安全访问,拦截微服务请求,校验合法性及负载均衡。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hKW870pZ-1656345257372)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627233539020.png)

    api-gateway配置

    server: 
    	port: 56010 #启动端口 命令行注入 
    spring: 
    	application: 
    		name: api‐gateway 
    	main: 
    		allow‐bean‐definition‐overriding: true # Spring Boot 2.1 需要设定 
    	cloud: 
    		nacos: 
    			discovery: 
    				server‐addr: 127.0.0.1:8848 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 
    				cluster‐name: DEFAULT 
    			config: 
    				server‐addr: 127.0.0.1:8848 # 配置中心地址 
    				file‐extension: yaml 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 # 开发环境 
    				group: NACOS_MICROSERVICE_GROUP # xx业务组
    

    网关的路由配置采用nacos远程配置,在nacos控制台开发环境中新增api-gateway.yaml配置集,配置组为

    TEST_GROUP,配置内容如下:

    zuul: 
    	routes: 
    		application1: 
    			stripPrefix: false 
    			path: /application1/**
    

    将请求为 /application1/ 开头的请求路由至 application1 服务,保留请求url中的 /application1/

    api-gateway启动:

    注意在启动类上使用@EnableZuulProxy注解标识此工程为Zuul网关,启动类代码如下:

    @SpringBootApplication 
    @EnableDiscoveryClient 
    @EnableZuulProxy 
    public class ApiGatewayBootstrap { 
        public static void main(String[] args) { 
            SpringApplication.run(ApiGatewayBootstrap.class, args); 
        } 
    }
    

    浏览器访问: http://127.0.0.1:56010/application1/service (相当于UI 前端 get请求)

    通过网关(api-gateway)请求Application1应用,Application1的业务实现又贯穿service1、service2

使用@org.apache.dubbo.confifig.annotation.Service标记dubbo服务


杂记:

浏览器中输入:

http://127.0.0.1:56020/service

相当于前端发送get请求,请求地址(url)为:http://127.0.0.1:56020/service,即 服务器:http://127.0.0.1 端口:56020 的service后端接口

但是,还是postman好用,能够发出post请求

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值