本文示例工程下载:https://files.cnblogs.com/files/xiandedanteng/WebFileDownload20191026.rar

制作一个Webapp,让其中一个网页提供下载链接,以使用户能下载本地文件或是临时生成的文件,这些都不是难事,网上也有很多既存的解决方案。

但是,这个问题难点在,但生成文件过大时,产生java.lang.OutOfMemoryError异常怎么办?有人提出修改JVM内存参数,如-Xms<min>m -Xmx<max>m方式,但终究是治标不治本的方法,如果下载数据量又超过设定的上限呢?

其实问题的本质是:在为大数据生成准备过程中,大量对象产生了来不及释放,因为还需要在接下来的步骤中使用,所以驻留在内存中,内存越积越多,终究导致java.lang.OutOfMemoryError异常。举个例子来说,有个emp表,存储员工的id姓名年龄等,当只有千百条时,取出结果集转成链表再写入csv文件自然没什么问题,但如果数据越来越多,还是结果集放链表里又来不及释放,总有内存不够的时候。

2019-10-25 14:43:05.518 ERROR 40016 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: GC overhead limit exceeded] with root cause

java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.lang.Integer.toString(Unknown Source) ~[na:1.8.0_201]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_201]
    at com.example.demo.CsvUtil.exportBigCsv(CsvUtil.java:78) ~[classes/:na]
    at com.example.demo.SpringBootWeb1Application.downloadBigCsvFile(SpringBootWeb1Application.java:141) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_201]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_201]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_201]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.24.jar:9.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.24.jar:9.0.24]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]

要解决这个问题,就得耐下心来,将整体读整体写改成分批读分批写(分批方案和分页方案类似,诸位可自行寻找合适自己DB的DB dialect),最后再下载。

示例页面:

<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
     <title>happy go lucky</title>
    </head>

     <body>
            <h2>文件下载测试</h2>
            <hr/>
            <ol>
                <li><a href="/dldLocalFile">下载本地文件dld.rar</a></li>
                <li><a href="/dldGeneratedFile/100">下载生成百行CSV文件</a></li>
                <li><a href="/dldGeneratedFile/100000000">下载生成亿行CSV文件</a></li>
                <li><a href="/dldGeneratedFile2/10000000">下载生成千万行CSV文件 可能 出现java.lang.OutOfMemoryError: GC overhead limit exceeded</a></li>
                <li><a href="/dldGeneratedFile3/10000000">下载生成千万行CSV文件 不会可能 出现java.lang.OutOfMemoryError: GC overhead limit exceeded</a></li>
            </ol>
     </body>
</html>
<script type="text/javascript">
<!--
    // 脚本
//-->
</script>

控制类:

package com.example.demo;

import java.io.File;
import java.io.FileInputStream;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@SpringBootApplication
public class WebFileDownloadApplication {
    private static Logger logger = Logger.getLogger(WebFileDownloadApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(WebFileDownloadApplication.class, args);
    }

    @RequestMapping("/")
    public String index() {
        logger.info("进入index页");
        return "index.html";
    }

    @RequestMapping("/dldLocalFile")
    public void downloadLocalFile(HttpServletResponse res, HttpServletRequest req) throws Exception {
        logger.info("下载本地文件");

        String localFilename = "dld.rar";
        String localFilepath = getClass().getResource("/static/" + localFilename).getPath();

        res.setContentType("multipart/form-data");
        res.setCharacterEncoding("UTF-8");
        res.setContentType("text/html");

        String userAgent = req.getHeader("User-Agent");
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            // IE Core
            localFilename = java.net.URLEncoder.encode(localFilename, "UTF-8");
        } else {
            // Non-IE Core
            localFilename = new String((localFilename).getBytes("UTF-8"), "ISO-8859-1");
        }
        res.setHeader("Content-Disposition", "attachment;fileName=" + localFilename);

        localFilepath = URLDecoder.decode(localFilepath, "UTF-8");
        FileInputStream instream = new FileInputStream(localFilepath);
        ServletOutputStream outstream = res.getOutputStream();
        int b = 0;
        byte[] buffer = new byte[1024];
        while ((b = instream.read(buffer)) != -1) {
            outstream.write(buffer, 0, b);
        }
        instream.close();

