NJU-服务端开发课程笔记

涉及Spring、Springboot、Spring Cloud、反应式编程等后端常用技术栈

Lecture 1 第一个Spring boot程序

  • git
  • 一个简单的springboot程序
    • 框架
    • maven
    • themyleaf快速构建网页
    • liveroad热部署
  • Junit
    • (public) void开头
    • assert
    • StandardOutputStreamLog工具可以收集打到控制台的内容

Lecture 2 spring依赖注入

spring的核心是提供了容器+依赖注入+AOP切面编程

  • bean在容器之中

  • 库存Bean注入到商品Bean中(在商品类中,spring帮忙new 库存)

    • 三种注入方式:

      • 类的构造方法
      • setter方法,set属性
      • 私有属性上加@Autowired
    • 不可以通过方法参数注入

  • image-20230914185655677

三种配置Bean方式

  • 顺便配置Bean间的依赖关系

  • image-20230914185947340

Bean的生命周期

  • 方便自定义override
  • 实例化(new)
  • name:获取名字
    • @Override setBeanName
  • factory:产生工厂接口
  • context
    • @Override setApplicationContext以获取Bean信息,在业务逻辑中使用
  • 销毁

应用上下文

  • 建议根据接口编程

自动化配置例子(优先):

  • @Component:将Class注册实例化为Bean
    • @Component()可以指定Bean的name
  • @Autowured:注入(对象参数/构造器/Setter)时需注解。spring从容器上下文寻找实现了接口的对象,并注入当前类(相当于new 子属性)
    • 若唯一,则返回
    • 若不存在/不唯一,则报错
    • @primary可指定优先注入的类
  • Object=Bean=Component(更业务)
  • @Configuration 总配置类
    • 上下文可以基于配置类来建立(较为推荐)
    • @ComponentScan:扫描文件夹中所有的Bean,建立Spring上下文
      • 等价 <context:component-scan base-package=“…”/>
      • 基础包(basePackages={“…”,”…”})
        • 类型不安全:Scan的文件夹目录会变
        • 解决方案:basePackageClasses={.class,.class}建立TagClass标识根文件夹
    • image-20230914193437131

