java后台很多场景是需要异步去处理的,比如耗时比较的大的,以及当前任务关系不是很依赖的推送、发送短信、赠送卡券优惠券、打包zip等等。这个时候异步执行器会很方便。
1、定义多线程池
启用异步注解:@EnableAsync
ExecutorConfig.java
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
String executors = "10";//可以从配置文件中获取
@Bean
public Executor asyncServiceExecutor() {
log.debug("开始配置 --> asyncServiceExecutor 异步线程执行器");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(Integer.parseInt(executors));
//配置最大线程数
executor.setMaxPoolSize(Integer.parseInt(executors));
//配置队列大小
executor.setQueueCapacity(0);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
2、使用异步执行
service方法中打上@Async(“asyncServiceExecutor”)注解
package com.dj.yier.service;
import com.dj.admin.config.ConfigProp;
import com.dj.yier.entity.GiftCard;
import com.dj.yier.utils.QRCodeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Service
@Slf4j
public class AsynService {
@Value("${card.url}")
private String cardUrl;
private GiftCardService giftCardService;
@Autowired
private ConfigProp configProp;
/**
* 异步生成图片
*/
@Async("asyncServiceExecutor")
public void executeAsync(GiftCardService service,String batchNo) {
giftCardService = service;
log.info("开始生成图片--> batchNo:" + batchNo);
long startTime = System.currentTimeMillis();
String subPath = "/coupon/" + batchNo + "/";
String fileRealPath = configProp.serverUploadPath + subPath;
String rootPath = configProp.serverUploadRoot + subPath;
File file = new File(fileRealPath + "/createFolder.jpg");
file.getParentFile().mkdirs();
List<GiftCard> cardList = giftCardService.getListByBatchNo(batchNo);
if(!CollectionUtils.isEmpty(cardList)) {
for (GiftCard giftCard : cardList) {
String imgName = giftCard.getCardNo() + ".jpg";
giftCard.setCardImg(rootPath + imgName);
QRCodeUtil.createQRCode(new File(fileRealPath + imgName), 300, cardUrl + giftCard.getCardNo(), "FQ" + giftCard.getCardId());
}
giftCardService.updateBatchById(cardList);
}
log.info("结束生成图片 --> batchNo:{}, 总个数:{},耗时:{}ms",batchNo,cardList.size(),System.currentTimeMillis() - startTime);
}
/**
* 异步打包zip
*/
@Async("asyncServiceExecutor")
public void packageZip(Integer batchId,File filePath,File saveFile) {
log.debug("开始打包ZIP-->" + batchId);
try {
saveFile.getParentFile().mkdirs();
if(saveFile.exists()){
saveFile.delete();
saveFile.createNewFile();
}
FileOutputStream fos = new FileOutputStream(saveFile);
ZipOutputStream out = new ZipOutputStream(fos);
zip(out, filePath, "");
out.close();
log.info("打包ZIP已完成...");
}catch (Exception e){
e.printStackTrace();
log.error("打包ZIP出现异常-->" + batchId);
}
}
public static void zip(ZipOutputStream out, File sourceFile, String base) throws Exception {
//如果路径为目录(文件夹)
if (sourceFile.isDirectory()) {
//取出文件夹中的文件(或子文件夹)
File[] fileList = sourceFile.listFiles();
if (fileList.length == 0) {
//如果文件夹为空,则只需在目的地zip文件中写入一个目录进入点
System.out.println(base + "/");
out.putNextEntry(new ZipEntry(base + "/"));
} else {
//如果文件夹不为空,则递归调用zip,文件夹中的每一个文件(或文件夹)进行压缩
for (File file : fileList) {
zip(out, file, base + "/" + file.getName());
}
}
} else {
//如果不是目录(文件夹),即为文件,则先写入目录进入点,之后将文件写入zip文件中
out.putNextEntry(new ZipEntry(base));
IOUtils.write(FileUtils.readFileToByteArray(sourceFile), out);
out.flush();
}
}
}