        if (outstream != null) {
            outstream.flush();
            outstream.close();
        }
    }

    @RequestMapping("/dldGeneratedFile/{count}")
    public void downloadGeneratedCsvFile(HttpServletResponse res, HttpServletRequest req,@PathVariable String count) throws Exception {
        logger.info("Start downloadGeneratedCsvFile");

        SimpleDateFormat dfs = new SimpleDateFormat("yyyyMMddHHmmss");
        Date time = new Date();
        String tStamp = dfs.format(time);

        String localFilename = tStamp+".csv";
        String path=req.getSession().getServletContext().getRealPath("/");
        String localFilepath = path+localFilename;
        logger.info("准备生成的本地路径文件名="+localFilepath);

        res.setContentType("multipart/form-data");
        res.setCharacterEncoding("UTF-8");
        res.setContentType("text/html");

        String userAgent = req.getHeader("User-Agent");
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            // IE Core
            localFilename = java.net.URLEncoder.encode(localFilename, "UTF-8");
        } else {
            // Non-IE Core
            localFilename = new String((localFilename).getBytes("UTF-8"), "ISO-8859-1");
        }
        res.setHeader("Content-Disposition", "attachment;fileName=" + localFilename);

        localFilepath = URLDecoder.decode(localFilepath, "UTF-8");

        List<String> dataList=new ArrayList<String>();
        for(int i=0;i<100;i++) {
            dataList.add(String.valueOf(i));
        }

        File file=new File(localFilepath);
        CsvUtil.generateCsv(file,Integer.parseInt(count));
        logger.info("已经生成文件:"+localFilepath);

        FileInputStream instream = new FileInputStream(localFilepath);
        ServletOutputStream outstream = res.getOutputStream();
        int b = 0;
        byte[] buffer = new byte[1024];
        while ((b = instream.read(buffer)) != -1) {
            outstream.write(buffer, 0, b);
        }
        instream.close();

        if (outstream != null) {
            outstream.flush();
            outstream.close();
            boolean isDeleted=file.delete();
            if(isDeleted) {
                logger.info("已经删除文件:"+localFilepath);
            }
        }
    }

    @RequestMapping("/dldGeneratedFile2/{count}")
    public void downloadGeneratedCsvFile2(HttpServletResponse res, HttpServletRequest req,@PathVariable String count) throws Exception {
        logger.info("Start downloadGeneratedCsvFile2");

        SimpleDateFormat dfs = new SimpleDateFormat("yyyyMMddHHmmss");
        Date time = new Date();
        String tStamp = dfs.format(time);

        String localFilename = tStamp+".csv";
        String path=req.getSession().getServletContext().getRealPath("/");
        String localFilepath = path+localFilename;
        logger.info("准备生成的本地路径文件名="+localFilepath);

        res.setContentType("multipart/form-data");
        res.setCharacterEncoding("UTF-8");
        res.setContentType("text/html");

        String userAgent = req.getHeader("User-Agent");
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            // IE Core
            localFilename = java.net.URLEncoder.encode(localFilename, "UTF-8");
        } else {
            // Non-IE Core
            localFilename = new String((localFilename).getBytes("UTF-8"), "ISO-8859-1");
        }
        res.setHeader("Content-Disposition", "attachment;fileName=" + localFilename);

        localFilepath = URLDecoder.decode(localFilepath, "UTF-8");

        List<String> dataList=new ArrayList<String>();
        for(int i=0;i<100;i++) {
            dataList.add(String.valueOf(i));
        }

        File file=new File(localFilepath);
        CsvUtil.generateCsv2(file,Integer.parseInt(count));
        logger.info("已经生成文件:"+localFilepath);

        FileInputStream instream = new FileInputStream(localFilepath);
        ServletOutputStream outstream = res.getOutputStream();
        int b = 0;
        byte[] buffer = new byte[1024];
        while ((b = instream.read(buffer)) != -1) {
            outstream.write(buffer, 0, b);
        }
        instream.close();

        if (outstream != null) {
            outstream.flush();
            outstream.close();
            boolean isDeleted=file.delete();
            if(isDeleted) {
                logger.info("已经删除文件:"+localFilepath);
            }
        }
    }

    @RequestMapping("/dldGeneratedFile3/{count}")
    public void downloadGeneratedCsvFile3(HttpServletResponse res, HttpServletRequest req,@PathVariable String count) throws Exception {
        logger.info("Start downloadGeneratedCsvFile3");

        SimpleDateFormat dfs = new SimpleDateFormat("yyyyMMddHHmmss");
        Date time = new Date();
        String tStamp = dfs.format(time);

        String localFilename = tStamp+".csv";
        String path=req.getSession().getServletContext().getRealPath("/");
        String localFilepath = path+localFilename;
        logger.info("准备生成的本地路径文件名="+localFilepath);

        res.setContentType("multipart/form-data");
        res.setCharacterEncoding("UTF-8");
        res.setContentType("text/html");

        String userAgent = req.getHeader("User-Agent");
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            // IE Core
            localFilename = java.net.URLEncoder.encode(localFilename, "UTF-8");
        } else {
            // Non-IE Core
            localFilename = new String((localFilename).getBytes("UTF-8"), "ISO-8859-1");
        }
        res.setHeader("Content-Disposition", "attachment;fileName=" + localFilename);

        localFilepath = URLDecoder.decode(localFilepath, "UTF-8");

        List<String> dataList=new ArrayList<String>();
        for(int i=0;i<100;i++) {
            dataList.add(String.valueOf(i));
        }

        File file=new File(localFilepath);
        CsvUtil.generateCsv3(file,Integer.parseInt(count));
        logger.info("已经生成文件:"+localFilepath);

        FileInputStream instream = new FileInputStream(localFilepath);
        ServletOutputStream outstream = res.getOutputStream();
        int b = 0;
        byte[] buffer = new byte[1024];
        while ((b = instream.read(buffer)) != -1) {
            outstream.write(buffer, 0, b);
        }
        instream.close();

        if (outstream != null) {
            outstream.flush();
            outstream.close();
            boolean isDeleted=file.delete();
            if(isDeleted) {
                logger.info("已经删除文件:"+localFilepath);
            }
        }
    }
}

