2021SC@SDUSC
消费队列中转换文件分析
分析这几个类,消费队列中转换文件有关的代码。
(一)线程池方法
在FileConvertQueueTask类中,先定义了startTask()方法,在spring容器启动后,开始从消费队列中获取文件并转换。
@PostConstruct
public void startTask(){
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new ConvertTask(previewFactory, cacheService, fileUtils));
logger.info("队列处理文件转换任务启动完成 ");
}
ExecutorService是Java中对线程池定义的一个接口,它java.util.concurrent
包中,在这个接口中定义了和后台任务执行相关的方法。Java API对ExecutorService接口的实现有两个,所以这两个即是Java线程池具体实现类。除此之外,ExecutorService还继承了Executor
接口(注意区分Executor接口和Executors工厂类),这个接口只有一个execute()
方法。
submit(Runnable)可以返回一个Future对象,通过返回的Future对象,我们可以检查提交的任务是否执行完毕。如果任务执行完成,future.get()
方法会返回一个null。注意,future.get()方法会产生阻塞。此时的submit传入的是一个ConvertTask对象。这个类是为了实现转换的任务。
使用完成ExecutorService之后应该关闭它,否则它里面的线程会一直处于运行状态。程序中的ExecutorService没有关闭,这个应用将一直运行。之所以会出现这种情况,是因为ExecutorService中运行的线程会阻止JVM关闭。如果要关闭ExecutorService中执行的线程,我们可以调用ExecutorService.shutdown()
方法。在调用shutdown()方法之后,ExecutorService不会立即关闭,但是它不再接收新的任务,直到当前所有线程执行完成才会关闭,所有在shutdown()执行之前提交的任务都会被执行。如果我们想立即关闭ExecutorService,我们可以调用ExecutorService.shutdownNow()
方法。这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。
(二)转换任务类
由于要使用线程池,ConvertTask静态类实现了Runnable接口。
初始化:
private final Logger logger = LoggerFactory.getLogger(ConvertTask.class);
private final FilePreviewFactory previewFactory;
private final CacheService cacheService;
private final FileUtils fileUtils;
public ConvertTask(FilePreviewFactory previewFactory,
CacheService cacheService,
FileUtils fileUtils) {
this.previewFactory = previewFactory;
this.cacheService = cacheService;
this.fileUtils=fileUtils;
}
run方法中:
public void run() {
while (true) {
String url = null;
try {
url = cacheService.takeQueueTask();
if(url != null){
FileAttribute fileAttribute = fileUtils.getFileAttribute(url);
FileType fileType = fileAttribute.getType();
logger.info("正在处理预览转换任务,url:{},预览类型:{}", url, fileType);
if(fileType.equals(FileType.compress) || fileType.equals(FileType.office) || fileType.equals(FileType.cad)) {
FilePreview filePreview = previewFactory.get(fileAttribute);
filePreview.filePreviewHandle(url, new ExtendedModelMap(), fileAttribute);
} else {
logger.info("预览类型无需处理,url:{},预览类型:{}", url, fileType);
}
}
} catch (Exception e) {
try {
Thread.sleep(1000*10);
} catch (Exception ex){
ex.printStackTrace();
}
logger.info("处理预览转换任务异常,url:{}", url, e);
}
}
}
cacheService.takeQueueTask()方法,从缓存中读取待转换队列。
下面的文件类型转换方法,实现逻辑与文件预览大部分一致。