【Alibaba Cola 状态机】重点解析以及实践案例
【Alibaba Cola 状态机】重点解析以及实践案例
1. 状态模式
状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为,简单地讲就是,一个拥有状态的context对象,在不同状态下,其行为会发生改变。看起来是改变了对象各个接口方法的实现一样。
模式中包含角色:
- 上下文
- 抽象状态
- 具体状态
优点包括解耦客户端和状态对象,可扩展性强,避免大量条件语句。
缺点是可能增加系统类的数量和复杂性。
适用场景如自动售货机的状态转换、线程状态管理等。代码示例展示了自动售卖机如何利用状态模式实现不同状态的切换。
推荐文章:23种设计模式之状态模式(State Pattern)_状态模式哪种状态切换好-CSDN博客
2. 状态机
状态机(Finite State Machine,简称FSM)是一个数学模型,用于描述对象在其生命周期中可能的状态以及状态之间的转换。
它由一组状态、一组事件、一组转换规则和一组动作组成,能够清晰地表示和管理对象的行为和状态变化。
在状态机中,“有限”指的是状态和事件都是有限的,即存在一个有限的状态集和事件集。这使得状态机具有明确的、可控的行为模式,便于分析和实现。
状态机的组成元素:状态、事件、转换、动作
状态(State): 表示对象的当前情况或条件。状态机中的状态是有限的,例如:待机、运行、暂停、停止等。
事件(Event): 触发状态转换的输入或信号。事件可以是外部输入、内部触发或其他系统生成的信号。
转换(Transition): 定义了状态之间的切换规则。当特定的事件发生时,状态机会根据转换规则从一个状态转换到另一个状态。
动作(Action): 在状态转换过程中执行的操作或任务。动作可以是状态进入前执行的预处理、状态转换时执行的中间操作或状态退出后执行的清理工作。
状态机的优缺点
优点:
- 逻辑清晰:状态机将复杂的系统行为分解为简单的状态和状态之间的转换,使系统逻辑更加清晰和易于理解。
- 可维护性高:由于状态机的逻辑是模块化的,任何状态的修改或扩展只需在该状态的实现部分进行,不会影响其他部分,增强了代码的可维护性。
- 可扩展性强:新的状态和转换可以方便地添加到现有的状态机中,使系统具有良好的扩展性。
缺点:状态爆炸,对于复杂系统,状态和转换的数量可能非常庞大,导致状态机图变得复杂难以管理,这被称为“状态爆炸”问题。
3. Alibaba Cola 状态机
实现一个状态机引擎,教你看清DSL的本质_状态机 dsl-CSDN博客
相比Spring statemachine状态机等的复杂,功能多;
但是我们 实际业务员 需要常用的功能,简单使用,所以这类就显得不简洁;再看cola-statemachine相比就是小巧、无状态、简单、轻量、性能极高的状态机DSL实现,解决业务中的状态流转问题。
如果是实现业务的话,阿里状态机是不二之选,更加适合我们日常开发!KISS(Keep It Simple and Stupid)
而如果是比较复杂的业务或者组件开发,这个状态机可能也能 妙用进行应对,面对不了可能就得用 Spring statemachine 有状态的状态机,或者对阿里状态机进行 二次开发
开源者的初心就是,让开发更舒适,结合实际需求抽离出必要部分,而不是严格按照传统状态模式,传统状态机
无状态状态机–cola stateMachine-CSDN博客
状态机本身没有状态,而是提供一个状态机单例,通过输入参数 “起始状态”、“事件”、“上下文”,这些参数足以确定一次状态轮转,期间通过 condition 和 action 后,返回“最终状态”,若轮转失败,则返回原状态;
由于没有状态,所以调用者使用这个状态机都是互不干扰的,通过输入决定输出(一次轮转),做到一个实例服务多个调用者
- 这里的上下文,就是过程中的通行数据罢了
- 你也可以在上下文里面去设置状态,像状态模式那样,当其实在使用状态机的时候,状态机就相当于状态模式的上下文,这样看,发挥状态机的优势,就没必要设置了。
采用了无状态设计之后,我们就可以使用一个状态机 Instance 来响应所有的请求了,性能会大大的提升
原本的状态机是有状态的,状态机当前的状态决定了其行为,这样导致每次请求,都是申请一个新的状态机去维护状态的轮转,轮转的过程,状态机的状态也在时刻发生变化;
当阿里状态机理念是状态机每次进行一次轮转就行了,哪怕需要连续的过程性的轮转,多次请求状态机即可(一个轮转的 action 嵌套执行外部轮转的事件,返回的最终状态可能与实际不符,最好嵌套执行内部轮转而不是外部轮转;或者等轮转结束,再按照这次请求的响应进行下次轮转)
有状态的状态机就相当于可以本地运行的应用,不同客户之间是隔离的,状态在应用内部轮转
无状态的状态机就相当于 web 应用,所有客户访问同一个 web,请求一次,执行一次特定的轮转,响应结果
4. Alibaba Cola 状态机使用
源码其实不难,大部分还是容易看懂的,如果出现问题按照思路可以调试去查查,这里就是我总结的用法。
/*** Alibaba Cola 状态机关键词* State:状态* Event:事件,状态由事件触发,引起变化* Transition:流转,表示从一个状态到另一个状态* External Transition:外部流转,两个不同状态之间的流转* Internal Transition:内部流转,同一个状态之间的流转* Condition:条件,表示是否允许到达某个状态* Action:动作,到达某个状态之后,可以做什么* StateMachine:状态机*/
4.1 StateMachineUtil(核心方法封装)
@Slf4j
public class StateMachineUtil {public static <S, E, C> StateMachine<S, E, C> getMachine(String machineId) {return StateMachineFactory.get(machineId);}public static void showMachine(String machineId) {getMachine(machineId).showStateMachine();}public static String generatePlantUML(String machineId) {return getMachine(machineId).generatePlantUML();}public static <S, E, C> void printMachine(String machineId) {StateMachine<S, E, C> stateMachine = getMachine(machineId);stateMachine.showStateMachine();System.out.println(stateMachine.generatePlantUML());}public static <S, E, C> S fireEvent(String machineId, S state, E event, C context) {return (S) getMachine(machineId).fireEvent(state, event, context);}}
- 通过 machineId 获得状态机实例:
StateMachineFactory.get(machineId)
- 打印状态机(注意重写 toString 方法到想要的效果)
- 执行状态机(machineId,起始状态,事件,上下文)(返回最终状态)
4.2 状态机准备信息
根据状态机轮转所需的信息,也就是准备信息,在状态机构建过程中需要用到;
我将其抽象成接口,有两个:外部流转助手、内部流转助手
- 状态的事件会让状态变成别的状态,还是不变就是这里外和内
public interface StateExternalTransitionHelper<S, E, C> {List<S> getFromState();S getToState(S from) throws GlobalServiceException;E getOnEvent();Condition<C> getWhenCondition();Action<S, E, C> getPerformAction();}
from 为 list 是因为有时候同一事件,多个状态都可以执行,其中 getToState 通过 from 得知 to,并允许抛出异常;
public interface StateInternalTransitionHelper<S, E, C> {List<S> getWithinList();E getOnEvent();Condition<C> getWhenCondition();Action<S, E, C> getPerformAction();
}
4.3 通过准备信息构造状态机
外部流转助手、内部流转助手 的实现类,就蕴含了准备信息,将这些在状态机构造过程中应用:
private static <S, E, C> void builderAssign(StateMachineBuilder<S, E, C> builder,StateExternalTransitionHelper<S, E, C> helper) {List<S> fromStateList = helper.getFromState();if(!CollectionUtil.isEmpty(fromStateList)) {E onEvent = helper.getOnEvent();Condition<C> whenCondition = helper.getWhenCondition();Action<S, E, C> performAction = helper.getPerformAction();fromStateList.forEach(fromState -> {try {S toState = helper.getToState(fromState); // 若抛异常就忽略这一个,构造下一个状态轮转// 不保证每个 toState 相等的情况下,不用 externalTransitions 与 fromAmongbuilder.externalTransition().from(fromState).to(toState).on(onEvent).when(whenCondition).perform(performAction);} catch (GlobalServiceException e) {log.warn(e.getMessage());}});}
}private static <S, E, C> void builderAssign(StateMachineBuilder<S, E, C> builder,StateInternalTransitionHelper<S, E, C> helper) {List<S> withinList = helper.getWithinList();if(!CollectionUtil.isEmpty(withinList)) {E onEvent = helper.getOnEvent();Condition<C> whenCondition = helper.getWhenCondition();Action<S, E, C> performAction = helper.getPerformAction();withinList.forEach(within -> {builder.internalTransition().within(within).on(onEvent).when(whenCondition).perform(performAction);});}
}public static <S, E, C> void buildMachine(String machineId,List<? extends StateExternalTransitionHelper<S, E, C>> externalHelpers,List<? extends StateInternalTransitionHelper<S, E, C>> internalHelpers) {// 创建一个 builderStateMachineBuilder<S, E, C> builder = StateMachineBuilderFactory.create();// 添加轮转externalHelpers.forEach(helper -> {builderAssign(builder, helper);});internalHelpers.forEach(helper -> {builderAssign(builder, helper);});// 创建状态机builder.build(machineId);
}
4.4 示例(简历状态轮转)
不要直接实现那两个接口,要先用模块内部的接口继承,这样注入 Spring 容器中的 bean,获取的时候指定我们自己的接口类型,防止获得别的模块的 helper bean
public interface ResumeStateExternalTransitionHelper extends StateExternalTransitionHelper<ResumeStatus, ResumeEvent, ResumeContext> {}
public interface ResumeStateInternalTransitionHelper extends StateInternalTransitionHelper<ResumeStatus, ResumeEvent, ResumeContext> {}
上下文:
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class ResumeContext {private Long managerId;private StuResume resume;ResumeExecuteDTO executeDTO;public void log(ResumeStatus from, ResumeStatus to, ResumeEvent event) {log.info("resume state from {} to {} run {} currentResume {} managerId {} executeDTO {}",from, to, event, resume.getId(), managerId, executeDTO);}}
简历状态:
@Getter
public enum ResumeStatus {DRAFT("草稿", 0),PENDING_SELECTION("待筛选", 1),REJECTED("筛选不通过", 2),SCHEDULE_INITIAL_INTERVIEW("待安排初试", 3),PENDING_INITIAL_INTERVIEW("待初试", 4),INITIAL_INTERVIEW_PASSED("初试通过", 5), // 仅当初试为最后一个流程时显示INITIAL_INTERVIEW_FAILED("初试不通过", 6), // 仅当初试为最后一个流程时显示SCHEDULE_SECOND_INTERVIEW("待安排复试", 7),PENDING_SECOND_INTERVIEW("待复试", 8),SECOND_INTERVIEW_PASSED("复试通过", 9), // 仅当复试为最后一个流程时显示SECOND_INTERVIEW_FAILED("复试不通过", 10), // 仅当复试为最后一个流程时显示SCHEDULE_FINAL_INTERVIEW("待安排终试", 11),PENDING_FINAL_INTERVIEW("待终试", 12),FINAL_INTERVIEW_PASSED("终试通过", 13), // 仅当复试为最后一个流程时显示FINAL_INTERVIEW_FAILED("终试不通过", 14), // 仅当复试为最后一个流程时显示PENDING_HANDLING("待处理", 15),SUSPENDED("挂起", 16),;ResumeStatus(String message, Integer code) {this.message = message;this.code = code;}@Overridepublic String toString() {return message;}private final String message;@EnumValue@JsonValueprivate final Integer code;public static ResumeStatus get(Integer code) {for (ResumeStatus resumeStatus : ResumeStatus.values()) {if(resumeStatus.getCode().equals(code)) {return resumeStatus;}}throw new GlobalServiceException(GlobalServiceStatusCode.USER_RESUME_STATUS_EXCEPTION);}
}
简历事件:
@Getter
public enum ResumeEvent {NEXT(1, "推进"),APPROVE(2, "通过"),ELIMINATE(3, "淘汰"),RESET(4, "重置"),PENDING(5, "待处理"),SUSPEND(6, "挂起"),CONFIRM(7, "转正"),;@Overridepublic String toString() {return description;}private final Integer event;private final String description;ResumeEvent(Integer event, String description) {this.event = event;this.description = description;}public static ResumeEvent get(Integer event) {for (ResumeEvent resumeEvent : ResumeEvent.values()) {if(resumeEvent.getEvent().equals(event)) {return resumeEvent;}}throw new GlobalServiceException(GlobalServiceStatusCode.USER_RESUME_STATUS_TRANS_EVENT_ERROR);}}
你也可以不是枚举类,但是我们要提供有限的固定的实例,并且代表状态和事件,枚举太适用了!
常量类:
public interface ResumeStateMachineConstants {String RESUME_STATE_MACHINE_ID = "resumeStateMachineId";}
配置类:
@Configuration
@RequiredArgsConstructor
public class ResumeStateMachineBuildConfig {private final List<ResumeStateExternalTransitionHelper> externalHelpers;private final List<ResumeStateInternalTransitionHelper> internalHelpers;@PostConstructpublic void buildInterviewMachine() {StateMachineUtil.buildMachine(ResumeStateMachineConstants.RESUME_STATE_MACHINE_ID,externalHelpers,internalHelpers);StateMachineUtil.printMachine(ResumeStateMachineConstants.RESUME_STATE_MACHINE_ID);}}
一个 helper 实现展示:
@Component
@RequiredArgsConstructor
public class ResumeNextStateHelper implements ResumeStateExternalTransitionHelper {private final Condition<ResumeContext> defaultResumeCondition;private final Action<ResumeStatus, ResumeEvent, ResumeContext> defaultResumeAction;@Overridepublic List<ResumeStatus> getFromState() {return List.of(DRAFT,PENDING_SELECTION,SCHEDULE_INITIAL_INTERVIEW,PENDING_INITIAL_INTERVIEW,SCHEDULE_SECOND_INTERVIEW,PENDING_SECOND_INTERVIEW,SCHEDULE_FINAL_INTERVIEW);}@Overridepublic ResumeStatus getToState(ResumeStatus from) throws GlobalServiceException {return switch (from) {case DRAFT -> PENDING_SELECTION;case PENDING_SELECTION -> SCHEDULE_INITIAL_INTERVIEW;case SCHEDULE_INITIAL_INTERVIEW -> PENDING_INITIAL_INTERVIEW;case PENDING_INITIAL_INTERVIEW -> SCHEDULE_SECOND_INTERVIEW;case SCHEDULE_SECOND_INTERVIEW -> PENDING_SECOND_INTERVIEW;case PENDING_SECOND_INTERVIEW -> SCHEDULE_FINAL_INTERVIEW;case SCHEDULE_FINAL_INTERVIEW -> PENDING_FINAL_INTERVIEW;default -> throw new GlobalServiceException(GlobalServiceStatusCode.USER_RESUME_STATUS_EXCEPTION);};}@Overridepublic ResumeEvent getOnEvent() {return ResumeEvent.NEXT;}@Overridepublic Condition<ResumeContext> getWhenCondition() {return defaultResumeCondition;}@Overridepublic Action<ResumeStatus, ResumeEvent, ResumeContext> getPerformAction() {return defaultResumeAction;}
}
这里这两个是我写的默认值,并注入了容器,这样的写法,需要注意 bean 的名称不要冲突了
通过以上代码,在项目启动的时候即可构造出状态机:
执行状态机(代码片段):
我个人觉得没必要在状态机内部将状态落库,根据请求状态机的响应,进行落库
5. 小思考 · 状态机设计的合理性
状态机并不是通过 from 和 to 确定 event,而是 from 和 event 确定轮转
通过 from 到 to 的变化,是确定不了事件的,实现通过 from 到 to 的变化触发某一事件,事件可能不止一个,而且并不保证触发我们想要的那一个
比如一次请求,对象的当前属性就是 from
,请求是以 event
作为参数,还是以 to
作为参数
① 若是 event
作为参数,那么根据 from
和 event
即可进行状态轮转,并返回最终的状态
② 若是 to
作为参数,from
到 to
的这个状态变化会触发什么特定行为
状态机更注重的是状态的轮转,也就是 ①,而 ② 是状态变化的后置行为
以“一场面试”为例,一场面试的状态可以是: 未开始 、 进行中 、 已结束
如果是 ①,传入的参数可以是 “开始面试” 这一具体事件,当前面试状态是 ”未开始“,就可以轮转成”进行中“,也可以是 “通知用户” 这一事件,状态内部流转的过程中对用户进行面试通知;
如果是 ②,传入的参数可以是 ”进行中“,面试状态将直接更新成”进行中“,状态变化触发对应的事件,但做不了内部轮转
① 这种方式靠的是状态机,让请求行为更加具体,如进行“开始面试”,“通知用户”这种具体的行为
而 ② 更加狭隘,如果我们设计一份代码来管理 from
到 to
触发的事件,如果要符合我们的接口预期,这往往可能 并不能做到 ① 的可读性高、灵活性高、通用性高、可扩展性高
用 ② 来进行状态轮转不太合适,但是也不是完全没用,更适合用其管理一些状态变化固定的“副作用”,作为状态轮转的后置行为,还是不错的!可以结合责任链模式去实现
但是又说回来,
from
到to
的转变的副作用,在编写代码的时候应该也就是规定对应事件的副作用吧,比如 “未开始” 到 “进行中”,就是“面试开始” 这一具体行为的副作用,那其实在状态机就能实现啊;也就是说 ② 这种方式适合,有多个事件可以进行
from
到to
的轮转,并且这些事件都有共同的副作用,这个副作用就可以用 ② 来管理,出现这种情况也很极端了~在比较简单的系统,
from
和to
能够 可以确定唯一的事件,没有内部轮转的需求 ,用这个也无所谓
如果非要 ② 这种请求方式,不想指定 event
,出现特殊的状态变化,就得自动触发对应事件,这种就属于特殊需求了, from
到 to
触发的事件的映射关系,也只能在 to
已知的情况下可以复用,甚至只用于这一特殊请求,代码写得可能比较死,不太优雅🙁,太为难了(;′⌒`),反正我不是很喜欢,我个人比较喜欢优雅直观的设计;
我个人认为要是有个接口可以任意改变状态,那么应该不需要触发什么特定事件了,毕竟都允许可以任意更改了,或者说有一个统一的事件
可以定义一个”任意更改状态“的事件,上下文携带 toState,所有状态都可以触发,在状态机的内部/外部轮转(状态的行为)即可
但这不符合状态机明确的设计理念
综上所述,
用 ① 更加合适,可以让请求行为更加优雅具体直观和灵活,开发低耦合更具有扩展性,能实现的功能更多;② 的这种请求方式适合那种状态变化没有任何事件触发的场景,或触发的都是同一事件的场景,等不具有状态轮转的过程概念的场景。
BUT,
规矩是死的,视具体需求而论,切勿只纸上谈兵!
以上也只是我的想法,不同人有不同的想法和理念!
状态机还可以结合很多其他的设计模式,更多妙用等你开发!
状态机你爱咋用咋用,只要合理都 OK 啦!
开发是灵活的过程,开发者的理念为准,没有固定的强限定,但是我们要满足其基本的优秀写法!
相关文章:

【Alibaba Cola 状态机】重点解析以及实践案例
【Alibaba Cola 状态机】重点解析以及实践案例 1. 状态模式 状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为,简单地讲就是,一个拥有状态的context对象,在不同状态下,其行为会发生改变。看起来是改…...
购买商城源码前需要考虑哪些方面?
前言 购买商城源码前需要考虑的方面包括功能满足、技术兼容性、可扩展性、公司实力、客户评价、安全性与稳定性等。 购买商城源码是一项重要决策,需要综合考虑多个因素。以下是详细的考虑方面: 1.功能满足: 确保所选的源码能够支持企业所…...

MongoDB快速入门CRUD
1. 数据库管理 1.1 切换数据库 切换到名为 myDatabase 的数据库。如果该数据库不存在,MongoDB 会在第一次写入数据时自动创建它。 use myDatabase;1.2 查看当前数据库 显示当前使用的数据库的名称。 db; 1.3 显示所有数据库 列出当前 MongoDB 实例中的所有数…...

【python基础】—利用pandas读取或写入mysql表数据
文章目录 一、read_sql()二、to_sql()三、连接数据库方式—MySQL1、用sqlalchemy包构建数据库链接2、用DBAPI构建数据库链接 四、容易遇到的问题 一、read_sql() 功能 将 SQL 查询/数据库表读入 DataFrame。 语法 读取数据库(通过SQL语句或表名) pand…...
C/C++信号量
文章目录 一、信号量介绍1.1 什么是信号量1.2 信号量的原子性1.3 信号量的使用 二、C语言使用2.1 函数接口2.2 信号量代码 三、C20使用3.1 函数接口 四、C11模拟信号量 一、信号量介绍 1.1 什么是信号量 信号量是一种特殊的变量,是操作系统层面的,可以…...

SSL Pining 问题解决方案
实战案例 为了能够更好的复现 SSL Pining 场景,我们对一个 App(https:app4.scrape.center)进行抓包,这个 App 包含了 SSL Pining 的相关设置,如果我们将手机的代理设置为抓包软件提供的代理服务,那么这个 …...

【Spring Boot】全局异常处理
目录 背景 前言 设计步骤 1.定义异常信息类: 2.自定义异常: 3.创建全局异常处理类 4.在控制器中抛出异常 5.输出 捕获 Valid 校验异常 背景 去面试的时候被问到SpringBoot项目中,如何处理全局异常的,也就是如何捕获全局异…...
安全基础学习-SM3加密算法
SM3是一种广泛使用在中国国家标准中的哈希算法,全称为“中国国家密码算法SM3”。它由中国国家密码管理局制定,主要用于数字签名和消息完整性验证。SM3算法与SHA-256在结构上类似,但其设计具有特定的改进以增强安全性。 SM3算法生成256位的哈希值,使用了32轮的迭代运算,并…...
MySQL中处理JSON数据:大数据分析的新方向
1. 简介 1.1. 概述 在MySQL中处理JSON数据的能力是在MySQL 5.7版本中引入的,并在后续的版本中不断得到增强。这使得MySQL能够直接操作和查询JSON格式的数据,极大地扩展了其处理复杂数据结构的能力。 1.2. 主要特点 灵活性与可扩展性 :JSON允许开发者存储不规则和嵌套的数…...
K8S 容器调度
在Kubernetes中,容器调度是一个自动化的过程,负责将容器(在Kubernetes中称为Pod)分配到集群中的合适节点上运行。这一过程由Kubernetes的调度器(kube-scheduler)控制,它通过一系列算法和策略来确…...

C++ //练习 17.2 定义一个tuple,保存一个string、一个vector<string>和一个pair<string, int>。
C Primer(第5版) 练习 17.2 练习 17.2 定义一个tuple,保存一个string、一个vector和一个pair<string, int>。 环境:Linux Ubuntu(云服务器) 工具:vim 代码块 /**********************…...

外观检测设备真的能提高生产效率吗?
零部件外观检测设备是一种专业的设备,用于对各类零部件的外观进行检测和评估。现代制造业中扮演着重要的角色,能够有效提升产品质量,确保产品符合国家标准和客户需求。 首先,零部件外观检测设备具备高精度和高效率的特点。通过采用…...

ant design pro 中用户的表单如何控制多个角色
ant design pro 如何去保存颜色ant design pro v6 如何做好角色管理ant design 的 tree 如何作为角色中的权限选择之一ant design 的 tree 如何作为角色中的权限选择之二ant design pro access.ts 是如何控制多角色的权限的 看上面的图片 当创建或编辑一个用户时,…...

Prometheus监控系统
目录 1.Prometheus概述 1.1 TSDB时序数据库 1.2 Prometheus 的特点 1.3 Prometheus 的生态组件 1.4 Prometheus 的工作模式: 1.5 Prometheus 的工作流程 1.6 Prometheus 的局限性 2.部署Prometheus 2.1 Prometheust Server 端安装和相关配置 2.2 部署 Expo…...

mq-fanout交换机
交换机 交换机是什么?步骤 交换机本身具备路由功能 消息先发到交换机,交换机在路由到队列,消费者监听队列拿到消息 广播模式是什么 是什么 例如:每个微服务创建队列,订单服务只启动1台,1个消费者,订单 怎么创建 创建一个队列 -交换机里type-选择模式(广播模式) 在交换…...

android13禁用打开wifi ap 热点
总纲 android13 rom 开发总纲说明 目录 1.前言 2.情况分析 3.代码分析 4.代码修改 5.彩蛋 1.前言 这个文章介绍的是如何禁止用户打开wifi热点,禁止用户安装app后,打开wifi热点。 2.情况分析 android13 应用层打开wifi AP public void setWifiApEnabled(boolean isEn…...
前端宝典之六:React源码解析之lane模型
本文主要内容: 介绍lane模型 一、 lane模型 lane模型就是react优先级的机制,可以用来 可以表示优先级的不同可能同时存在几个同优先级的更新,所以还得能表示批的概念方便进行优先级相关计算 1、表示优先级不同 lane模型使用31位的二进制…...

邦德咖啡线下门店盛大开业,引领国产健康咖啡新风尚
近日,国内咖啡市场迎来了一股清新的绿色风潮,邦德咖啡线下门店正式拉开帷幕,以其独特的健康理念和创新的产品,誓要成为国产咖啡界的一股强劲力量。 邦德咖啡线下门店以阿卡迪亚绿色为品牌主色调,立志打造国产健康咖啡…...

Elasticsearch + Search UI 构建一个文件搜索引擎
目录 Elasticsearch使用优势App Search Search UI配置engine集中管理配置和提供实用工具函数配置和初始化一个基于Elasticsearch的搜索界面应用程序Search UI 基础用法 好书推荐 Elasticsearch 使用优势 使用ElasticSearch的主要好处在于其强大的全文搜索和实时分析能力。Elas…...

机械学习—零基础学习日志(如何理解概率论2)
全概率公式与贝叶斯公式 上面所提到的公式,可以使用上一篇文章的基本公式推导。 使用到了概率的基本运算公式。 完整的公式展示: 习题练习: 剩余的练习: 第二题解析: 第三题: 第四题: 注意&…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...