数据生成类:

package com.example.demo;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

public class CsvUtil {
    private static Logger logger = Logger.getLogger(CsvUtil.class);

    // 这种方式不会内存溢出,因为创建的数组对象用于写完文件后在一个循环结束就释放了
    public static boolean generateCsv(File file,int rowCount) {
        try {
            FileWriter fileWriter =new FileWriter(file, true);

            for(int j=0;j<rowCount;j++) {
                int lineNo=j;

                String[] arr=new String[20];

                for(int k=0;k<arr.length;k++) {
                    arr[k]=String.valueOf(k);
                }

                String info=String.valueOf(lineNo)+","+String.join(",", arr)+System.getProperty("line.separator");
                fileWriter.write(info);
            }

            fileWriter.flush();
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }

    // 这种方式因为生成一个大list,容易造成内存驻留过多而溢出
    public static boolean generateCsv2(File file,int rowCount) {
        try {
            // 先模拟访问数据库创建集合,当数据量大时会出现outofmemory异常
            List<String[]> list=new ArrayList<String[]>();
            for(int i=0;i<rowCount;i++) {
                String[] arr=new String[20];
                for(int k=0;k<arr.length;k++) {
                    arr[k]=String.valueOf(k);
                }

                list.add(arr);
            }

            // 再将集合写文件
            FileWriter fileWriter =new FileWriter(file, true);

            int index=0;
            for(String[] arr:list) {
                index++;

                String info=String.valueOf(index)+","+String.join(",", arr)+System.getProperty("line.separator");
                fileWriter.write(info);
            }

            fileWriter.flush();
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }

    // 这种方式改成分批写入文件方式,以规避内存溢出
    public static boolean generateCsv3(File file,int rowCount) {
        logger.info("generateCsv3");

        try {
            final int LinesOnceTime=10000;
            int count=rowCount/LinesOnceTime;

            for(int i=0;i<count;i++) {
                // 再将集合写文件
                FileWriter fileWriter =new FileWriter(file, true);

                List<String[]> list=new ArrayList<String[]>();

                // 这回list被限制在了LinesOnceTime件,这一步代表着从数据库分批取,oracle有townum支持,mysql有limit支持
                for(int j=0;j<LinesOnceTime;j++) {
                    String[] arr=new String[20];

                    for(int k=0;k<arr.length;k++) {
                        arr[k]=String.valueOf(k);
                    }

                    list.add(arr);
                }

                int index=0;
                for(String[] arr:list) {
                    index++;

                    int lineNo=i*LinesOnceTime+index;
                    String info=String.valueOf(lineNo)+","+String.join(",", arr)+System.getProperty("line.separator");
                    fileWriter.write(info);
                }

                fileWriter.flush();
                fileWriter.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }
}

续篇请看:https://www.cnblogs.com/xiandedanteng/p/11747855.html

--END-- 2019年10月26日14:49:02

[SpringBoot/SpringMVC]从Webapp下载一个大文件出现java.lang.OutOfMemoryError: GC overhead limit exceeded怎么办?的更多相关文章

  1. 正确使用MySQL JDBC setFetchSize()方法解决JDBC处理大结果集 java.lang.OutOfMemoryError: Java heap space

    昨天在项目中需要对日志的查询结果进行导出功能. 日志导出功能的实现是这样的,输入查询条件,然后对查询结果进行导出.由于日志数据量比较大.多的时候,有上亿条记录. 之前的解决方案都是多次查询,然后使用l ...

  2. 导入到eclipse里的工程挺大的,然后就一直报: An internal error occurred during: "Building workspace". GC overhead limit exceeded 这个错误。

    解决方法: 原因是Eclipse默认配置内存太小需要更改Eclipse安装文件夹下的eclipse.ini文件. Eclipse.ini默认文件如下: 修改如下: -Xms1024m -Xmx2048 ...

  3. Facebook图片存储系统Haystack——存小文件,本质上是将多个小文件合并为一个大文件来降低io次数,meta data里存偏移量

    转自:http://yanyiwu.com/work/2015/01/04/Haystack.html 一篇14页的论文Facebook-Haystack, 看完之后我的印象里就四句话: 因为[传统文 ...

  4. spring-framework-3.2.4.RELEASE 综合hibernate-release-4.3.5.Final一个错误Caused by: java.lang.NoClassDefFound

    LZ一体化的今天spring-framework-3.2.4.RELEASE 综合hibernate-release-4.3.5.Final一个错误Caused by: java.lang.NoCla ...

  5. 精讲RestTemplate第6篇-文件上传下载与大文件流式下载

    本文是精讲RestTemplate第6篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...

  6. mac下载百度云盘大文件及断点续传的方法

    问题 作为资源共享平台, 百度云做的还是很出色的, "xxx site:pan.baidu.com"就可以找到很丰富的资源. 然而, 下载百度云上的文件就略蛋疼了. 早在12年的时 ...

  7. 推荐一个大文件查找工具---WizTree

    DB备份.dump.电影等文件多了以后,经常遇到磁盘空间不够用的情况,日积月累本来清晰的目录结构找起来也很费劲,尤其是要查找删除无用的大文件.windows本身那差劲的搜索功能就不提了,从搜索引擎上查 ...

  8. 判断大文件是否上传成功(一个大文件上传到ftp,判断是否上传完成)

    大文件上传ftp,不知道有没有上传完成,如果没有上传完成另一个程序去下载这个文件,导致下载不完整. 判断一个文件是否上传完成的方法: /** * 间隔一段时间去计算文件的长度来判断文件是否写入完成 * ...

  9. python如何打开一个大文件?

    with open('a.csv','r') as f: for i in f: print(i) while True: a = f.readline() if not a: break f.rea ...

随机推荐

  1. Windows工作原理

    Windows工作原理中心思想 Windows工作原理的中心思想就是“动态链接”概念.Windows自身带有一大套函数,应用程序就是通过调用这些函数来实现它的用户界面和在屏幕上显示文本与图形的.这些函 ...

  2. 排序算法(冒泡、选择)-python代码展示

    冒泡排序: def bubble_sort(list): for i in range(len(list) - 1): # 这个循环负责设置冒泡排序进行的次数 for j in range(len(l ...

  3. Ubuntu系统---安装“搜狗拼音法”导致桌面打不开

    Ubuntu系统---安装“搜狗拼音法”导致桌面打不开 ubuntu系统中文版,安装完后,自带中文输入法.中文用着好好的,用一段时间后,就会莫名的出现,切换不过来,中文输入不好用了.只是简单想装一个搜 ...

  4. 【Leetcode】【简单】【283. 移动零】【JavaScript】

    题目描述 283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12]输出: [1,3,12,0,0] 说 ...

  5. replace函数实现

    ##replace函数,跟split函数处理类似,比split简单 #coding=gbk ss='** *axx* *bv** *ctt** **dff***' print(ss) result=[ ...

  6. BZOJ 3308 毒瘤结论 网络流

    结论:在答案集合中的数其质因数最多有两个 且有两个的话一个>n1/2一个<n1/2 这样我们就可以把所有质数筛出来 弄成二分图 左边是<n1/2右边是>n1/2的 所以先把单个 ...

  7. mysql总复习

    目录 数据库操作 库操作 表操作 数据行操作 表关系操作 单表操作 外键创建 多表联查 pymysql模块 索引 主键索引 唯一索引 普通索引 数据库操作 库操作 create database 库名 ...

  8. 解决CentOS虚拟机开机黑屏卡死问题

    默认配置 导致的错误 1.直接就是黑屏,连杠杠都没有 2.centos系统关不掉 3.关闭vmware提示:虚拟机XXX繁忙 解决方式 一(我的失败,依旧不行)1.强制关闭vmware,重启计算机(不 ...

  9. 属性 Attribute

    一.创建属性 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor, AllowMultiple = true, ...

  10. spring timetask 定时任务调度

    作者:Garry1115 定时任务调度即在设置的特定时间执行特定的任务,不需要人工干预. spring timertask spring 自身所带定时任务类,不需要引入第三方jar包,使用方式如下: ...