JavaConfig例子:

  • 不建议把业务代码放入。有可能跳过执行
  • 更适用于改编第三方代码
  • 自动化配置有时会行不通,如:第三方库
  • @Configuration:配置类
  • @Bean(name=“..”):提供实例化Bean的逻辑
    • Spring的Bean默认使⽤单例模式,只会创建⼀个:在调⽤构造⽅法时会被Spring截获,如果已经new过了就不会再继续new。也可以⼿动指定不⽤Singleton模式(@Scope带参数,可以指定prototype,⽤⼀个创建⼀次

xml例子(特殊场景):

  • 构造器注入
    • c-命名空间
    • 注入字面量值 vase
    • 注入集合
  • 属性注入
    • p-命名空间
    • util-命名空间
  • ref:引用(用于如list构造、constructor-arg)
  • value:赋值

混合配置类例子:

  • image-20230914205612870

  • @Configuration

    @Import(xxx.class)

    @ImportResource(“//xml path”)

  • XML中导入

    • <import resource=’xml’/>

—往后考试不考—

Profile选择性配置,类似#ifdef:

  • 方法定义:
    • @Bean
    • @Profile(“prov”)
  • 激活
    • spring.profiles.default
    • spring.profiles.active
    • @ActiveProfiles(“dev”)

Conditional条件注入例子:

  • @Bean或@Component

  • @Conditional(**.class)

  • 接口

    • Condition{

      boolean matches(…)

      }

自动装配的歧义:

  • @Primary优先注入
  • 定义时
    • @Componet或@Bean
    • @Qualifier(“…”)自定义限定符
  • 使用时
    • @Autowired
    • @Qualifier(“…”) bean名称或自定义限定符,默认Bean名是限定符

Lecture 3 AOP切面编程

横切关注点(cross-cutting concern)

  • 关注共有的可以抽象出来的操作
    • image-20230921192144754
  • 举例:
    • 日志
    • 安全
    • 事务
    • 缓存

AOP术语

  • 通知(Advice):切面做什么以及何时做
    • what + when
  • 切点(Pointcut):何处
    • 具体where
  • 切面(Aspect):Advice和Pointcut的结合
  • 连接点(Join point):方法(spring ) | 字段修改、构造方法(其他)
    • 可以切的地方
  • 引入(introduction):引入新的行为和状态
    • 动态给类添加新方法
  • 织入(Weaving):切面应用到目标对象的过程

通知(Advice)类型

  • @Before 在某连接点之前执行的通知
    • “execution(* 包名.接口名.方法名(参数类型) )”
    • 实例化切面Bean,注解
  • @After
  • @AfterReturning
  • @AfterThrowing 出现意外
  • @Around 环绕通知可以在方法调用前后完成自定义的行为
    • 相当于前四个的混合,更自由。可以控制返回值
    • joinPoint.proceed() 调用切面方法
  • image-20230921201439967
    • image-20230921194712381
    • image-20230921194937329
    • image-20230921194952447
  • 原理:Proxy代理
    • image-20230921201906728
    • image-20230921200647533

切点指示器

  • Pointout法
    • @Pointcut( “execution(* soundsystem.CompactDisc.playTrack( int )) “ + “&& args(trackNumber) //获取参数
      && within(soundsystem.*) //限定包路径
      && bean(sgtPeppers) “) //限定bean名称,或者: && !bean(sgtPeppers)
  • 注解法
    • @Around(“@annotation(innerAuth)”) //限定注解
      public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) { … }
      @InnerAuth public R register(@RequestBody SysUser sysUser) { … }

多代理类注入

  • 增强Bean。在不改变原类的前提下,利用切面新增方法
  • image-20230921212102249
  • image-20230921212516346

Lecture 4 spring MVC

model -view-control

  • image-20230930002053524
  • image-20231007183839364 * 1.必经servlet * 2.映射路径 * 3.获取参数,映射到controller * 4.servlet通过controller获取数据与视图 * 5.servlet解析视图

类前注解

  • @Slf4j:这是Lombok库提供的注解,用于自动生成日志记录器(Logger)。在使用@Slf4j注解后,可以直接使用log字段进行日志记录,而无需手动创建Logger对象。例如,log.info("Message")
  • @Controller:等价于@component。这是Spring框架提供的注解,用于标识一个类作为控制器组件。控制器处理传入的HTTP请求,并返回相应的视图或数据。使用@Controller注解后,Spring会自动识别该类并将其作为控制器进行管理。
  • @RequestMapping("/design"):这是Spring MVC框架提供的注解,用于映射HTTP请求到相应的处理方法。在这个例子中,@RequestMapping注解指定了路径为”/design”,表示该控制器处理的请求路径为”/design”开头的请求。

请求映射注解

  • @RequestMapping
  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

模型数据绑定

  • @ModelAttribute:这是 Spring MVC 框架提供的注解,用于将方法参数或方法返回值绑定到模型中。当使用 @ModelAttribute 注解修饰方法时,该方法会在每次请求处理之前被调用,用于准备模型数据。当使用 @ModelAttribute 注解修饰方法参数时,它会从模型中获取对应的属性值,并将其绑定到方法参数中。

    • @ModelAttribute标注在方法上时,说明该方法是用于添加一个或多个属性到model上;这样的方法能接收@RequestMapping注解相同的参数类型,只不过不能直接被映射到具体的请求上;

      • 当@ModelAttribute注解标注返回值为void的方法时,需要传入Model参数,并使用model.addAttribute()方法手动的往Model上绑定数据。
    • @ModelAttribute标注在方法参数上时,说明该方法参数的值将由model中取得;如果model中找不到,那么该参数会先被实例化,然后被添加到model中;在model中存在以后,请求中所有名称匹配的参数都会填充到该参数中;

    • 这在Spring MVC中被称为数据绑定,一个非常有用的特性,我们不用每次都手动从表格数据中转换这些字段数据;

  • @SessionAttributes:这是 Spring MVC 框架提供的注解,用于指定模型属性的值将存储在会话(Session)中。通过 @SessionAttributes 注解,可以将模型中的指定属性值暂时存储在会话中,以便在多个请求之间共享该属性的值。通常与 @ModelAttribute 注解一起使用,以确保在多个请求之间保持一致的模型属性值

  • Model属性会复制到Servlet Request属性中,这样视图中就可以使用它们用于渲染页面

    • Servlet Request 是 Java Servlet 规范中定义的一个类,用于表示客户端发起的 HTTP 请求。它包含了请求的各种信息,如请求方法、URL、请求头、请求参数等。通过 Servlet Request,开发人员可以获取并处理客户端发送的请求数据。
    • servlet是⼀个⼩粒度的运⾏单位
      • Tomcat:webserver 是⼀个web容器,可运⾏,⾥⾯装的是servlet(有许多servlet)
      • servlet处理客户端请求request,返回response

SpringMVC获取参数的方式 、Converter

  • Converter 负责将前端传来String格式的表单,转换成Ingredient
  • image-20231007184128914

校验

  • 领域类上添加校验规则
  • 控制器中声明校验:@Valid

使用视图控制器(View Controller)

  • 如果一个控制器非常简单,不需要填充模型或处理输入
  • 继承接口WebMvcConfigurer,用于配置
  • 简单的从请求URL到视图 registry.addViewController(“/“).setViewName(“home”); //GET请求
  • image-20231001123912054

@data

  • 生成setter和getter
  • Lombok是编译期的东西

Lecture 5 数据持久化

Java数据库连接(Java Database Connectivity,JDBC)和Java持久化API(Java Persistence API,JPA)是两个常用的技术。

JDBC

是Java平台提供的一组API,用于在Java应用程序和各种关系型数据库之间建立连接和执行数据库操作。JDBC允许开发人员使用Java代码来执行诸如查询、插入、更新和删除等数据库操作。它提供了一种标准的方式来访问不同数据库系统,独立于具体的数据库实现。通过JDBC,开发人员可以使用Java语言编写数据库驱动程序,连接到数据库并执行SQL语句。

  • JDBC的主要组件包括:

    • DriverManager:用于管理数据库驱动程序的类,负责建立数据库连接。

    • Connection:表示与数据库的连接,可以执行SQL语句和事务管理。

    • Statement:用于执行SQL语句的接口,包括创建、执行和处理结果等操作。

    • ResultSet:表示数据库查询结果集,可以遍历和操作查询结果。

  • 使用JDBC时,开发人员需要手动编写SQL语句、处理连接、事务和结果集等细节。虽然JDBC提供了灵活性和直接控制数据库的能力,但对于大型应用程序或复杂的数据库操作,编写和维护大量的JDBC代码可能变得繁琐和冗长。

JDBC template

  • JdbcTemplate是Spring Framework提供的一个用于简化JDBC(Java Database Connectivity)操作的类库。它封装了JDBC的底层细节,提供了一组简单而强大的方法来执行SQL查询、更新和批处理等操作。
  • JdbcTemplate简化了JDBC的使用,减少了样板代码的编写,并提供了异常处理和资源管理等功能。它是Spring框架中数据访问对象(DAO)模式的核心组件之一,用于与关系型数据库进行交互。
  • H2数据库是一个基于Java的嵌入式关系型数据库管理系统(RDBMS)。它提供了一个轻量级、快速、可嵌入的数据库解决方案,适用于开发和测试环境。H2数据库支持标准SQL语法和JDBC API,可以通过内存模式或嵌入式模式在应用程序中嵌入和使用。
    • image-20231008142847877

生成TABLE

如果在应⽤的根类路径下存在名为schema.sql的⽂件,那么在应⽤启动的时候将会基于数据库执⾏这个⽂件中的SQL。所以,我们需要将程序清单3.8中的内容保存为名为schema.sql的⽂件并放到“src/main/resources”⽂件夹下。

我们可能还希望在数据库中预加载⼀些配料数据。幸运的是,Spring Boot还会在应⽤启动的时候执⾏根类路径下名为data.sql的⽂件。将其保存到“src/main/resources/data.sql”⽂件中。

  • 其他方法:
  • CommandLineRunner
  • Applycation.run

Repository的实现

  • @Repository
  • 接口: RowMapper,可以使用lambda表达式
  • 注入DesignTacoController,使用IngredientByldConverter实现优化
  • identity字段由数据库自动生成值,获取返回的ID,GeneratedKeyHolder
    • PreparedStatementCreatorFactory
    • PreparedStatementCreator
    • jdbcOperations.update

异常体系

  • QLException
    • 发生异常时很难恢复 ✓ 难确定异常类型
  • Hibernate异常
    • 定义了许多具体异常,方便定位问题 ✓ 对业务对象的侵入
  • Spring所提供的平台无关的持久化异常
    • DataAccessException ✓ 具体异常,方便定位问题 ✓ 隔离具体数据库平台

JPA

是Java平台的Java持久化规范,提供了一种更高级别的抽象,用于简化Java应用程序与数据库之间的交互。JPA的目标是提供一种对象关系映射(Object-Relational Mapping,ORM)的解决方案,将Java对象与数据库表之间进行映射。

  • JPA的核心概念包括:

    • 实体类(Entity):用于表示数据库中的表,通过注解或XML配置与数据库表进行映射。

    • EntityManager:类似于JDBC中的Connection,用于管理实体对象的生命周期、执行数据库操作以及处理事务。

    • JPQL(Java Persistence Query Language):类似于SQL的查询语言,用于查询和操作实体对象。

  • JPA提供了一种面向对象的编程模型,将数据库操作转化为对Java对象的操作,避免了直接编写SQL语句和处理数据库连接的繁琐工作。它还提供了缓存、延迟加载、事务管理等高级特性,简化了开发过程并提高了应用程序的可维护性。

  • JPA是一个规范,不是具体的实现。常见的JPA实现包括Hibernate、EclipseLink、OpenJPA等。开发人员可以根据具体需求选择适合的JPA实现来与数据库进行交互,并使用JPA提供的API进行开发。

综上所述,JDBC是一种低级别的数据库访问API,提供了直接的数据库连接和操作能力,而JPA是一种高级别的ORM规范,提供了更简化和面向对象的数据库访问方式。在选择使用JDBC还是JPA时,需要根据具体的应用场景和需求来决定。

生成TABLE

  • @Entity
  • @Table(name=”Taco_Order”)
  • @OneToMany
    • 生成关联表
  • @NoArgsConstructor注解。JPA需要实体有⼀个⽆参的构造器.

repository查询方法

继承CRUD

  • image-20231008164713521
  • image-20231008164834610

定义查询方法,无需实现

  • 领域特定语言(domain-specific language,DSL),spring data的命名约定
  • 查询动词+主题+断言
  • 查询动词: get、read、find、count
  • 例子:
    List findByDeliveryZip( String deliveryZip );

声明自定义查询

  • 不符合方法命名约定时,或者命名太长时

  • @Query(“Order o where o.deliveryCity = ‘Seattle”)

    List readOrdersDeliveredInSeattle( );

两个好处

  • 便于做mock测试
  • 更改时只需更改Repository

Lecture 6 非关系数据库

MongeDB

  • 分布式
  • 类json格式
  • image-20231012185636855
  1. 基本的CRUD操作:
    • 创建数据库:使用use <database_name>命令创建一个新的数据库。
    • 创建集合:使用db.createCollection("<collection_name>")命令创建一个新的集合。
    • 插入文档:使用db.<collection_name>.insertOne(<document>)命令插入一个文档到指定集合。
    • 查询文档:使用db.<collection_name>.find(<query>)命令查询符合条件的文档。
    • 更新文档:使用db.<collection_name>.updateOne(<filter>, <update>)命令更新符合条件的文档。
    • 删除文档:使用db.<collection_name>.deleteOne(<filter>)命令删除符合条件的文档。
  2. 高级查询和操作:
    • 使用查询运算符和条件语句来执行更复杂的查询操作。
    • 学习索引的创建和使用,以提高查询性能。
    • 学习如何使用聚合管道进行数据聚合和数据处理操作。
    • 学习MongoDB的数据备份和恢复方法,以及复制和分片等高可用性和扩展性特性。

Redis

  • Key-value的Hash表结构

  • 存在内存,速度快。也可以持久化

  • 主要作缓存。低延迟

  • 常用作集群,有主从复制

  1. Redis的基本操作:
    • 设置键值对:使用SET命令设置一个键值对。
    • 获取值:使用GET命令获取一个键对应的值。
    • 存储列表:使用LPUSHRPUSH命令将值添加到列表的左侧或右侧。
    • 存储哈希:使用HSET命令将字段和值添加到哈希中。
    • 存储集合:使用SADD命令将值添加到集合中。
    • 存储有序集合:使用ZADD命令将带有分数的成员添加到有序集合中。
  2. Redis的高级功能:
    • 使用过期时间:设置键的过期时间,让Redis自动删除过期的键。
    • 发布和订阅:使用PUBLISH命令发布消息,使用SUBSCRIBE命令订阅消息。
    • 事务:使用MULTIEXEC命令执行一系列命令作为一个事务。
    • Lua脚本:使用Redis的Lua脚本功能执行复杂的操作。
    • 持久化:了解Redis的持久化机制,将数据保存到磁盘上。
  • 链接java

    • 新增键值对

      • redis.opsForValue().set(product.getSku(), product);
        
        1
        2
        3
        4
        5
        6
        7



        * 新增set

        * ```
        redisTemplate.opsForSet().add("cart", product);
  • 序列化是必须的

    • image-20231012205511018

    • redis.setKeySerializer(new StringRedisSerializer());
      redis.setValueSerializer(new Jackson2JsonRedisSerializer<Product>(Product.class));
      redis.afterPropertiesSet(); // if this were declared as a bean, you wouldn't have to do this
      
      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

      # Lecture 7 Spring Securety

      ## cookie

      * HTTP 协议是一种用于在客户端和服务器之间传输超文本的协议。它是无状态的,这意味着每个请求都是独立的,服务器不会记住之前的请求。然而,有时候需要在多个请求之间保持一些状态信息,这就是 Cookie 的作用。
      * 当服务器发送 HTTP 响应时,它可以在响应头中包含一个 Set-Cookie 标头,其中包含了一个或多个键值对,用于设置 Cookie 的属性,如名称、值、过期时间、域名、路径等。客户端(通常是Web浏览器)在接收到这个响应时会将这些 Cookie 保存在本地。
      * 之后,当客户端发送新的 HTTP 请求时,它会在请求头中包含一个 Cookie 标头,其中包含了保存的 Cookie 信息。服务器可以读取这些 Cookie,识别客户端,并根据需要采取相应的操作。例如,服务器可以使用 Cookie 来跟踪用户的会话、存储用户的首选项、实现购物车功能,判断客户端是否登录。

      ## Basic 认证

      在 HTTP 协议中,Basic 认证是一种简单的身份验证机制。它通过在 HTTP 请求的头部添加一个名为 "Authorization" 的字段,将用户名和密码以 Base64 编码的形式发送给服务器来进行身份验证。

      Basic 认证的工作流程如下:

      1. 客户端发送 HTTP 请求到服务器,并在请求头部添加 "Authorization" 字段。
      2. "Authorization" 字段的值为 "Basic" 加上用户名和密码的 Base64 编码。格式为:`Basic <base64encoded(username:password)>`
      3. 服务器接收到请求后,检查 "Authorization" 字段的值。
      4. 服务器将 "Authorization" 字段的值进行解码,并获取用户名和密码。
      5. 服务器使用解码后的用户名和密码进行验证,通常是比对存储在服务器上的用户凭据。
      6. 如果验证成功,服务器返回请求的资源;如果验证失败,服务器返回 HTTP 401 Unauthorized 响应。

      ## Securety

      用户需要做的:![image-20231026184904538](https://lar-blog.oss-cn-nanjing.aliyuncs.com/picGo_img/AppData/Roaming/Typora/typora-user-images/image-20231026184904538.png)

      1. 继承UserDetailsService,自定义User类
      2. 实现登录视图
      3. 实现FilterChain,配置合法用户
      1. `FilterChain` 是 Spring Security 中的过滤器链,用于处理请求的安全过滤器。每个请求都会经过一系列的过滤器,用于验证身份、授权访问等操作。过滤器链由多个过滤器组成,并按照一定的顺序依次执行。
      2. 身份验证:过滤器链中的某些过滤器负责身份验证,检查请求中的身份凭证(如用户名和密码、令牌等),并将其与预先配置的用户信息进行比对,以确定请求是否来自有效的身份。
      3. 访问控制:过滤器链中的其他过滤器负责访问控制,根据配置的规则和权限信息,判断请求是否有权限访问特定的资源。根据规则的配置,可以允许或拒绝请求的访问。
      4. 处理安全相关的操作:过滤器链还可以处理一些安全相关的操作,如跨站请求伪造(CSRF)防护、XSS(跨站脚本攻击)防护、会话管理等。
      4. 继承WebSecurityConfigureAdapter
      1. 重写其中的方法,可以定义安全规则、身份验证方式、访问控制等安全相关的配置。
      2. 提供了默认的安全配置:`WebSecurityConfigurerAdapter` 类提供了一组默认的安全配置,包括关闭跨站请求伪造(CSRF)防护、启用 HTTP Basic 认证、配置默认登录页面等。通过继承并重写需要修改的方法,可以对默认配置进行定制。
      3. 配置安全策略:通过重写 `configure()` 方法,可以添加自定义的安全规则。例如,可以配置哪些 URL 需要进行身份验证、使用哪种身份验证方式、定义访问规则等。这些配置可以基于角色、权限或其他条件来限制用户的访问权限。
      4. 定义认证方式:通过重写 `configure(AuthenticationManagerBuilder)` 方法,可以指定身份验证方式。可以使用内存中的用户、数据库中的用户、LDAP、OAuth 等多种方式进行身份验证。

      框架做的:

      1、实现用户登录控制器(get、post)|
      2、请求重定向到用户登录页面
      3、通过Filter对设定的权限进行控制权限不通过报以下错误:

      ### 自动配置

      Spring Securety加入pom.xml后,会有HTTP basic认证对话框并提示你认证。

      要想通过这个认证,你需要⼀个⽤户名和密码。⽤户名为user,⽽密码则是随机⽣成的,它会被写⼊应⽤的⽇志⽂件中。⽇志条⽬⼤致如下

      * ```sql
      Using default security password: 087cfc6a-027d-44bc-95d7-cbb3a798a1ea

通过将security starter添加到项目的构建文件中,我们得到了如下的自动配置的安全特性∶

  • 所有的HTTP请求路径都需要认证;
  • 不需要特定的角色和权限,
  • 没有登录页面,认证过程是通过HTTP basic认证对话框实现的;
  • 系统只有一个用户,用户名为user

为了满足Taco Cloud的安全需求,我们需要编写一些显式的配置,覆盖掉自动配置为我们提供的功能。我们首先配置一个合适的用户存储,这样就能有多个用户了。

  • 基于内存的用户存储;
  • 基于JDBC的用户存储﹔
  • 以LDAP作为后端的用户存储﹔
  • 自定义用户详情服务。

不管使用哪种用户存储,你都可以通过覆盖
WebSecurityConfigurerAdapter基础配置类中定义的configure()方法来进行配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select username, password, enabled from Users " +
"where username=?")
.authoritiesByUsernameQuery(
"select username, authority from UserAuthorities " +
"where username=?");
}

