最近在工作中使用到了spring自帶的@Async,主要是爲了把其中耗時多、響應慢、計算複雜的業務抽出來查詢。從代碼設計上看Spring自帶的比傳統線程池提交在代碼層次上看起來優雅簡潔了不少,無需顯示去申明線程池相關代碼, 在方法上加註解既可異步返回結果。空閒時間大概看了下原理,其實就是代理模式(cglib or 接口), 剛好最近學習到線程和併發相關的jdk組件,今天就打算自己手動實現這個異步組件。
總體實現思路流程:客戶端調用後-》通過代理模式代理-》重寫Submit方法並返回Future-》把Future 放到自定義的異步返回包裝類-》客戶端直接拿到返回的Future 進行阻塞get
流程圖:
以下是接口代理實現,至於Cglib代理實現和接口代理原理是一致的,可以自行實現。
1.新建代理接口
public interface IAsyncProxy { /** * 獲取代理對象 * 1. 如果是實現了接口,默認使用 dynamic proxy 即可。 * 2. 如果沒有實現接口,默認使用 CGLIB 實現代理。 * @return 代理對象 */ Object proxy(); }
2.新建動態代理實現類
public class DynamicProxy implements InvocationHandler, IAsyncProxy { /** * 被代理的對象 */ private final Object target; public DynamicProxy(Object target) { this.target = target; } /** * * * @param proxy 原始對象 * @param method 方法 * @param args 入參 * @return 結果 * @throws Throwable 異常 */ @Override @SuppressWarnings("all") public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return AsyncExecutor.submit(target, method, args); } @Override public Object proxy() { // 我們要代理哪個真實對象,就將該對象傳進去,最後是通過該真實對象來調用其方法的 InvocationHandler handler = new DynamicProxy(target); return Proxy.newProxyInstance(handler.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); } }
其中最主要的是代理之後我們要如何交給異步處理,在invoke方法內,我通過線程池去提交任務,細心的可以發現AsyncExecutor在jdk包裏是沒有的,這個類是我自己定義的。至於原因有以下幾個:
1.jdk自帶的ExecutorService的submit無法滿足現有功能, 所以需要重新實現ExecutorService做擴展,重寫submit方法。
2.submit之後需要包裝統一的返回結果
3.定義異步接口
/** * <p> 異步執行結果 </p> / public interface IAsyncResult<T> extends Future<T> { /** * 獲取執行的結果 * @return 結果 */ Object getResult(); }
抽象的異步返回類
public abstract class AbstractAsyncResult<T> implements IAsyncResult<T> { @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return false; } @Override public T get() throws InterruptedException, ExecutionException { try { return this.get(AsyncConstant.DEFAULT_TIME_OUT, TimeUnit.SECONDS); } catch (TimeoutException e) { throw new RuntimeException(e); } } }
返回結果類
/** * 異步執行結果 */ public class AsyncResult<T> extends AbstractAsyncResult<T> { /** * future 信息 */ private Future<T> future; /** * 結果 */ private Object value; /** * 獲取執行的結果 * @return 結果 */ @Override public Object getResult() { // 直接返回結果 if(future == null) { return this.getValue(); } try { T t = future.get(); // 這裏拿到的 AsyncResult 對象 if(null != t) { return ((AsyncResult)t).getValue(); } return null; } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return future.get(timeout, unit); } public Object getValue() { return this.value; } public void setValue(Object value) { this.value = value; } public void setFuture(Future<T> future) { this.future = future; } }
4.定義一個異步接口,繼承ExecutorService
/** * <p> 異步框架執行器 </p> */ public interface IAsyncExecutor extends ExecutorService { }
/** * 異步執行器 */ public class AsyncExecutor extends ThreadPoolExecutor implements IAsyncExecutor { //region 私有屬性 /** * 是否初始化 */ private static volatile boolean isInit = false; /** * 是否被銷燬 */ private static volatile boolean isDestroy = false; /** * 線程執行器 */ private static ExecutorService executorService = null; //endregion //region 構造器 public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } //endregion @SuppressWarnings("all") public static <T> IAsyncResult<T> submit(Object target, Method method, Object[] objects) { // 初始化的判斷 if(!isInit) { init(); } //通過線程池提交 Future future = executorService.submit(new Runnable() { @Override public void run() { try { method.invoke(target, objects); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); //Future future = executorService.submit(() -> method.invoke(target, objects)); AsyncResult<T> asyncResult = new AsyncResult<>(); asyncResult.setFuture(future); return asyncResult; } /** * 初始化 * 1. 暫時不添加配置相關的信息 * 2. 最後調整狀態 */ private static synchronized void init() { try { if(isInit) { return; } // 各種屬性配置 // 淘汰策略 // 最佳線程數量 executorService = Executors.newFixedThreadPool(10); updateExecutorStatus(true); } catch (Exception e) { throw new AsyncRuntimeException(e); } } /** * 銷燬容器 * 1. 銷燬的時候進行等待,確保任務的正常執行完成。 * 2. 任務執行的統計信息,後期添加。 */ private static synchronized void destroy() { if(isDestroy) { return; } executorService = null; updateExecutorStatus(false); } /** * 更新執行器的狀態 * @param initStatus 初始化狀態 */ private static void updateExecutorStatus(final boolean initStatus) { isInit = initStatus; isDestroy = !isInit; } }
總結:
以上代碼最核心的就是通過動態代理在內部通過線程池異步提交,以及重寫jdk的線程池也是爲了能夠重寫內部核心方法