Spring 响应式编程-读书笔记
序言
大家好,我是比特桃。本文为《Spring 响应式编程》的读书笔记,响应式技术栈可以创建极其高效、易于获取且具有回弹性的端点,同时响应式可以容忍网络延迟,并以影响较小的方式处理故障。响应式微服务还可以隔离慢速事务并加速速度最快的事务。通过本书可以学到以下内容:
- 响应式编程基本原则和响应式流(Reactive Stream)规范;
- 使用 Spring 5 集成的 Project Reactor 响应式开发框架;
- 使用 Spring Webflux 构建响应式 RESTful 服务;
- 使用 Spring Data Reactive 构建响应式数据访问组件;
- 使用 Spring Cloud Stream Reactive 构建响应式消息通讯组件。
第一章 响应式Spring
首先了解一下响应式编程相关的名词:
- 弹性:可以横向扩展;
- 回弹:故障隔离,做到独立性;
- 消息驱动:不应该是阻塞的,即时响应。
响应式中,较为关键的是背压:主要用来支持回弹性,实现处理阶段之间工作负载管理的复杂机制,可以确保一个处理阶段不会压垮另一个。
在JVM领域,构建响应式系统最知名的两个框架:Akka 、Vert.x。而在在传统 Java 中,实现响应式的方式:
- 回调函数,但会带来回调地狱问题;
- JDK 8 CompletionStage.
Spring 4为了兼容旧 JDK 没有支持CompletionStage,在Spring 5中才支持该方法。同时,Servlet 3.0 引入了异步客户端-服务器通讯,3.1 支持I/O 非阻塞写入。但是Spring MVC 没有提供一个开箱即用的异步非阻塞客户端。为了陈旧包袱,彻底丧失响应式支持。也导致了 Spring为响应式单独开了一份技术栈。
第二章 Spring响应式编程基本概念
发布订阅模式,它可以被视为观察者模式的变体。在基于RxJava的实现中,但没有人监听时,温度传感器不会探测温度数据。这种行为是响应式编程具有主动订阅概念这一事实的自然结果。基于发布-主题的实现没有这样的属性,因此存在更多限制。
RxJava库是 Reactive Extensions(响应式扩展,也称为 ReactiveX)的Java虚拟机实现。Reactive Extensions 是一组工具,能用命令式语言处理数据流,无论该流是同步的还是异步的。ReactiveX通常被定义为观察者模式、迭代器模式和函数式编程的组合。
RXJava通过订阅者订阅可观察流,该流又反过来触发事件生成的异步过程。采用这种方法对可变对象有害,唯一合理的策略是采用不变性。不变性即函数式编程(functional programming)的核心原则之一。对象一旦被创建,就不会被更改。这样一条简单的规则可以防止在并行系统中可能出现的问题。
如果没有函数式编程,人们就必须创建许多匿名类或者内部类,这些类会污染应用程序。并且他们创建的样板代码多于有效代码。正由于它的不可变性,非常适合应用于并发编程。
历史
异步编程的历史最早追溯05年微软做的:大规模异步数据密集型互联网服务架构的编程模型。09年开源了Rx.NET,后来Netflix正面临大量互联网流量这一复杂难题,就开源了RxJava。并基于它开发了诸如:Hystrix、Ribbon、Zuul、RxNetty知名的库。但其实在响应式编程方向完全落实并成功做出巨大贡献的是:Node.js。
RxJava也并不是Java中唯一的解决方案,Vert.x也可以实现类似功能。Vert.x是一个事件驱动的开发框架,在设计上类似Node.js。它为异步编程提供了一个简单的并发模型和原始语义。
随着RxJava的成功,许多公司和开源项目都开始了激烈的竞争。由于各个库的行为总体上非常相似,但在实现中又略有不同。所以如果共用一些响应式库,可能会出现隐藏的bug。为了解决这些兼容性问题,出现了一个标准:响应式流(Reactive Streams)。
第三章 响应式流-新的标准
使用多个响应式库需要自己去编写适配器进行兼容,Spring 4的ListenableFuture和CompletionStage之间并没有直接的集成,而在Spring 5中才扩展了ListenableFuture的API名为Comple-table的方法来解决不兼容问题。核心问题在于没有一种方法能够使库提供商提供对齐的API,Vert.x、Ratpack和Retrofit都比较重视RxJava,并提供了支持。
在整个响应式环境演变的早期阶段,所有库的设计思想都是把数据从源头推送到订阅者。采用推模型的主要原因是它可以通过将请求量减少到最小值来优化整体处理时间。
这也就是为什么RxJava1.x及类似的开发库以推送数据为目的进行设计,这也是为什么流技术能称为分布式系统中组件之间重要的通讯技术。但如果生产者不关注消费者的吞吐能力,则会存在一下可能:
- 慢生产者和快消费者
- 快生产者和慢消费者
针对这种情况的解决方案是将未处理的元素收集到队列中。
- 无界队列:无限大小的队列;
- 有界丢弃队列:为避免内存溢出;
- 有界阻塞队列:支付订单阻塞;
通常,纯推模型中不受控制的语义可能导致许多我们不希望出现的情况。响应式宣言中提到使系统巧妙地响应负载的机制的重要性,及背压的重要性。
响应式流规范定义了4个主要的接口:Publisher、Subscriber、Subscription和Processor。
其中,Publisher和Observable、Subscriber和Observer基本相同;
在Subscriber中的onSubscribe方法中,引用了Subscription,这为控制元素的生产提供了基础。响应式流规范引入了request方法以扩展Publisher和Subscriber之间的交互能力。为了通知Publisher应该推送多少数据,Subscriber应该通过request方法发出关于所需数量的信号,并确保传入元素的数量不超过限制。
与纯推模型相反,该规范为我们提供了混合推拉模型,而此模型可以对背压进行合理控制。
Processor是Publisher和Subscriber的组合。它的目标是再Publisher和Subscriber之间添加一些处理阶段。
第四章 Project Reactor 响应式应用程序的基础
响应式流规范(reactivestreams)使得响应式库彼此兼容,并通过引入拉-推数据交换模型解决了背压问题。但它只是定义了规范,并不提供日常使用,Spring 实现了Project Reactor(简称Reactor)。
响应式流规范(reactivestreams)使得响应式库彼此兼容,并通过引入拉-推数据交换模型解决了背压问题。但它只是定义了规范,并不提供日常使用,Spring 实现了Project Reactor(简称Reactor)。Reactor1.x 版本包含了消息处理的最佳实践,例如Reactor模式(Reactor Pattern),以及函数式和响应式编程风格。
Reactor模式是一种行为模式,有助于异步事件响应和同步处理。这意味着所有事件都需要排队,并且事件的实际处理稍后由单独的现成负责执行。一个事件被分派给所有有关方面(事件处理程序)并进行同步处理。
Reactor 1.x与Spring框架很好地集成在一起,Reactor 1.x 与消息处理库一起提供了许多附加的组件,例如针对Netty的附加组件。Reactor 2首开响应式流之先河。将事件总线和流功能提取到单独的模块中,使得Reactor Streams库完全符合响应式流规范。Reactor API与Java Collections API 具有更好的集成性。Reactor的Streams API与RxJavaAPI更加相似,补充了在背压管理、线程调度和回弹性方面的支持。发送消息的Reactor对象被重命名为了EventBus。
RxJava和ProjectReactor的想法浓缩成了一个reactive-stream-commons的库,后来该库也成为了Reactor3.x。同时,Reactor3.x塑造了Spring 5框架的响应式变种(reactive metamorphosis)
Reactor库设计的目的就是为了在构建异步管道时避免回调地狱和深层嵌套代码。我们可以将响应式应用程序的处理的数据视为在装配线上的移动。Reactor即是传送带又是工作站。Reactor API只有订阅才会触发真实的数据流。该库常见的背压传播模式:
- 仅推送:当订阅者通过 subscription.request(Long.MAX_VALUE)请求有效无线数量额元素时。
- 仅拉取:当订阅者通过 subscription.request(1) 仅在收到前一个元素后请求下一个元素时。
- 拉-推(有时成为混合):当订阅者有实时控制需求,且发布者可以适应所提出的数据消费速度时。
Project Reactor是建立在响应式流规范之上的,org.reactivestreams:reactive-streams 是 Project Reactor 的唯一强制依赖。响应式流规范自定义了4个接口,即 Publisher、Subscriber、Subscription和Processor<T, R>。
ProjectReactor提供了Publisher接口的两种实现,即Flux和Mono。
Mono是Reactor的两种核心类型之一,另一个类型是Flux。 两者都实现了反应式流的Publisher接口。Flux代表具有零个、一个或者多个(可能是无限个)数据项的管道。它的公式为: onNext x 0…N [onError | onComplete]。例如:Flux.range(1, 5).repeat();
Mono是一种特殊的反应式类型,针对数据项不超过一个的场景,它进行了优化。公式表示为:onNext x 0…1 [onError | onComplete]。当应用程序API最多返回一个元素时,Mono很有用。因此,它可以替换comple-tableFuture,并提供相似的语义。CompletableFuture会立即开始处理,而Mono在订阅者出现之前什么都不做。Mono类型的好处只在于它不仅提供了大量的响应式操作符,还能够完美地结合到更大的响应式工作流程中。例子:当操作完成需要通知客户端的时候,也可以使用Mono,处理完成时发出 onComplete()信号,发生故障时返回onError()。在这种场景下,不会返回任何数据,而只是发出通知信号,而这个通知信号反过来可以用作进一步计算的触发器。
Flux和Mono是Reactor提供的最基础的构建块,而这两种反应式类型所提供的操作符则是组合使用它们以构建数据流动管线的黏合剂。Flux和Mono共有500多个操作,这些操作都可以大致归类为:
创建操作;
组合操作;
转换操作;
逻辑操作。
第五章 使用Spring Boot 2实现响应性
Project Reactor可以在没有Spring框架的基础上运行,如果结合Spring的依赖注入,将会变得更好。
09年Spring团队为了快速开发应用,使用了约定优于配置(Convention-over-configuration)的方法。12年发布了Spring boot,采用了无容器Web应用程序的理念和可执行的胖JAR(Fat JAR)技术。最关键的两个注解:@SpringBootApplication,用来运行IoC容器;@spring-boot-autoconfigure,自动配置一些“-starter-”后缀的组件。
Spring 5.x引入了对响应式流和响应式库的原生支持,其中响应式库包含了RxJava 1/2和Project Reactor3。
Servlet API 3.1的适配器提供了与WebMVC适配器不同的纯异步和非阻塞集成。当然,Spring WebMVC模块还支持Servlet API4.0,后者支持HTTP/2。
早期,Spring Data主要提供对底层存储区域的同步阻塞访问。幸好,第五代 Spring Data 提供了ReactiveCrudRepository接口,该接口暴露了ProjectReactor的响应式类型,以便于响应式工作流程无缝集成。
Spring Sessiong模块可以试用高效的抽象来进行会话管理,Spring Sessiong引入了ReactiveSessionRepository,它可以使用Reactor的Mono类型对存储的会话进行异步非阻塞访问。
旧的Spring Security使用ThreadLocal作为SecurityContext实例的存储方法,在单个Thread内执行的时候很有效,在任何时候,我们都可以访问存储在ThreadLocal中的SecurityContext。但是在异步通讯时,我们需要将ThreadLocal内容传输到另一个Thread。如今新一代Spring Security采用了Reactor上下文功能,以便在Flux或Mono流中传输安全上下文。
Netflix Zuul基于使用阻塞同步请求路由的ServletAPI,使处理请求无效并获得更好性能的唯一办法是调整底层服务器线程池。幸好Spring Cloud引入了新的Spring Cloud Gateway模块,该模块构建于Spring WebFlux之上,并在Project Reactor 3 的支持下提供异步和非阻塞路由。除了网关,Spring Cloud Streams还获得了Project Reactor的支持,并引入了更加细粒度的流模型。还有Spring Cloud Function和Spring Cloud Data Flow,这些可以构建自己的FaaS(Function as a service)。
Spring Actuator提供了与WebFlux的完全集成,并使用其异步、非阻塞变成模型,以便有效地暴露指标端点。Spring Cloud Sleuth模块也支持了Project Reactor的响应式编程,开箱即用的分布式跟踪。
第六章 WebFlux异步非阻塞通讯
从Spring框架在Web应用程序领域开始演进起,就将Spring Web模块与Java EE的 Servlet API进行集成的决定。Spring框架的整体基础设施都是围绕Servet API构建的,他们之间紧密耦合。例如,Spring Web MVC 整体以Front Controller模式为基础。该模式在Spring Web MVC中由org.springframework.web.servlet.DispatcherServlet 类实现,而该类简介扩展了javax.servlet.http.HttpServlet类。
整体设计依赖于底层Servlet容器,而该容器负责处理容器内所有映射Servlet。DispatchServlet作为一个集成点,用于集成灵活且高度可配置的Spring Web基础设施和繁重且复杂的Servlet API。HandlerMapping的可配置抽象有助于将最终的业务逻辑(如控制器和bean)与Servlet API分离。
尽管Servlet API支持异步、非阻塞通讯(从3.1版本开始),但SpringMVC模块的实现不仅存在很多缺陷,还不允许在整个请求生命周期中出现非阻塞操作。例如它没有开箱即用的非阻塞HTTP客户端,任何外部交互都可能导致阻塞的I/O调用。旧版的Spring中Web抽象的另一个劣势是,对于一个非Servlet服务器(如Netty)而言,重用Spring Web功能或编程模型没有灵活性。
WebFlux提供了开发轻量级应用,该特性是通过函数式路由映射和我们能够编写复杂的请求路由逻辑的内置API实现的。纯函数式路由的组合足以适应新的响应式编程方法。此外,还提供了WebClient的旧RestTemplate的响应式替代品。虽然WeboSocket在13年就引入了Spring,但目前仍然有一些阻塞操作,例如将数据写入I/O或从I/O读取数据仍然是阻塞操作。WebFlux模块为WebSocket引入了改进版本的基础设施,并且提供了客户端的支持。
对比WebFlux和WebMVC
以前,计算机是顺序的,大家习惯浏览简单静态的内容,系统的总体负载总是很低的。而现在Web用户数量达到了十几级,并且内容开始变成动态的甚至是实时的,而对吞吐量和延迟的要求已经发生了很大变化。要计算并行工作单元的数量如何改变延迟或吞吐量,可以用到利特尔定律(Little’s Law):N = X x R。系统或队列驻留的平均请求数(或同时处理的请求数)(N)等于吞吐量(或每秒用户数)(X)乘以平均响应时间或延迟时间(R);例如:系统平均响应时间R为0.2S,吞吐量X为每秒100个请求,那么它应该能够同时处理20个请求,或者并行处理20个用户。
传统的基于Servlet的Web框架,如Spring MVC,在本质上都是阻塞和多线程的,每个连接都会使用一个线程。在请求处理的时候,会在线程池中拉取一个工作者(worker)线程来对请求进行处理。同时,请求线程是阻塞的,直到工作者线程提示它已经完成为止。
这样带来的后果就是阻塞式Web框架在大量请求下无法有效地扩展。缓慢的工作者线程所带来的延迟会使情况变得更糟,因为它将花费更长的时间才能将工作者线程送回池中,准备处理另一个请求。在某些场景中,这种设计完全可以接受。事实上,在很大程度上这就是十多年来大多数Web应用程序的开发方式,但是时代在改变。
这些Web应用程序的客户端以前是偶尔浏览网站的人们,而现在这些人会频繁消费内容而且会使用与HTTP API协作的应用程序。如今,物联网(甚至不需要人类)产生了汽车、喷气式发动机和其他非传统的客户端,它们会持续地和Web API交换数据。随着消费Web应用的客户端越来越多,可扩展性比以往任何时候都更加重要。
异步的Web框架能够以更少的线程获得更高的可扩展性,通常它们只需要与CPU核心数量相同的线程。通过使用所谓的事件轮询(event looping)机制(如图11.1所示),这些框架能够用一个线程处理很多请求,这样每次连接的成本会更低。
右上角的方框表示另一种编程模型,它使用函数式编程范式来定义控制器,而不是使用注解。
尽管Spring WebFlux控制器通常会返回Mono和Flux,但是这并不意味着Spring MVC无法体验反应式类型的乐趣。如果你愿意,那么Spring MVC也可以返回Mono和Flux。
这里的区别在于,这些类型会如何被使用。Spring WebFlux是真正的反应式Web框架,允许在事件轮询中处理请求;而Spring MVC是基于Servlet的,依赖于多线程来处理多个请求。
Web MVC建立在阻塞I/O之上,这意味着处理每个传入请求的Thread可能被从I/O读取传入的消息所阻塞。
相比之下,WebFlux构建在非阻塞API之上,这意味着没有操作需要与I/O阻塞Thread进行交互。WebFlux能比Web MVC更有效地利用一个Thread。
WebFlux应用的场景:
- 微服务系统:典型微服务系统最显著的特点就是大量的I/O通讯,I/O的存在,尤其是阻塞式I/O,会降低整个系统延迟和吞吐量。
- 处理客户端连接速度慢的系统:如果客户端数量很多,那么系统崩溃的可能性会比较大。例如,黑客能很容易的通过使用拒绝服务(Denial-of-Service,DoS)攻击使我们的服务器不可用。相比之下,WebFlux使我们能在不阻塞工作线程的情况下接受连接。
- 流或实时系统:这些系统的特点是低延迟和高吞吐量,使用非阻塞通讯可以实现低延迟和高吞吐量。然而这种响应式框架有其自身的缺点,即使用通道和回调的复杂交互模型。但我们可以通过响应式库构建一个异步的非阻塞流而且还需要很小的开销。
WebFlux可用响应式Web服务器(Netty)和非阻塞的Undertow功能
第七章 响应式数据库访问
响应式应用程序中始终不鼓励阻塞I/O,Spring Data模块以响应式方式访问数据,即便选择的数据库没有提供响应式或异步驱动程序,我们仍然可以使用专用的线程池来构建一个围绕它的响应式应用程序。
Eric Evans《领域驱动设计:软件核心复杂性应对之道》为成功的为微服务架构定义了重要的理论基础,并使其成型。领域驱动设计(Domain-Driven Design,DDD),建立了一个通用的词汇表(即上下文、领域、模型和统一语言),根据DDD定义的单个边界上下文(bounded context)通常会被映射到单独的微服务中。
由于DDD非常关注业务核心域(core domain),尤其是用来表达、创建和检索域模型的工件,因此实体(Entity)、值对象(Value object)、聚合(Aggregate)、存储库(Repository)等对象在本章中将会被频繁提及。
在考虑DDD的应用程序实现期间,应将上述对象映射到应用程序持久化层。这种领域模型构成了逻辑和物理数据模型的基础。
未完待续……
相关文章:
Spring 响应式编程-读书笔记
序言 大家好,我是比特桃。本文为《Spring 响应式编程》的读书笔记,响应式技术栈可以创建极其高效、易于获取且具有回弹性的端点,同时响应式可以容忍网络延迟,并以影响较小的方式处理故障。响应式微服务还可以隔离慢速事务并加速速…...
CI流水线的理解
一、概念 单元测试:针对软件的基本单元(如:类、函数)所做的测试。 集成测试:将软件代码单元集成起来后,以组件、模块和子系统为单位进行的测试,主要测试接口间的交互关系。也称组件测试…...
OpenStack手动分布式部署Nova【Queens版】
目录 Nove简介: 1、登录数据库配置(在controller执行) 1.1登录数据库 1.2数据库里创建nova-api 1.3数据库登录授权 1.4创建nova用户 1.5添加admin用户为nova用户 1.6创建nova服务端点 1.7创建compute API 服务端点 1.8创建一个placement服务…...
centos7 oracle19c安装 ORA-01012: not logged on
总共分三步 1.下载安装包:里面有一份详细的安装教程 链接:https://pan.baidu.com/s/1Of2a72pNLZ-DDIWKrTQfLw?pwd8NAx 提取码:8NAx 2.安装后,执行初始化:时间较长 /etc/init.d/oracledb_ORCLCDB-19c configure 3.配置环境变量,不配置环境变量,sq…...
山东小巨人申报条件
国家专精特新小巨人特点1、经济效益:上年度企业营业收入在1亿元至4亿元之间,近2年主营业务收入或净利润的平均增长率达到10%以上,企业资产负债率不高于70%。2、专业化程度:(1)企业从事特定细分市场时间达到…...
手写中实现并学习ahooks——useRequest
前言 最近业务没有之前紧张了,也是消失了一段时间,也总结了一些之前业务上的问题。 和同事沟通也是发现普通的async await 封装api在复杂业务场景下针对于请求的业务逻辑比较多,也是推荐我去学习一波ahooks,由于问题起源于请求…...
[手写OS]动手实现一个OS 之 准备工作以及引导扇区
[手写OS]动手实现一个OS之第一步-环境以及引导扇区 环境准备 一台可用计算机(linux我不知道,我用的Windows)汇编编译器NASM一个方便的软盘读写工具VirtualBox 汇编编译器NASM 官网地址:https://www.nasm.us/pub/nasm/snapshot…...
JVM实战OutOfMemoryError异常
目录 Java堆溢出 常见原因: 虚拟机栈和本地方法栈溢出 实验1:虚拟机栈和本地方法栈测试(作为第1点测试程序) 实验2:(作为第1点测试程序) 运行时常量池和方法区溢出 运行时常量池内存溢出 …...
C++虚函数操作指南
1 什么是虚函数?1.1 虚函数的使用规则1.2 用 C 运行虚函数的示例1.3 协变式返回类型2 在 C 中使用虚函数的优点2.1 代码更为灵活、更为通用2.2 代码可复用2.3 契约式设计3 虚函数的局限性3.1 性能3.2 设计问题3.3 调试,容易出错4 虚函数的替代方案4.1 仅…...
Mybatis-Plus分页插件
引言:MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能 1.添加Configuration配置类 Configuration MapperScan("com.atguigu.mybatisplus.mapper") //可以将主类中的注解移到此处public class MybatisPlusConfig {Beanpublic Mybatis…...
Selenium Webdriver options的实用参数设置
1、关闭Chrome浏览器受自动控制的提示 options.add_experimental_option(useAutomationExtension, False) options.add_experimental_option(excludeSwitches, [enable-automation])2、关闭是否保存密码的弹窗 options.add_experimental_option("prefs", { "c…...
代码随想录算法训练营第七天|454.四数相加II 、 383. 赎金信 、 15. 三数之和 、18. 四数之和
454.四数相加II 454.四数相加II介绍给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:思路因为是存放在数组里不同位置的元素,因此不需要考虑去重的操作,而…...
详解抓包原理以及抓包工具whistle的用法
什么是抓包? 分析网络问题业务分析分析网络信息流通量网络大数据金融风险控制探测企图入侵网络的攻击探测由内部和外部的用户滥用网络资源探测网络入侵后的影响监测链接互联网宽频流量监测网络使用流量(包括内部用户,外部用户和系统)监测互联网和用户电脑的安全状…...
【C++】反向迭代器
文章目录一、什么是反向迭代器二、STL 源码中反向迭代器的实现三、reverse_iterator 的模拟实现四、vector 和 list 反向迭代器的实现一、什么是反向迭代器 C 中一共有四种迭代器 – iterator、const_iterator、reverse_iterator 以及 const_reverse_iterator,其中…...
(蓝桥真题)扫描游戏(计算几何+线段树二分)
题目链接:P8777 [蓝桥杯 2022 省 A] 扫描游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 样例输入: 5 2 0 1 1 0 3 2 4 3 5 6 8 1 -51 -33 2 样例输出: 1 1 3 4 -1 分析:先考虑如何对物件进行排序,首先&…...
面试官:什么是双亲委派模型?如何打破它?
本文已经收录进 JavaGuide(「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。) 参加过校招面试的同学,应该对这个问题不陌生。一般提问 JVM 知识点的时候,就会顺带问你双亲委派模型(别扭的翻译。。。)。 就算是不准备面试,学习双亲委派模型对于我…...
自建服务器系列- DDNS配置
1、环境说明 光猫桥接路由器拔号的模式 2、DDNS是什么 对于DHCP方式获得的IP,无论对于局域网内来说,还是外网来说,都会有使得IP地址每隔一段时间变化一次,如果想要通过恒定不变的地址访问主机,就需要动态域名解析。…...
vue中使用axios简单封装用法,axios报错the request was rejected because no multipart boundar
在这里插入代码片## 创建实例 //这个写法作为我错误的记录,可以不看暂时 transformRequest: [(data: any) > {if (!data) {data {}}return qs.stringify(data)}]在我的项目里面,初始化配置里面进行handers的修改,例如:例如将…...
Leetcode.1220 统计元音字母序列的数目
题目链接 Leetcode.1220 统计元音字母序列的数目 Rating : 1730 题目描述 给你一个整数 n,请你帮忙统计一下我们可以按下述规则形成多少个长度为 n的字符串: 字符串中的每个字符都应当是小写元音字母(a, e, i, o, u)…...
深入元空间
元空间是干嘛的?元空间存储的是类的相关信息,就是类的运行时表达。包括:Class文件类的结构和方法常量注解代码优化JDK1.8分界在1.8版本之前,类的meta信息、类变量、字符串常量池都存储在永久代。1.8版本以后,类变量、实…...
前端技术和框架
一、各种技术概述 1.HTML 🧨HTML中文称为超文本标记语言,从语义上来说,它只是一种是一种标识性的语言,并不是一种编程语言。 <p>这是一段话</p>通过这个标签可以表示文本的一个段落。而且其中还有还有图片标签、视…...
02从零开始学Java之Java到底是个啥?
博主简介我是壹壹哥(孙玉昌),十年软件开发授课经验,CSDN博客专家、阿里云专家博主、掘金优秀创作者、infoQ专家博主;关注壹壹哥(孙玉昌),带你玩转Java,轻松实现从入门到放弃,哦不,到熟悉&#x…...
KEIL5中头文件路劲包含问题
方式1:1.Keil中添加头文件相对路劲的方法在c/c配置中添加路劲,最终是将添加的绝对路径转化为相对路径;注意:相对路径的当前位置指.uvproj文件所在位置在C/C配置中的include paths”中添加工程所用的所有头文件的路径;2…...
机智云目前我用过最便捷的物联网快速开发方案
GE211 MINI DTU上手来看,是一款尺寸比较小巧的模块,适合放置在几乎所有白色家电中,通过ph2.0端子(注意不要买错)引出了5v、gnd、tx、rx。可以说是非常方便了。下面正式开始我们的接入流程:首先注册一个机智…...
MySQL基础篇1
第1章 数据库介绍 1.1 数据库概述 什么是数据库? 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作。 数据库分两…...
AQS 源码解读
一、AQS AQS 是 AbstractQueuedSynchronizer 的简称,又称为同步阻塞队列,是 Java 中的一个抽象类。在其内部维护了一个由双向链表实现的 FIFO 线程等待队列,同时又提供和维护了一个共享资源 state ,像我们平常使用的 ReentrantLo…...
使用 DataLoader 加载数据报错‘expected sequence of length 4 at dim 1 (got 0)’
使用 transformer 将字符串转为 id 序列,字符串为中英文混杂形式, 运行中出现报错:expected sequence of length 4 at dim 1 (got 0) 发现是在encoder_plus转换时,将输入的文本根据max_length截断了,导致[MASK]等字段…...
第十四届蓝桥杯第三期模拟赛B组C/C++原题与详解
文章目录 一、填空题 1、1 找最小全字母十六进制数 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 给列命名 1、2、1 题目描述 1、2、2 题解关键思路与解答 1、3 日期相等 1、3、1 题目描述 1、3、2 题解关键思路与解答 1、4 乘积方案数 1、4、1 题目描述 1、4、2 题解关…...
致敬三八女神节,致敬IT女生
前言 三八女神节是一个特别的节日,它是为了纪念所有的女性,表达对她们的尊重和关爱。在这个特别的节日里,我们想要致敬所有在IT领域中奋斗的女生,她们用自己的智慧和努力为这个世界带来了无限的可能。 IT女神 从事IT行业的女生…...
【Go语言学习笔记】数据
目录字符串数组数组初始化指针复制切片基本操作resliceappendcopy字典deletemap是引用类型并发操作字符串 字符串是不可变字节(byte)序列,其本身是一个复合结构 type stringStruct struct{str unsafe.Pointerlen int }头部指针指向字节数组…...
政务公开做的好的网站有哪些/郑州seo团队
问题描述: 抛出org.hibernate.NonUniqueResultException Testvoid findPhoneSpecsByPhoneId(){public A ab.findById(1);System.out.println(a);}原因分析: 你希望拿到一个对象 ,但实际返回结果有N个对象 解决方案: 如下我解决…...
网页视频下载软件免费版/seo翻译
一、maven各个命令的区别: 1、maven clean 清空target下的文件2、maven compile 编译(在target下生成.class文件) 一般使用:mvn clean package 先清缓存再打包注意:如果使用的是Eclipse的maven插件,插件默认…...
谁能帮我做网站/网络热词英语
我致力于最新的前沿安卓技术分析和使用教学,不打算将很多很深的东西,因为有多少人愿意沉下你的心境去学习难点?我一般只会简单提及.文字错漏在所难免还希望同学们喜欢 热修复介绍 热修复是什么? 如果你一个项目已经上线,出现了严重缺陷,那么你第一反应是推送新版本.那么问题来…...
网站建设前的功能/su搜索引擎优化
括号生成 题目描述: 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。题目链接 class Solution { public:vector<string> result;vector<string> generateParenthesis(int n) {int …...
推广网站2024/常州百度推广代理
Linux中一个基本命令是ls。没有这个命令,我们会在浏览目录条目时会遇到困难。这个命令必须被每个学习linux的人知道。本文引用地址:http://www.eepw.com.cn/article/268238.htmls是什么ls命令用于列出文件和目录。默认上,他会列出当前目录的内…...
将网站的主机放在美国/seo教程seo入门讲解
微信小程序的用户信息获取需要请求微信的服务器,通过小程序提供的API在小程序端获取CODE,然后将CODE传入到我们自己的服务器,用我们的服务器来换取session_key和openid。 小程序端比较简单,从教程的API部分把代码拷贝到小程序里就…...