web请求保护

1
2
3
4
5
6
7
8
9
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests()
.antMatchers("/design", "/orders").hasRole("USER")
.antMatchers("/", "/**").permitAll()
.and()
.build();
}

方法级别保护

1
2
3
4
5
// 我们可以直接在 deleteAllOrders() 方法上应用安全性配置,如下所示:
`@PreAuthorize` ("hasRole('ADMIN')")
public void deleteAllOrders() {
orderRepository.deleteAll();
}

为了使 @PreAuthorize 工作,您需要启用全局方法安全。为此,您需要使用 @EnableGlobalMethodSecurity注解安全配置类.

阻止CSRF攻击

跨站请求伪造(CSRF)是一种常见的安全攻击。它涉及到让用户在一个恶意设计的 web 页面上编写代码,这个页面会自动(通常是秘密地)代表经常遭受攻击的用户向另一个应用程序提交一个表单。例如,在攻击者的网站上,可能会向用户显示一个表单,该表单会自动向用户银行网站上的一个 URL 发送消息(该网站的设计可能很糟糕,很容易受到这种攻击),以转移资金。用户甚至可能不知道攻击发生了,直到他们注意到他们的帐户中少了钱。

为了防止此类攻击,应用程序可以在显示表单时生成 CSRF token,将该 token 放在隐藏字段中,然后将其存储在服务器上供以后使用。提交表单时,token 将与其他表单数据一起发送回服务器。然后服务器拦截请求,并与最初生成的 token 进行比较。如果 token 匹配,则允许继续执行请求。否则,表单一定是由一个不知道服务器生成的 token的恶意网站呈现的。

