使用SpringEvent解决WebUploader大文件上传解耦问题

目录

前言

一、SpringEvent涉及的相关组件

1、 事件(Event)

2、事件监听器

3、事件发布器

二、WebUploader大文件处理的相关事件分析

1、事件发布的时机

2、事件发布的代码

三、事件监听器及实际的业务处理

1、文件上传处理枚举

2、文件上传监听器的实现

3、文件具体处理逻辑

4、实际处理实例

 四、总结


前言

        关于Spring的Event机制,相信使用Java开发的朋友们一定非常熟悉。Spring Event是Spring框架内建的一种发布/订阅(Publish-Subscribe)模式的实现,它允许应用内部不同组件之间通过事件进行通信。当某个特定事件发生时,系统中对这类事件感兴趣的监听器可以接收到通知并执行相应操作。是不是看起来跟消息队列差不多,尤其是这种发布/订阅的模式,确实非常符合消息中间件的模式。通常来说,消息队列一般有以下几种作用。异步、解耦和削峰。不过请大家注意,之所以在这里讲解SpringEvent,在一般的中小型项目中,我们的部署节点是单个,技术的架构选型一般也是单体架构。因此我们可以在不引入复杂架构的前提下来实现一个简单版本的消息队列。通过发布订阅的模式来进行应用程序解耦,让各个功能组件更加符合实际架构的布置。从而让程序扩展起来更方便。以上是关于SpringEvent这个框架的知识,更多的关于SpringEvent的相关知识,大家感兴趣的可以登录spring的官方网站来进行查询。

        除了Spring的Event机制之外,在我们日常的项目开发过程中,肯定会遇到大文件上传的处理场景,而大文件的处理通常是需要蛮长的时间。同时,不同的场景甚至不同的业务,对于上传附件的处理是不尽相同的。比如在用户信息Excel的上传处理中,不仅需要将当前的Excel数据进行关联绑定,同时还需要解析数据后,将Excel提交的数据结果存储到数据库中。而另外一个类型,比如单据生成的任务表格,就需要根据单据信息,匹配不同的模板来生成不同的任务。由此种种需求,要求我们的应用程序在开发过程中具有较大的扩展性,可以支持将不同的应用程序快速的切入到应用中,同时能针对不同的场景灵活开发。极端的情况下,甚至需要同一种业务,根据不同的状态来定制附件的读取需求。

        本文以WebUploader大文件上传组件为例,在大文件处理的场景中使用SpringEvent的事件发布机制,灵活的扩展对文件的处理需求。本文通过代码实例的讲解,让您快速的了解如何在Spring中快速开发Event应用程序,同时使用枚举来实现动态的注册过程,实现方便灵活的注册机制。最后结合一个具体的场景详细说明在学生信息附件上传中来进行附件处理的过程,方便您掌握上述的知识点。

一、SpringEvent涉及的相关组件

        为了让不熟悉SpringEvent的朋友对Event也有一个大致的印象。这里还是对SpringEvent对象包含的方法和相关组件的应用进行简单的介绍。

1、 事件(Event)

        事件(Event)事件是应用程序中发生的某种事情,可以是用户行为、系统状态改变等。在Spring中,事件通常表示为一个Java类,它包含了与事件相关的信息。如果大家做过GUI界面的实际与实现,或者进行过Web界面的开发,相信对事件机制一定非常熟悉。比如鼠标点击事件、鼠标双击事件、鼠标拖拽事件、鼠标悬浮事件等等。事件一定是经过触发的,由某一种设备或者事务来进行触发,从而形成某种事件。在本文的场景中,文件上传后在服务器端进行合成是一种事件。

2、事件监听器

        事件监听器(Event Listener): 事件监听器是一段代码,它等待并响应事件的发生。在Spring中,事件监听器通常实现了ApplicationListener接口,该接口定义了监听事件的方法。如果对监听器模式有所了解朋友一定了解,监听器类的设计非常友好,会根据设计进行监听,而当有相应的变化进行发生时,监听器则会根据发生的情况同时相应的类或者接口,从而实现消息的动态传递。

