logback能够把N天的日志压缩成一个包(zip,gz),在压缩的时候logback采用后台异步线程的方式来实现,下面我们就来看看Future接口在logback中的妙用。java
先来看下Future接口的全貌吧。异步
public interface Future<V> { //取消任务 boolean cancel(boolean mayInterruptIfRunning); // 任务若是被取消就返回true boolean isCancelled(); //若是任务完成就返回true boolean isDone(); // 获取线程的执行结果,若是任务没有执行完成就会一直等待 V get() throws InterruptedException, ExecutionException; //获取任务的执行结果,能够指定一个单位时间,若是在规定的时间内没有完成任务,那么就会抛出TimeoutException异常 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
/** gz压缩方法,用于压缩成.gz文件 */ private void gzCompress(String nameOfFile2gz, String nameOfgzedFile) { File file2gz = new File(nameOfFile2gz); if (!file2gz.exists()) { addStatus(new WarnStatus("The file to compress named [" + nameOfFile2gz + "] does not exist.", this)); return; } if (!nameOfgzedFile.endsWith(".gz")) { nameOfgzedFile = nameOfgzedFile + ".gz"; } File gzedFile = new File(nameOfgzedFile); if (gzedFile.exists()) { addWarn("The target compressed file named [" + nameOfgzedFile + "] exist already. Aborting file compression."); return; } addInfo("GZ compressing [" + file2gz + "] as [" + gzedFile + "]"); createMissingTargetDirsIfNecessary(gzedFile); BufferedInputStream bis = null; GZIPOutputStream gzos = null; try { bis = new BufferedInputStream(new FileInputStream(nameOfFile2gz)); gzos = new GZIPOutputStream(new FileOutputStream(nameOfgzedFile)); byte[] inbuf = new byte[BUFFER_SIZE]; int n; while ((n = bis.read(inbuf)) != -1) { gzos.write(inbuf, 0, n); } bis.close(); bis = null; gzos.close(); gzos = null; if (!file2gz.delete()) { addStatus(new WarnStatus("Could not delete [" + nameOfFile2gz + "].", this)); } } catch (Exception e) { addStatus(new ErrorStatus("Error occurred while compressing [" + nameOfFile2gz + "] into [" + nameOfgzedFile + "].", this, e)); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { // ignore } } if (gzos != null) { try { gzos.close(); } catch (IOException e) { // ignore } } } } //工厂方法,能够根据传入的类型来判断是使用gz,仍是zip压缩 public void compress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) { switch (compressionMode) { case GZ: gzCompress(nameOfFile2Compress, nameOfCompressedFile); break; case ZIP: zipCompress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); break; case NONE: throw new UnsupportedOperationException("compress method called in NONE compression mode"); } }
logback 把压缩的任务交给了一个线程去执行async
//开启一个线程用于压缩日志文件 public Future<?> asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) throws RolloverFailure { CompressionRunnable runnable = new CompressionRunnable(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); ExecutorService executorService = context.getExecutorService(); Future<?> future = executorService.submit(runnable); return future; } //压缩线程 class CompressionRunnable implements Runnable { final String nameOfFile2Compress; final String nameOfCompressedFile; final String innerEntryName; public CompressionRunnable(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) { this.nameOfFile2Compress = nameOfFile2Compress; this.nameOfCompressedFile = nameOfCompressedFile; this.innerEntryName = innerEntryName; } public void run() { Compressor.this.compress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); } }
stop方法才是重头戏,当调用stop方法的时候,须要检查有没有线程在正在进行压缩工做,能够看出logback使用Future的特性就是检测某个后台任务是否在指定时间内完成任务。ide
@Override public void stop() { if (!isStarted()) return; //检查任务是否完成 //压缩任务 waitForAsynchronousJobToStop(compressionFuture, "compression"); //clean任务 waitForAsynchronousJobToStop(cleanUpFuture, "clean-up"); super.stop(); } private void waitForAsynchronousJobToStop(Future<?> aFuture, String jobDescription) { if (aFuture != null) { try { //获取执行结果 aFuture.get(CoreConstants.SECONDS_TO_WAIT_FOR_COMPRESSION_JOBS, TimeUnit.SECONDS); } catch (TimeoutException e) { addError("Timeout while waiting for " + jobDescription + " job to finish", e); } catch (Exception e) { addError("Unexpected exception while waiting for " + jobDescription + " job to finish", e); } } }