获取用户信息

然而,也许最干净的解决方案是简单地接受 processOrder() 中的用户对象,但是使用@AuthenticationPrincipal 对其进行注解,以便它成为身份验证的主体:

1
2
3
4
5
6
7
8
9
10
11
12
13
@PostMapping
public String processOrder(@Valid TacoOrder order, Errors errors,
SessionStatus sessionStatus,
@AuthenticationPrincipal User user) {
if (errors.hasErrors()) {
return "orderForm";
}
order.setUser(user);
orderRepo.save(order);
sessionStatus.setComplete();
return "redirect:/";

}

@AuthenticationPrincipal 的优点在于它不需要强制转换(与身份验证一样),并且将特定于安全性的代码限制为注释本身。当在 processOrder() 中获得 User 对象时,它已经准备好被使用并分配给订单了。

三种方式

  1. DesignTacoController
    参数: Principal principal
    String username = principal.getName();
  2. OrderController
    @AuthenticationPrincipal User user
  3. 安全上下文获取
    Authentication authentication = SecurityContextHolder.getContext(getAuthentication();
    User user = (User) authentication.getPrincipal();

Lecture 8 属性配置

属性使用方法

四种属性来源( property source)

  • application.properties、application.yml: server.port = 8090
  • 命令行参数( commandLineArgs ) : java -jar taco-cloud-sd-jdbc-0.0.3-SNAPSHOT.jar –server.port=8081
  • JVM系统属性: java -Dserver.port=8091 -jar taco-cloud-sd-jdbc-0.0.3-SNAPSHOT.jar
  • 操作系统环境变量:set SERVER_PORT=8082、java -jar taco-cloud-sd-jdbc-0.0.3-SNAPSHOT.jar

Https(考试略

  • HTTPS (Secure Hypertext Transfer Protocol)安全超文本传输协议,是一个安全通信通道,它基于HTTP开发用于在客户计算机和服务器之间交换信息。它使用安全套接字层(SSL)进行信息交换,简单来说它是HTTP的安全版,是使用TLS/SSL加密的HTTP协议。HTTP协议采用明文传输信息,存在信息窃听、信息篡改和信息劫持的风险,而协议TLS/SSL具有身份验证、信息加密和完整性校验的功能,可以避免此类问题发生。
    • SSL(Secure Sockets Layer安全套接字协议),及其继任者传输层安全(Transport Layer Security ,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层与应用层之间对网络连接进行加密。

单双向验证(考试略

image-20231026200525305

image-20231026200936146

秘钥配置(考试略

生成密钥库

  • keytool -genkey -alias tomcat -keyalg RSA -storetype PKCS12 -storepass letmein -keystore mykeys.p12
  • 密钥库类型: PKCS12
  • image-20231026205420773

查看密钥库

  • keytool -list -keystore mykeys.p12 -storepass letmein

keytool基本使用

  • 生成key和库
    keytool -genkey -v -alias key别名-keyalg RSA -storetype PKCS12 -keystore库文件名.p12
  • 导出证书
    keytool -keystore库文件名.p12-export -alias key别名-file证书文件名.cer
  • 打印证书信息
    keytool -printcert -file证书文件名.cer
  • 导入证书到库
    keytool -import -v -file证书文件名.cer -keystore库文件名.p12

SSL配置(考试略

image-20231026214759577启用 SSL(Secure Sockets Layer)协议来加密和保护应用程序的通信。下面是对配置中各个属性的解释:

  • server.port: 8443: 指定应用程序的端口号为 8443。这是应用程序监听的 HTTPS 连接的端口号。
  • ssl.key-store: classpath:mykeys.p12: 指定使用的密钥库文件的路径和名称。classpath: 前缀表示从类路径中加载密钥库文件,即在应用程序的资源目录下。
  • ssl.key-store-password: letmein: 指定密钥库的密码,用于访问密钥库文件的内容和密钥对。
  • ssl.key-password: letmein: 指定密钥的密码,用于访问密钥库中的具体密钥。

这些配置项用于配置应用程序在 HTTPS 模式下监听的端口号、使用的密钥库文件及其密码。通过配置 SSL,应用程序能够使用 HTTPS 协议进行安全的加密通信。

在实际部署中,应根据实际情况配置真实的证书和密钥库,以确保安全性。

配置日志

Spring Boot默认使用Logback,日志配置文件logback.xml

  • 默认日志级别:INFO
  • 分级别、分包目录日志配置(application.yml)
    • logging:
      level:
      root: WARN
      org:
      Springframework:
      security: DEBUG
    • 以上配置的含义是设置根日志级别为 WARN,意味着只有警告级别及以上的日志会被输出。同时,对于包名为 org.springframework.security 下的所有类,将其日志级别设置为 DEBUG,即会输出该包下的所有调试级别的日志信息。

自定义配置属性

  • ConfigurationProperties(prefix= “taco.orders”)
  • @Validated

通过application.yml文件提供值

激活不同配置 Spring profile

  • 定义特定profile的属性,通过使用不同的YAML或属性文件

    • application-{profile名}.properties

    • application-{profile名}.yml

  • 也可以将不同profile属性放到同一个YAML文件中,使用3个短线进行分隔,并且使用spring.profiles属性来命名profile

激活的三种方式

  • 环境变量: spring_profiles_active=prod
  • 命令行参数: java -jar ***.jar –spring.profiles.active=prod
  • JVM系统属性: java -Dspring.profiles.active=prod -jar ****.jar
  • 使用注解@Profile(!prod)条件化地创建Bean,可以加到@Configuration或@Bean上

Actuator

Spring Boot Actuator是Spring Boot提供的一个功能强大的模块,用于监控和管理Spring Boot应用程序。它提供了一组内置的RESTful端点(endpoints),可以用于获取关于应用程序运行时的各种信息,例如健康状况、度量指标、配置属性、日志记录等。

  • Spring Boot Actuator的主要目标是帮助开发人员和运维人员更好地理解和管理应用程序的运行状态和行为,以便监测和调试应用程序,进行性能优化和故障排查。
  • image-20231102185612299

下面是一些Spring Boot Actuator提供的常用端点:

  1. /health:用于检查应用程序的健康状况,包括是否存活和是否就绪。
  2. /info:提供关于应用程序的基本信息,例如应用程序的名称、版本等。
  3. /metrics:用于获取应用程序的度量指标,例如内存使用情况、HTTP请求计数等。
  4. /env:获取应用程序的配置属性和环境变量。
  5. /loggers:用于管理和配置日志记录器,包括查看日志级别、修改日志级别等。
  6. /trace:提供最近的HTTP请求追踪信息,包括请求路径、处理时间等。

Lecture 9 RESTful API

image-20231102191853434

K8s

部署多个pod

REST原则(重要

  • REST:Representational State Transfer:表现层状态转移
  • 表现层(Representation):json、xml、html、pdf、excel
  • 状态转移(State Transfer):服务端–客户端

资源(Resources),就是网络上的一个实体

  • 标识:URI

  • HTTP协议的四个操作方式的动词:GET、POST、PUT、DELETE

    • CRUD:Create、Read、Update、Delete
    • 不需要再在url体现增删改查
  • 如果一个架构符合REST原则,就称它为RESTful架构

前端vue

vue作为桥梁的作用

  • image-20231102191932611

  • Vue所关注的核心是MVC模式中的视图层,同时, 它也能方便地获取数据更新,并通过组件内部特定的方法实现视图与模型的交互

MVVM模型

单文件组件

  • 模板、逻辑和样式在一个组件里,组件更加内聚且更可维护
  • 组件是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用

MVVM

  • 一种用于构建用户界面的软件架构模式,它将应用程序的逻辑和界面进行分离,使代码更易于维护和测试。

下面是对 Vue.js 中 MVVM 架构模式的各个组成部分的介绍:

  1. Model(模型):
    模型代表应用程序的数据和业务逻辑。在 Vue.js 中,模型通常是由 JavaScript 对象或数组表示,包含应用程序的数据和状态。
  2. View(视图):
    视图是用户界面的呈现层,它由 HTML 模板表示。在 Vue.js 中,视图通常是使用 Vue 的模板语法编写的,通过绑定数据和指令来实现动态渲染。
  3. ViewModel(视图模型):
    视图模型是连接视图和模型的桥梁。它是一个 JavaScript 对象,在 Vue.js 中由 Vue 实例表示。视图模型负责管理视图和模型之间的数据绑定和交互逻辑。它通过双向数据绑定将视图的变化反映到模型,并将模型的变化反映到视图。

在 Vue.js 中,视图模型通过定义数据属性和计算属性来表示模型,并使用指令和事件绑定等特性来处理用户输入和响应用户操作。视图模型还提供了一些生命周期钩子函数,用于处理视图的初始化、更新和销毁过程

通过 MVVM 架构模式,Vue.js 实现了数据驱动的视图,即当模型的状态改变时,视图会自动更新,而无需手动操作 DOM。这使得开发人员可以更专注于处理业务逻辑和数据处理,而无需过多关注界面的变化和更新。

REST API

重要理解

  • 对资源(url)的操作
  • 以面向数据的格式返回:JSON或XML

一些注解

  1. @RequestMapping:用于将请求映射到控制器方法或处理程序方法。它可以用于类级别和方法级别的注解,用于定义处理请求的路径、HTTP方法、请求参数等。
    1. produces 指定指定当前方法返回对象的Content-Type。
    2. consumes指定当前方法可以处理的请求Content-Type
  2. @GetMapping:是 @RequestMapping 的缩写形式,用于将 GET 请求映射到方法。它指定了特定的路径,当收到 GET 请求时,将调用对应的方法来处理请求。
    1. params`属性用于指定URL参数过滤条件。该方法仅处理带有”recent”参数的GET请求。
  3. @PostMapping:是 @RequestMapping 的缩写形式,用于将 POST 请求映射到方法。类似于 @GetMapping,它指定了特定的路径,当收到 POST 请求时,将调用对应的方法来处理请求。
    1. @ResponseStatus(HttpStatus.CREATED)表示在POST请求成功后返回状态码201(Created)
  4. @PutMapping:是 @RequestMapping 的缩写形式,用于将 PUT 请求映射到方法。类似于 @GetMapping,它指定了特定的路径,当收到 PUT 请求时,将调用对应的方法来处理请求。
  5. @DeleteMapping:是 @RequestMapping 的缩写形式,用于将 DELETE 请求映射到方法。类似于 @GetMapping,它指定了特定的路径,当收到 DELETE 请求时,将调用对应的方法来处理请求。
    1. 使用@ResponseStatus(HttpStatus.NO_CONTENT)表示成功删除后返回状态码204(No Content)。
  6. @PatchMapping:是 @RequestMapping 的缩写形式,用于将 PATCH 请求映射到方法。类似于 @GetMapping,它指定了特定的路径,当收到 PATCH 请求时,将调用对应的方法来处理请求。
    1. 和Put的区别在于,只更新某一个,相当于补丁
  7. @RestController:是一个组合注解,用于标记一个类为 RESTful Web 服务的控制器。它结合了 @Controller@ResponseBody 注解的功能,用于处理请求并返回数据,通常用于构建 RESTful API。
  8. @ResponseBody:用于将方法的返回值直接作为响应体返回给客户端,而不是通过视图解析器渲染为视图。它可以用于方法级别或控制器类级别。
  9. ResponseEntity:是一个类,用于表示 HTTP 响应的实体,包括状态码、响应头和响应体等。它可以用于方法的返回值类型,以更灵活地构建和自定义 HTTP 响应。

请求

请求头:请求头由 key/value 对组成,每行为一对,key 和 value 之间通过冒号(:)分割。请求头的作用主要用于通知服务端有关于客户端的请求信息

  • User-Agent:生成请求的浏览器类型
  • Accept:客户端可识别的响应内容类型列表;星号* 用于按范围将类型分组。*/*表示可接受全部类型,type/*表示可接受 type 类型的 所有子类型。
    • application/json常用
    • image-20231102200252323
  • Accept-Language: 客户端可接受的自然语言
  • Accept-Encoding: 客户端可接受的编码压缩格式
  • Accept-Charset: 可接受的字符集
  • Host: 请求的主机名,允许多个域名绑定同一 IP 地址
  • connection:连接方式(close 或 keepalive)
  • Cookie: 存储在客户端的扩展字段
  • **Content-Type:**标识请求内容的类型
  • **Content-Length:**标识请求内容的长度

请求体:请求体主要用于 POST 请求

  • 与 POST 请求方法配套的请求头一般有 Content-Type和 Content-Length

响应

状态行:由 HTTP 协议版本、状态码、状态码描述三部分构成,它们之间由空格隔开。

状态码:由 3 位数字组成,第一位标识响应的类型,常用的5大类状态码如下:

  • 1xx:表示服务器已接收了客户端的请求,客户端可以继续发送请求

  • 2xx:表示服务器已成功接收到请求,并进行处理

    • 记住201 创建资源
  • 3xx:表示服务器要求客户端重定向

  • 4xx:表示客户端的请求有非法内容

    • 未授权,返回状态码401 Unauthorized
  • 5xx:标识服务器意外错误

响应头

  • Location:服务器返回给客户端,用于重定向到新的位置
  • Server: 包含服务器用来处理请求的软件信息及版本信息。Vary:标识不可缓存的请求头列表
  • Connection: 连接方式
    • close 是告诉服务端,断开连接,不用等待后续的请求了。
    • keep-alive 则是告诉服务端,在完成本次请 求的响应后,保持连接
  • Keep-Alive: 300,期望服务端保持连接多长时间(秒)

响应内容

  • 服务端返回给请求端的文本信息。

消息转换器

将java对象与json互转

  • 没有model和视图,控制器产生数据,然后消息转换器转换数据之后的资源表述
  • spring自动注册一些消息转换器(HttpMethodConverter),不过类路径下要有对应转换能力的库,如: Jackson Json processor、JAXB库

使用方法

  • 使用注解@ResponseBody或类级@RestController,作用:指定使用消息转换器
  • 请求传入,@RequestBody以及HttpMethodConverter

前后端传参的四种方式

  1. GET请求参数

通过URL携带参数,比如:

1
/users?id=1&name=Tom

后端通过@RequestParam获取参数。

  1. POST请求表单

表单提交参数,post表单数据到后端。

后端通过@RequestParam或@ModelAttribute获取表单数据。

  1. POST请求body

将JSON/XML等格式的数据放入请求体中传输。

后端通过@RequestBody注解将请求体绑定到对象中。

  1. POST请求文件

通过form表单或XMLHttpRequest上传文件到后端。

后端通过MultipartFile获取上传的文件。

  • 总结:

    • GET方式通过URL携带参数

      • POST方式通过表单或请求体传参
        • 表单通过@RequestParam或@ModelAttribute获取
        • 请求体通过@RequestBody将body绑定到对象
    • 文件上传通过表单或者XMLHttpRequest对应MultipartFile获取文件

spring-boot-starter-data-rest

目的

  • 将Spring Data存储库暴露为REST端点
  • 自动实现增删改查的REST API

用于快速开发基于Spring Data REST的Restful API项目。

  • 自动引入Spring Data REST、Spring HATEOAS等组件所需要的依赖。

  • 自动配置和启用了Spring Data REST功能。

  • 自动暴露Spring Data Repositories

  • 自动暴露Restful API。

  • 返回值包含实体与其相关实体或操作的URI链接。

  • 对外提供与数据相关的Restful CRUD接口。

  • 可以根据不同需求定制和扩展自动生成的API功能。

使用它可以一步创建基于实体的Restful API项目框架**,开发者只需定义接口和实体类即可。**大大提高开发效率。

使用方式

  • @Data
    @Entity
    @RestResource(rel=”tacos”, path=”tacos”)

  • image-20231102211936578

RestTemplate(不考

目的

  • 测试和保护REST端点

RestTemplate是Spring提供的用于执行HTTP请求的客户端模板类。使用RestTemplate可以方便地发起各种HTTP请求,与远程服务进行交互,在Spring注入模板后使用更简单高效。主要方法如下:

  • getForObject:执行HTTP GET请求,并解析响应体为指定对象类型返回。
  • getForEntity:执行HTTP GET请求,返回ResponseEntity对象,包含响应头和响应体。
  • postForObject:执行HTTP POST请求,并解析响应体为指定对象类型返回。
  • postForEntity:执行HTTP POST请求,返回ResponseEntity对象。
  • postForLocation:执行POST请求,返回Location头指定的URL。
  • put:执行HTTP PUT请求,用于资源更新。
  • delete:执行HTTP DELETE请求,用于资源删除。
  • execute:执行任意HTTP请求但不解析响应体,返回Response。
  • exchange:执行任意HTTP请求,返回ResponseEntity对象,包含请求响应全过程的数据。
  • image-20231102214752049

Feign(不考

分布式使用

远程调用RestAPI

  • image-20231102211737197

Lecture 10 OAuth2

  • OAuth2,一个专门为 API创建的授权规范。

  • 对微服务作权限控制

  • 统一认证和授权,专心业务

image-20231111094840312

  • 非常重要的图!考试必考

  • 流程:

    • 1.用户进入url,发现没登录

    • 2.资源服务器 重定向到 授权服务器,打开登录对话框

    • 3.新的url(资源服务器)让用户提供consent

      • image-20231111102642798
    • 4.用户确认授权consent

    • 5.返回授权码 auth code

    • 6.Client获取auth code 后再向授权服务器获取token(不能直接获取吗?)

      • 减少明文密码在浏览器出现的次数,转化为authcode。避免被第三方软件劫持
      • image-20231111112405718
    • 7.用户带着token 去资源服务器请求资源

      • 资源服务器需向authserver获取公钥,用以解码token,验证身份
    • 8.返回资源

      1. 令牌和凭证:
        • 令牌(Token)是一种代表用户身份的数据结构,用于在身份验证和授权过程中进行传递。令牌可以是访问令牌(Access Token)、身份令牌(ID Token)等。它们通常由授权服务器颁发给客户端,用于表示用户的身份和授权信息。
        • 凭证(Credential)是用于证明用户身份和权限的数据,可以是用户名和密码、API密钥、数字证书等。凭证通常由用户提供给身份验证系统或应用程序,用于获取相应的令牌或授权。
      2. 公私钥和凭证:
        • 公私钥是一对密钥,用于加密和解密数据。公钥用于加密数据,而私钥用于解密数据。公钥可以安全地共享给其他人,而私钥必须保持机密。
        • 凭证在身份验证过程中可以与公私钥配对使用,以提供更安全的身份验证机制。例如,数字证书是一种凭证形式,其中包含用户的公钥和其他身份信息,并由证书颁发机构(CA)使用其私钥签名。在身份验证过程中,验证方可以使用公钥解密数字证书的签名,并验证证书的真实性和完整性。
  • 举例:用微信获取信息 理解

JWT、JWK

  • JSON web key,RSA密钥对(公钥私钥),用于对令牌签名.令牌会用私钥签名,资源服务器会通过从授权服务器获取到的公钥验证请求中收到的令牌是否有效
    • interface JWKSource
    • interface JwtDecoder
  • JWT是一种开放标准(RFC 7519),用于在不同实体之间安全传输信息。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
    • 头部包含描述JWT的元数据,如使用的加密算法等。
    • 载荷包含有关实体和其他附加数据的信息,例如用户ID、过期时间等。
    • 签名是对头部和载荷进行数字签名的结果,用于验证JWT的完整性和真实性。
  • JWT提供了一种安全传输和验证信息的标准化格式,而JWK用于描述和传输用于JWT签名和验证的密钥对。通过使用JWK,可以验证JWT的真实性和完整性

image-20231111101635688

  • 解码例子 ↑

授权服务器

1.
2. 开发Spring Security User实体,接入数据库。

  1. image-20231111111631218

资源服务器

  1. 添加OAuth2 pom依赖
  2. 添加SCOPE权限控制 / 开启调用API前的过滤器:
    1. image-20231111111518116
  3. 指定授权服务器地址,目的是获得公钥
    1. image-20231111111539864

开发客户端

  1. 添加Oauth2-client专用的pom依赖
  2. 代码配置
    1. 定义第2步的重定向
    2. image-20231111113701029
  3. 属性配置
    1. 配置获取token的重定向地址
    2. image-20231111113709321

Lecture 11 消息中间件

ActiveMQ

Java 消息服务(Java Message Servcie)

  • JMS是一个Java标准,定义了使用消息代理(message broker)的通用API
  • Spring通过基于模板的抽象为JMS功能提供了支持,这个模板就JmsTemplate

生产消息

1
2
3
4
5
6
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL, USERNAME, PASSWORD);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("queue.example");

关键方法

  • javax.jms.Destination:指定队列或主题 : tacocloud.order.queue

    • application.yml(default-destination)

    • @Bean(Destination对象)

    • 直接String指定

  • 发送消息的两个方法:send、convertAndSend

  • MessageConverter

    • SimpleMessageConverter:实现String与TextMessage的相互转换、字节数组与BytesMessage的相互转换、Map与MapMessage的相互转换,以及Serializable对象与ObjectMessage的相互转换
    • MappingJackson2MessageConverter:使用Jackson 2 JSON库实现消息与JSON格式的互转
    • image-20231116204313985

不同模式

  • 拉取模式(Pull Model):

    • 拉取模式下,消费者主动从消息队列中拉取消息。即消费者需要不断地向消息队列发出请求,检测是否有新的消息到来,如果有则拉取消息进行消费。
  • 推送模式(Push Model):

    • 推送模式下,消息队列主动推送消息给消费者。当消息队列中有新消息到达时,会主动通知并直接发送给消费者,而不是等待消费者拉取。

RabbitMQ

  • Exchange:交换机,它是消息进入队列的入口。负责将消息路由到对应的Queue
    • 主要类型:
      • Direct Exchange:根据routing key完全匹配将消息路由到对应的Queue。
      • Fanout Exchange:将消息进行广播,将消息路由到所有绑定到该Exchange的Queue。
      • Topic Exchange:根据routing key的通配符规则将消息路由到对应的Queue。
  • Binding:绑定关系,它将Exchange和Queue绑定起来。
  • Routing Key:路由键,Exchange根据该键与Binding的binding key匹配将消息路由到对应的Queue。
  • Binding key:Binding中的键,它将Exchange和Queue关联起来。
  • image-20231116203552518

Lecture 12 spring integration

image-20231123205551218

  • 本节课做的:③Email Server

集成流配置三种方式

  • XML配置
  • Java配置
  • 使用DSL的Java配置

最简集成流的五个部分

  • image-20231123205532037
  • 消息分为Header和Payload

集成流的组件

  • Channels(通道) —Pass messages from one element to another.
    • 例如:PublishSubscribeChanne、QueueChannel、PriorityChannel
    • image-20231123210628428
  • Filters(过滤器) —Conditionally allow messages to pass through the flow based on some criteria.
    • image-20231123210721288
  • Transformers(转换器) —Change message values and/or convert message payloads from one type to another.
    • image-20231123210821660
  • Routers(路由器) —Direct messages to one of several channels, typically based on message headers.
    • image-20231123212118322
  • Splitters(切分器) —Split incoming messages into two or more messages, each sent to different channels.
    • image-20231123212211014
    • 切分的是消息,不是router到多个channel
  • Aggregators(聚合器) —The opposite of splitters, combining multiple messages coming in from separate channels into a single message.
  • Service activators(服务激活器) —Hand a message off to some Java method for processing, and then publish the return value on an output channel.
    • image-20231123212241684
    • 类似transformers,语义上不同
  • Channel adapters(通道适配器) —Connect a channel to some external system or transport. Can either accept input or write to the external system.
    • image-20231123212510747
    • Inbound Channel Adapter(入站通道适配器)
      • 作用:Inbound Channel Adapter 负责将外部系统的数据转换成消息,并将这些消息发送到 Spring Integration 流程中的通道。
      • 例子:一个常见的例子是文件适配器(File Inbound Channel Adapter),它可以监听指定的文件夹,并在文件变化时将文件内容转化为消息发送到通道中。另一个例子是 JMS 入站适配器,用于从 JMS 队列接收消息。
    • Outbound Channel Adapter(出站通道适配器)
      • 作用:Outbound Channel Adapter 负责将消息从 Spring Integration 流程中取出并传递给外部系统。
      • 例子:一个例子是文件适配器(File Outbound Channel Adapter),它将消息的内容写入文件。另一个例子是 JMS 出站适配器,用于将消息发送到 JMS 队列。
  • Gateways(网关) —Pass data into an integration flow via an interface
    • image-20231123212410022

Lecture 13 反应式编程

什么是Reactor、java NIO、netty

  • Reactor是一个反应式编程库,用于构建异步和非阻塞的应用程序。
  • Java NIO是Java平台提供的非阻塞I/O编程模型,用于提高I/O操作的性能和并发能力。
  • Netty则是基于Java NIO的网络应用程序框架,提供了高性能和可定制的网络编程API。
  • 这些技术和框架都有助于构建高效的异步和非阻塞的应用程序和网络服务。

对比

  • 命令式编程范式
    • image-20231207183004199
    • 强调顺序,强调怎么做
  • 反应式编程范式
    • image-20231207190905257
    • 关注数据流和事件变化,强调什么要做
    • 将计算看作是一系列数据流的转换和响应事件的触发。
  • 声明式编程可以应用于多种编程范式。注重问题的描述和逻辑
    • 函数式编程是一种常见的声明式编程范式,强调使用函数作为基本的构建块来解决问题,并避免可变状态和副作用。
    • 函数式编程和反应式关系紧密

解决了什么问题

  • IO密集型场景,减少等待,管理多线程。
    • IO:远程通信、内存读写
  • 用尽量少的线程,解决多请求。事件队列
    • image-20231207191850202

Reactor(重要)

Reactive Streams:

  • 一套规范,供无阻塞回压的异步流处理标准

    • 回压是指当生产者生成数据的速度大于消费者处理数据的速度时,消费者如何向生产者发出信号以控制数据流的速度。背压机制是为了解决这种情况下的流量控制问题,以确保消费者能够有效地处理数据,而不会被淹没或溢出
  • 与jdk的stream的区别:java的stream是同步的

  • jdk的反应式编程叫做Flow

Reactor

  • Spring Pivotal团队提供的响应式编程的Java实现

Spring WebFlux

  • 基于响应式编程的Web应用程序的开发。
  • 类似于Spring MVC的编程模型,但不基于servlet

反应式流规范定义的4个接口(++重要)

问答题

注意①②③④⑤

image-20231207183850643

  1. Publisher(发布者):表示数据的生产者,可以发布数据流。
    1. submit:发布数据给subscription,每个subscriber对应一个subscription
    2. subscribe:与下一个订阅者建立连接
  2. Subscriber(订阅者):表示数据的消费者,可以订阅并处理数据流。
    1. onSubscribe:publisher告诉订阅者,建立连接
    2. onNext:订阅者获取下一个数据。背压调节流速
    3. onError:告诉订阅者出错
    4. onComplete:告诉订阅者结束
  3. Subscription(订阅关系):一个协调者,纽带。表示订阅者与发布者之间的连接,用于控制数据流的请求和取消订阅。
    1. request,subscriber请求数据
    2. cancel
  4. Processor(处理器):表示一个中间组件,同时具有发布者和订阅者的功能,可以将数据进行转换、过滤等操作。
    1. extends Publisher,Subscriber

Flux 和 Mono

Flux和Mono是Reactor库中的两个核心类,用于支持反应式流编程模型。

  • Flux:Flux是一个表示0到N个元素的异步序列的类。它类似于Java 8中的Stream,但具有异步和背压控制的能力。Flux可以用于表示多个值的流,可以是有限的,也可以是无限的。它可以发出元素,同时也可以处理背压,以确保在消费者准备好接收时进行数据流控制。
  • Mono:Mono是一个表示0或1个元素的异步序列的类。它类似于Flux,但只能发出零个或一个元素。Mono可以用于表示单个值的流,例如数据库查询、HTTP请求的响应等。它也可以处理背压,确保在消费者准备好接收时进行数据流控制

消息

  • 正常的包含元素的消息、序列结束的消息和序列出错的消息
  • 和Integration消息区别:没有消息Head和Body之分
  • 和RabbitMQ等中间件区别:不需要序列化和反序列化,因为只在JVM中流动

四种操作

  • 创建操作

    • image-20231207202800486
    • 根据对象/集合/迭代器,甚至是时间间隔(interval)创建。
      • 消费时,多线程自动编排
      • ww
  • 组合操作

    • image-20231207205111813
      • merge:合并同类型
      • zip:合并不同类型到tuple,也可以自己改造元素
      • first:只看第一个有数据的流
      • image-20231207212923617
  • 过滤操作

    • Predicate:返回True或False
    • image-20231207213307397
      • image-20231207213359092
  • 转换操作(重要)

    • image-20231207213626300

    • map:转换类型,返回的是数据

      • image-20231207213646882
    • flatMap:返回的是流,所以类型是Mono/Flux

      • image-20231207214205506

        • Schedulers:可以决定是否并行,顺序不可控
      • 本质上是扁平化,将多个流化为一个流。在多重流时可以并发处理

      • image-20231208013716522

    • image-20231207214531371

    • 返回分组(List)的流。类似MapReduce

      • image-20231207214827674
  • 逻辑操作

    • image-20231208014251456
    • Boolean也是流

Lecture 14 WebFlux

WebFlux

image-20231207200211792

  • 必须Subscribe才能操作数据

R2DBC

查看评论