3、事件发布器

        事件发布器(Event Publisher): 事件发布器负责发布事件,通知所有监听该事件的监听器。在Spring中,ApplicationEventPublisher接口表示事件发布器,可以通过Spring容器自动注入或手动获取。通常在Spring工作环境中,我们会使用applicationContext来进行事件的发布。上面三者就是SpringEvent的核心组件。事件发布器(publisher)会在事件(event)发生时进行事件的发布,事件发布后,有监听者进行事件监听,当监听到自己感兴趣的主体事件,则进行相应的事件处理。由此形成时间的发布、监听和处理的闭环操作。

        在介绍上述的重要组件之后,我们通过大文件处理的实例来具体介绍SpringEvent的详细应用。

二、WebUploader大文件处理的相关事件分析

        本节重点介绍WebUploader大文件处理组件中的后台相关事件处理。通过本节将了解何时进行相应事件的注册,具体的事件发布方法是什么?

1、事件发布的时机

        事件的发布时机是非常重要的,关于Webuploader则不再进行具体介绍。但是需要注意的是,如果在应用程序中采用了WebUploader这种后台处理机制,我们需要在后台实现数据的分片上传处理、分片的合并的操作。同时为了能兼容大文件和小文件的处理。以Webuploader为例,针对大文件,我们以5MB作为一个分片的切分逻辑,这种情况下可能有两种情况需要处理。第一种是单个文件的大小小于5MB,根据分片的策略,小于5MB的文件将不会进行分片而直接上传到后台。这时候也同样不会触发分片的合并逻辑。第二种情况是文件的大小超过5MB,比如有一个256MB的文件,就会进行分片上传。在服务端我们实现自定义的分片上传之后,还需要进行文件的合并。因此,我们在选择事件的发布时机时,就有两个点需要考虑的。需要分片的和不需要分片的文件处理时机。这两种都需要考虑,才能不漏掉相应的文件处理。

2、事件发布的代码

        在掌握了事件的发布时机后,我们就知道了在处理文件上传时的程序中如何切入事件的发布。事件的发布入口有两个地方,第一个无需分片的事件处理入口。第二个是在分片合并完成的事件入口。

        在进行事件发布前,我们需要在程序中创建一个Event的实例对象,用来进行事件信息的绑定和设置。这里我们取名位文件上传事件,关键代码如下所示:

package com.yelang.framework.event;
import org.springframework.context.ApplicationEvent;
import com.yelang.project.webupload.domain.FileEntity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@ToString
public class FileUploadEvent extends ApplicationEvent {private static final long serialVersionUID = 7396389156436678379L;private FileEntity fileEntity;//上传文件对象/***   重写构造函数* @param source 事件源对象* @param fileEntity 已上传的文件对象*/public FileUploadEvent(Object source,FileEntity fileEntity) {super(source);this.fileEntity = fileEntity;}
}

        为了方便大家可以获取上传的文件信息实体,我们将文件实体类在事件发布时一同绑定到事件上下文中。fileEntity其实就是一个文件上传的接收实体,关键代码如下:

package com.yelang.project.webupload.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yelang.framework.web.domain.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@TableName("biz_file")
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class FileEntity extends BaseEntity {private static final long serialVersionUID = 1L;private Long id;@TableField(value = "f_id")private String fid;@TableField(value = "b_id")private String bid;@TableField(value = "f_type")private String type;@TableField(value = "f_name")private String name;@TableField(value = "f_desc")private String desc;@TableField(value = "f_state")private Integer state;@TableField(value = "f_size")private Long size;@TableField(value = "f_path")private String path;@TableField(value = "table_name")private String tablename = "temp_table";private String md5code;private String directory;@TableField(value = "biz_type")private String bizType;@TableField(exist = false)private boolean previewSign;@TableField(exist = false)private String previewType;
}

        我们在小文件(小于5MB)上传成功之后以及大文件合并完成之后就可以发布文件上传事件,在下面的代码中,我们通过applicationContext上下文对象发布了一个FilaUploadEvent的事件。大致的代码如下所示:

