Java 使用接受文件的spring控制器防止内存不足错误

Java 使用接受文件的spring控制器防止内存不足错误,java,spring,file,upload,out-of-memory,Java,Spring,File,Upload,Out Of Memory,假设我正在用Spring设计一个REST服务,我需要一个方法来接受一个文件,并返回某种响应。应用服务器的POST请求大小限制为100MB。下面是假设的spring控制器方法实现: public ResponseEntity<ResponseDto> uploadFile(@RequestBody MultipartFile file) { return ResponseEntity.ok(someService.process(file)); } public R

假设我正在用Spring设计一个REST服务,我需要一个方法来接受一个文件,并返回某种响应。应用服务器的POST请求大小限制为100MB。下面是假设的spring控制器方法实现:

public ResponseEntity<ResponseDto> uploadFile(@RequestBody MultipartFile file) {
        return ResponseEntity.ok(someService.process(file));
} 
public ResponseEntity上载文件(@RequestBody MultipartFile文件){
返回ResponseEntity.ok(someService.process(文件));
} 
假设我的服务器有64GB的RAM。如果在很短的时间内(足够短的时间内,
process()
方法仍在为每个上载的文件运行),1000个用户决定上载100MB的文件(或者只有一个用户同时上载1000个文件),我如何确保不会出现内存不足错误


编辑:为了澄清,我希望确保我的应用程序不会崩溃,而是停止接受/延迟新请求。

您可以监控内存使用情况,查看何时必须停止接受请求或取消现有请求。

你也可以用这个

Runtime runtime = Runtime.getRuntime();
System.out.println("Free memory: " + runtime.freeMemory() + " bytes.");

即使您可以使用64 GB RAM在内存中保存许多文件,您也不想浪费太多资源。有一些节省内存的方法来读取文件,例如,您可以使用BufferedReader,这是一种非常节省内存的方法来读取文件,因为它不会将整个文件存储在内存中

这本书很好地解释了这一点:

从字符输入流读取文本,缓冲字符,以便高效读取字符、数组和行。 可以指定缓冲区大小,也可以使用默认大小。对于大多数情况,默认值足够大

通常,读取器发出的每个读取请求都会导致底层字符或字节流发出相应的读取请求。因此,建议将BufferedReader包装在任何read()操作可能代价高昂的读取器(如FileReader和InputStreamReader)周围。比如说,

缓冲读取器 =新的BufferedReader(新的文件读取器(“foo.in”)

将缓冲来自指定文件的输入。如果没有缓冲,每次调用read()或readLine()都可能导致从文件中读取字节,将其转换为字符,然后返回,这可能非常低效

以下是另一个您可能会发现有用的问题:


如果您需要像您在评论中所说的那样计算文件的校验和,您可以使用。

请考虑创建一个数据库表来保存正在进行的上载:

CREATE TABLE PROC_FILE_UPLOAD 
(
  ID NUMBER(19,0) NOT NULL 
, USER_ID NUMBER(19,0) NOT NULL 
, UPLOAD_STATUS_ID NUMBER(19,0) NOT NULL 
, FILE_SIZE NUMBER(19,0)
, CONSTRAINT PROC_FILE_UPLOAD_PK PRIMARY KEY (ID) ENABLE
);

COMMENT ON COLUMN PROC_FILE_UPLOAD.FILE_SIZE IS 'In Bytes';
USER\u ID
是用户表中的FK,并且
UPLOAD\u STATUS\u ID
将FK以应用程序的不同状态上传到数据字典中(
进行中
完成
错误
未知
,任何适合您的)


在您的服务上载文件之前,它必须检查当前用户是否已上载文件,以及是否已达到最大并发上载次数。如果是这样,请拒绝上载,否则用新上载更新
PROC\u FILE\u upload
信息并继续。

这似乎很酷。Spring/Tomcat/其他应用服务器是否提供了这种机制的某种抽象?实际上它取决于层。如果我处在您的位置,我将分析我是否需要像tomcat这样的容器,或者我将使用Spring boot。基于这一选择……这取决于你可以在哪里申请。如何做出选择取决于。。。。如果它只是一个web服务,或者您也想提供其他服务,比如JSP。。由于对范围的了解有限,很难回答这个问题。如果您也想从外部世界监视它,那么尝试一下,您不需要停止接受新请求。您只需要更高效地读取文件。正如我在回答中所建议的那样,实现BufferedReader更简单、更友好。这似乎很酷,但如果我需要将整个文件一次性读入内存(例如,如果我需要验证校验和),该怎么办?处理大文件不再像过去那样是一个大问题,有很多解决方案。例如,为了计算校验和(我编辑了答案以添加链接):