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); } } }