@SuppressWarnings("resource")
private AjaxResult mergeChunks(FileEntity db_file,String chunk_dir,String chunks,String f_path) throws IOException {if (db_file == null) {return AjaxResult.error(AjaxResult.Type.WEBUPLOADERROR.value(), "找不到数据");}if (db_file.getState() == 1) {//未分片文件上传成功合并成功后发布相应事件,各监听器自由监听并执行applicationContext.publishEvent(new FileUploadEvent(this, db_file));return AjaxResult.success();}if(db_file.getSize() > block_size){//xxx 其它业务逻辑db_file.setState(1);fileService.updateById(db_file);File tempFile = new File(chunk_dir);if (tempFile.isDirectory() && tempFile.exists()) {tempFile.delete();}//分片文件上传成功合并成功后发布相应事件,各监听器自由监听并执行applicationContext.publishEvent(new FileUploadEvent(this, db_file));}return AjaxResult.success();
}

三、事件监听器及实际的业务处理

        在上面小节中,我们介绍如何发布Spring的Event,同时以一个大文件的上传为例,具体的介绍了如何进行文件上传事件的发布。本节接着在上面的例子中,重点讲解在事件发布后,如何进行事件的监听以及具体的业务回调处理机制。通过本节可以掌握在实际业务中进行灵活的业务扩展和定制。

1、文件上传处理枚举

        在讲解事件监听器之前,首先我们对监听器中的具体回调业务类进行注册。在实际业务中,我们可以选择将具体回调业务类进行持久化处理,比如使用关系型数据库 进行处理,将具体的业务类、物理表、业务属性、回调业务实现类统一保存的数据库中。这样在执行的时候统一通过数据去获取即可。这种模式也是可以的,实现起来也比较简单。如何在不引入数据库的前提下实现呢?其实我们可以利用枚举类来轻松实现这类需求。下面分享一下这种设计,文件上传处理枚举类的业务逻辑如下所示:

package com.yelang.framework.aspectj.lang.enums;
/*** 文件上传监听服务注册枚举类* @author 夜郎king*/
public enum FileUploadServiceRegisterEnum {UNKOWN(-1,"UNKOWN","","","未知"),PROJZSPRCSINFSERVIMPL(0,"biz_student","studentUploadCallbackServiceImpl","123a","项目程序管理文件上传回调处理枚举");private int index;//下标,编号作用private String tableName;//业务表名称,根据表名检索具体执行的servcieprivate String execService;//业务实际执行serviceprivate String bizType;//业务类型private String desc;//描述说明public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}public String getTableName() {return tableName;}public void setTableName(String tableName) {this.tableName = tableName;}public String getExecService() {return execService;}public void setExecService(String execService) {this.execService = execService;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}public String getBizType() {return bizType;}public void setBizType(String bizType) {this.bizType = bizType;}private FileUploadServiceRegisterEnum(int index, String tableName, String execService, String bizType, String desc) {this.index = index;this.tableName = tableName;this.execService = execService;this.bizType = bizType;this.desc = desc;}public static FileUploadServiceRegisterEnum getEnumByTableName(String tableName){FileUploadServiceRegisterEnum result = null;for (FileUploadServiceRegisterEnum enumObj : FileUploadServiceRegisterEnum.values()) {if(enumObj.getTableName().equals(tableName)){result = enumObj;break;}}return result;}public static FileUploadServiceRegisterEnum getEnumByTableNameAndBizType(String tableName,String bizType){FileUploadServiceRegisterEnum result = null;for (FileUploadServiceRegisterEnum enumObj : FileUploadServiceRegisterEnum.values()) {if(enumObj.getTableName().equals(tableName) && enumObj.getBizType().equals(bizType)){result = enumObj;break;}}return result;}
}

        在进行业务注册时,我们会定义具体的枚举实例,如下:PROJZSPRCSINFSERVIMPL(0,"biz_student","studentUploadCallbackServiceImpl","123a","项目程序管理文件上传回调处理枚举");0是下标索引号,biz_student是业务表,studentUploadCallbackServiceImpl是回调的具体业务实现类,123a是业务类型描述,根据需要可以用来区分同一个表的不同业务实现。最后一个是业务的描述。

2、文件上传监听器的实现

        在定义上述的枚举类之后,我们来进行文件上传监听器的实现,核心代码如下:

package com.yelang.framework.event.listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.yelang.common.utils.StringUtils;
import com.yelang.common.utils.spring.SpringUtils;
import com.yelang.framework.aspectj.lang.enums.FileUploadServiceRegisterEnum;
import com.yelang.framework.event.FileUploadEvent;
import com.yelang.project.common.service.IFileUploadCallbackService;
import com.yelang.project.webupload.domain.FileEntity;
/*** 公共事件监听器组件,具体实现使用策略模式实现,统一由本类处理后进行相应转发,* 多种event监听均在本类中实现注册监听,使用event模式便于程序解耦,程序处理逻辑更加清晰* @author 夜郎king*/
@Component
public class YelangSpringListener {private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");@EventListenerpublic void fileUploadEventRegister(FileUploadEvent event){try {sys_user_logger.info("当前处理线程名称:" + Thread.currentThread().getName());FileEntity fileEntity = event.getFileEntity();if(StringUtils.isNotEmpty(fileEntity.getTablename())){FileUploadServiceRegisterEnum rigisterEnum = null;if(StringUtils.isNotBlank(fileEntity.getBizType())) {//业务类型不为空,则根据表名和业务名称来查找执行servicerigisterEnum = FileUploadServiceRegisterEnum.getEnumByTableNameAndBizType(fileEntity.getTablename(), fileEntity.getBizType());}else {rigisterEnum = FileUploadServiceRegisterEnum.getEnumByTableName(fileEntity.getTablename());}if(null != rigisterEnum && StringUtils.isNotEmpty(rigisterEnum.getExecService())){String execService = rigisterEnum.getExecService();IFileUploadCallbackService service = SpringUtils.getBean(execService);service.process(fileEntity);}else{sys_user_logger.info("未注册文件上传监听回调处理器.");}}} catch (Exception e) {sys_user_logger.error("文件上传事件监听发生错误.",e);}}
}

         上面的逻辑中,重点就是找到回调的具体枚举实例,然后使用Spring的IOC机制,找到注册到Spring上下文中的IFileUploadCallbackService类,

if(null != rigisterEnum && StringUtils.isNotEmpty(rigisterEnum.getExecService())){String execService = rigisterEnum.getExecService();IFileUploadCallbackService service = SpringUtils.getBean(execService);service.process(fileEntity);
}

        然后调用process方法开始进行文件的处理。

3、文件具体处理逻辑

        为了让不同的业务实现不同的业务处理需要,我们将文件处理方法封装成统一的一个接口,然后通过不同的实例类来进行实现。接口的定义如下:

package com.yelang.project.common.service;
import com.yelang.project.webupload.domain.FileEntity;
public interface IFileUploadCallbackService {/*** 文件上传事件监听器回调服务接口,封装公共服务,可以读取相关表格或修改业务表,具体实现由各实现类来完成* @param fileEntity 文件实体* @throws Exception*/void process(FileEntity fileEntity) throws Exception;
}

        然后定义统一的文件处理实现类,实现上述的接口,并实现具体的文件处理方法。

package com.yelang.project.common.service.impl;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.yelang.common.utils.StringUtils;
import com.yelang.project.common.service.IFileUploadCallbackService;
import com.yelang.project.extend.student.domain.Student;
import com.yelang.project.extend.student.service.IStudentService;
import com.yelang.project.webupload.domain.FileEntity;
@Service("studentUploadCallbackServiceImpl")
public class StudentUploadCallbackServiceImpl implements IFileUploadCallbackService{private static final Logger logger = LoggerFactory.getLogger("sys-user");@Autowiredprivate IStudentService studentService;@Override@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)public void process(FileEntity fileEntity) throws Exception {if(null != fileEntity && StringUtils.isNotEmpty(fileEntity.getBid())){String pkId = fileEntity.getBid();Student stu = studentService.selectStudentById(Long.valueOf(pkId));//System.out.println(fileEntity.getPath());//System.out.println(stu.getName() + "\t" + stu.getAddress());logger.info("开始处理........");Thread.sleep(35 * 1000);//休眠35秒测试logger.info("执行结束");}}
}

        上面的程序逻辑比较简单,我们仅演示了如何从事件发布器中获取FileEntity实体的信息,同时打印相应的信息。在实际业务中,可以实现更复杂的业务。

4、实际处理实例

        下面我们结合实际场景来看一下具体的实现及调用过程。

        我们来看一下后台的处理信息的输出,

        可以很明显的看到,在后台的控制台已经成功的输出相应的内容,表明事件的发布、监听、处理按照预定的设计运行。

23:14:53.169 [http-nio-8080-exec-37] INFO  sys-user - [fileUploadEventRegister,32] - 当前处理线程名称:http-nio-8080-exec-37
23:14:53.198 [http-nio-8080-exec-37] DEBUG c.y.p.e.s.m.S.selectById - [debug,137] - <==      Total: 1
23:14:53.199 [http-nio-8080-exec-37] INFO  sys-user - [process,32] - 开始处理........
23:15:08.200 [http-nio-8080-exec-37] INFO  sys-user - [process,34] - 执行结束

 四、总结

         以上就是本文的主要内容,本文以WebUploader大文件上传组件为例,在大文件处理的场景中使用SpringEvent的事件发布机制,灵活的扩展对文件的处理需求。本文通过代码实例的讲解,让您快速的了解如何在Spring中快速开发Event应用程序,同时使用枚举来实现动态的注册过程,实现方便灵活的注册机制。行文仓促,定有不足之处,真诚期待各位专家朋友在评论区批评指正,不甚感激。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/876855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python+selenium web自动化测试知识点合集2

选择元素 对于百度搜索页面&#xff0c;如果我们想自动化输入“selenium”&#xff0c;怎么做呢&#xff1f; 这就是在网页中&#xff0c;操控界面元素。 web界面自动化&#xff0c;要操控元素&#xff0c;首先需要 选择 界面元素 &#xff0c;或者说 定位 界面元素 就是 先…

C++客户端Qt开发——界面优化(QSS)

1.QSS 如果通过QSS设置的样式和通过C代码设置的样式冲突&#xff0c;则QSS优先级更高 ①基本语法 选择器{属性名&#xff1a;属性值; } 例如&#xff1a; QPushButton {color: red; } 1>指定控件设置样式 #include "widget.h" #include "ui_widget.h&qu…

qt--做一个拷贝文件器

一、项目要求 使用线程完善文件拷贝器的操作 主窗口不能假死主窗口进度条必须能动改写文件大小的单位&#xff08;自适应&#xff09; 1TB1024GB 1GB1024MB 1MB1024KB 1KB1024字节 二、所需技术 1.QFileDialog 文件对话框 QFileDialog也继承了QDialog类&#xff0c;直接使用静态…

Redis缓存数据库进阶——Redis与分布式锁(6)

分布式锁简介 1. 什么是分布式锁 分布式锁是一种在分布式系统环境下&#xff0c;通过多个节点对共享资源进行访问控制的一种同步机制。它的主要目的是防止多个节点同时操作同一份数据&#xff0c;从而避免数据的不一致性。 线程锁&#xff1a; 也被称为互斥锁&#xff08;Mu…

Robot Operating System——内部审查(Introspection)Service

大纲 introspection_service检验Parameter值和类型修改内部审查&#xff08;Introspection&#xff09;功能的状态完整代码 introspection_client完整代码 测试参考资料 在ROS 2&#xff08;Robot Operating System 2&#xff09;中&#xff0c;内部审查&#xff08;Introspect…

【中项】系统集成项目管理工程师-第7章 软硬件系统集成-7.3软件集成

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

python 裁剪图片

情况&#xff1a; 有时候看视频&#xff0c;看到一个漂亮的妹子&#xff0c;按下 Alt PrintScreen 进行截图之后&#xff0c;会把整个屏幕都截图。 需要适当剪裁一下。 每次打开 PS &#xff0c; 也太慢了。 所以写个代码&#xff0c; 快速处理。 效果对比&#xff1a; 原始…

【2025留学】德国留学真的很难毕业吗?为什么大家不来德国留学?

大家好&#xff01;我是德国Viviane&#xff0c;一句话讲自己的背景&#xff1a;本科211&#xff0c;硕士在德国读的电子信息工程。 之前网上一句热梗&#xff1a;“德国留学三年将是你人生五年中最难忘的七年。”确实&#xff0c;德国大学的宽进严出机制&#xff0c;延毕、休…

OOP知识整合----集合

目录 一、定义 1、集合: ( 不限制长度&#xff0c;存多少是多少) 2、集合框架: 二、List集合中常用的方法 1、Boolean add(Object o) 2、void add(int index,Object o) 3、Boolean remove(Object o) 4、Object remove(int index) 5、int size() 6、Boolean conta…

Code Effective学习笔记--第8章防御式编程

这一章聚焦如何通过断言和Java的异常处理机制这些防御式编程的方法来提高程序的健壮性和安全性&#xff0c;这是防御式编程技术的方面。但是健壮性和安全性到了一定的程度其实是矛盾的&#xff0c;健壮性意味着对于任何的输入&#xff0c;程序都不会终止而且都能给出返回&#…

Tftp服务器环境搭建

1、什么是Tftp TFTP&#xff08;Trivial File Transfer Protocol&#xff0c;简单文件传输协议&#xff09;是一种基于UDP&#xff08;User Datagram Protocol&#xff09;的文件传输协议&#xff0c;它被设计为一个非常简单的文件传输机制&#xff0c;特别适用于那些对复杂性有…

make2exe:自动集成测试

模板Makefile&#xff0c;生成多个C/C模块的集成测试程序。

免费【2024】springboot 基于微信小程序的宠物服务中心

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

JavaDS —— 二叉搜索树、哈希表、Map 与 Set

前言 我们将学习 Map 与 Set 这两个接口下的 TreeMap 与 TreeSet &#xff0c;HashMap 与 HashSet &#xff0c;在学习这四个类使用之前&#xff0c;我们需要先学习 二叉搜索树与 哈希表的知识。 二叉搜索树 在学习二叉树的时候&#xff0c;我们就已经了解过二叉搜索树的概念…

酒店智能门锁接口pro[0922]D801 对接收银-SAAS本地化-未来之窗行业应用跨平台架构

proUSB接口函数[0922中性版]-D801 调用函数库&#xff1a; 提供Windows下的32位动态连接库proRFL.DLL&#xff0c;函数使用详细说明 //-----------------------------------------------------------------------------------// 功能&#xff1a;读DLL版本&#xff0c;不涉…

【Linux C | 网络编程】进程池退出的实现详解(五)

上一篇中讲解了在进程池文件传输的过程如何实现零拷贝&#xff0c;具体的方法包括使用mmap&#xff0c;sendfile&#xff0c;splice等等。 【Linux C | 网络编程】进程池零拷贝传输的实现详解&#xff08;四&#xff09; 这篇内容主要讲解进程池如何退出。 1.进程池的简单退…

Java并发编程(上)

并发&#xff1a;多个线程&#xff08;进程&#xff09;竞争一个资源 并行&#xff1a;多个线程&#xff08;进程&#xff09;同时运行不同资源 线程和进程的关系简单地说&#xff0c;进程是一个容器&#xff0c;一个进程中可以容纳若干个线程&#xff0c;一个进程里面&#…

微信小程序入门

创建一个入门程序 这是index.vxml代码 <!--index.wxml--> <navigation-bar title"Weixin" back"{{false}}" color"black" background"#FFF"></navigation-bar> <view class"container" ><view&…

苹果CMS:资源采集站如何设置定时采集详细教程讲解

我们搭建好站点之后&#xff0c;会自定义一些采集&#xff0c;但是需要每天去手动执行&#xff0c;有时候甚至会忘记&#xff0c;那我们如何处理呢&#xff1f;今天我们就来介绍一下如何设置定时器。 如果按照官方例子来设置定时器会遇到一个问题就是采集的资源未绑定类型&…

WAF+API安全代表厂商|瑞数信息入选IDC报告《生成式AI推动下的中国网络安全硬件市场现状及技术发展趋势》

近日&#xff0c;全球领先的权威资讯机构IDC正式发布《IDC Market Presentation&#xff1a;生成式AI推动下的中国网络安全硬件市场现状及技术发展趋势&#xff0c;2024》报告。报告中IDC 评估了众多厂商的安全硬件产品能力&#xff0c;并给出了产品对应的推荐厂商供最终用户参…