擴展異步並行調度框架asyncLoad支持註解配置

一、 需求

隨着業務越來越複雜,對應的代碼也越來越複雜,耗時也越來越多,因此急需一套並行框架,通過搜索發現阿里提供了一個並行框架asyncLoad(https://github.com/alibaba/asyncload.git),但是此框架不支持註解的方式,使的對應的代碼侵入性很大,所以對asyncLoad框架進行擴展,使其能夠支持對應的註解配置的方式來進行異步並行。

二、 實現原理

1. 異步並行基本實現方式:

  • 原理:基本就是線程池 + Future 的結合來實現;
  • 優點:開發靈活
  • 缺點:需要開發人員瞭解整個並行框架,且對代碼有侵入,而且對應的返回結果是Future<對象> 和本身原來的返回結果<對象> 不一樣,那麼在寫代碼的時候就要考慮這些差異;

爲了解決異步並行基本實現方式的缺點,就是不需要開發人員爲了實現異步並行使原來代碼實現的方式要進行改變,因此需要另外一種異步並行更通用的實現方式,如asyncLoad這種;

2. 異步並行通用實現方式:

  • 原理:線程池 + Future + Cglib 結合的方式來實現
  • 優點:正好是異步並行基本實現方式對應的缺點,不需要基礎開發人員瞭解更多異步並行實現方式,可以讓基礎開發人員還是按照原來開發串行執行代碼一樣進行開發,唯一的不同就是在需要異步並行執行的方法上增加對應的配置(xml,註解等方式);
  • 缺點:cglib本身的方式帶來的缺點(通過實現對應目標類的子類來實現動態代理,並且可以在生成子類的時候在對應方法上進行攔截,增強子類方法的功能),但是這種方式的代理本身不支持final類(因爲final類不支持生成對應的子類),因此對應的像基元類型就不支持;靈活性不如基礎的好;

三、 增加註解配置

1. 設計

Asyncload原先整體設計對應的類圖如下:
asyncload類圖.jpg

AsyncLoad 註解對應的類圖如下:
擴展asyncLoad支持註解對應的類圖

2. 實現

2.1類功能簡介

  • 註解@AsyncClassDef
@Documented
@Retention(RUNTIME)
@Target({ TYPE })
@Inherited
/**
 * @author yujiakui
 *
 *         下午3:06:31
 *
 */
public @interface AsyncClassDef {

    /**
     * 異步方法列表
     *
     * @return
     */
    AsyncMethodDef[] asyncMethods() default {};

    /**
     * 類級別線程池配置
     *
     * @return
     */
    AsyncThreadPoolConfig classThreadPoolConf() default @AsyncThreadPoolConfig;

}

註解@AsyncClassDef表示的是對應這個類需要對應的異步,但是其中的屬性可以過濾指定的方法能夠進行異步並行處理,如下是其對應的屬性:註解AsyncClassDef對應的屬性

  • 註解@AsyncMethodDef
@Documented
@Retention(RUNTIME)
@Target({ METHOD, ElementType.ANNOTATION_TYPE })
/**
 * @author yujiakui
 *
 *         下午3:02:52
 *
 *         異步並行方法對應的註解
 *
 */
public @interface AsyncMethodDef {

    /**
     * 方法匹配對應的正則PatternMatchUtils
     *
     * 注意:將這個註解放在方法上則這個對應的methodMatchRegex將不起作用,因爲此時就是對應這個方法
     *
     * @return
     */
    String[] methodMatchRegex() default {};

    /**
     * 排除方法匹配模式
     *
     * 注意:將這個註解放在方法上則這個對應的methodMatchRegex將不起作用,因爲此時就是對應這個方法
     *
     * @return
     */
    String[] excludeMethodMatchRegex() default {};

    /**
     * 默認超時時間
     *
     * @return
     */
    long timeout() default 1000;

    /**
     * 開啓的異步線程池中的對應執行的線程是否繼承當前線程的threadLocal,默認不繼承
     *
     * @return
     */
    boolean inheritThreadLocal() default false;

    /**
     * 方法線程池配置
     *
     * @return
     */
    AsyncThreadPoolConfig methodThreadPoolConf() default @AsyncThreadPoolConfig;

}
  • 註解@AsyncThreadPoolConfig
@Documented
@Retention(RUNTIME)
@Target({ ElementType.ANNOTATION_TYPE })
/**
 * @author yujiakui
 *
 *         下午3:43:29
 *
 *         異步線程池配置
 */
public @interface AsyncThreadPoolConfig {

    /**
     * 是否生效,默認爲不生效(如果方法上的線程池不生效,則找類上面的,如果類上面的也不生效,則只有默認全局的)
     *
     * @return
     */
    boolean effect() default false;

    /**
     * 線程池核心線程數和最大線程數的大小,默認是20
     *
     * @return
     */
    int poolSize() default 20;

    /**
     * 隊列大小,默認是100
     *
     * @return
     */
    int queueSize() default 100;

    /**
     * 線程池拒絕處理策略
     *
     * @return
     */
    PoolRejectHandleMode rejectPolicy() default PoolRejectHandleMode.CALLERRUN;
}

註解@AsyncThreadPoolConfig表示的線程池對應的配置屬性信息,具體屬性信息如下表所示:註解AsyncThreadPoolConfig對應的屬性其中對應的PoolRejectHandleMode對象是一個枚舉類型,目前主要提供了兩種類型:REJECT(線程池隊列滿了之後再來請求直接拒絕)和CALLERRUN(用於被拒絕任務的處理程序,它直接在 execute 方法的調用線程中運行被拒絕的任務;如果執行程序已關閉,則會丟棄該任務)

  • 註解@EnableAsyncClass
@Documented
@Retention(RUNTIME)
@Target({ TYPE })
@Inherited
/**
 * @author yujiakui
 *
 *         上午11:35:46
 *
 */
public @interface EnableAsyncClass {

    /**
     * 異步並行類方法信息列表
     *
     * @return
     */
    EnableAsyncClassMethodInfo[] classMethodInfos() default { @EnableAsyncClassMethodInfo };
}

註解@EnableAsyncClass表示的是對應的類開啓對應的異步並行,也就是隻要被這個類調用的方法,只要被調用方法支持對應的異步並行調用,在這個類中就可以被異步並行調用了,對應的屬性如下表所示:註解@EnableAsyncClass對應的屬性信息

  • 註解@EnableAsyncClassMethodInfo
@Documented
@Retention(RUNTIME)
@Target(TYPE_USE)
/**
 * @author yujiakui
 *
 *         上午11:44:26
 *
 *         開啓異步並行類方法信息
 */
public @interface EnableAsyncClassMethodInfo {

    /**
     * 對應類的全名,默認是ALL,就是全部(即是標記了異步並行定義的類)
     *
     * @return
     */
    String classFullName() default AsyncLoadAnnotationConstants.ALL_CLASSES;

    /**
     * 默認全部標記定義了所有異步並行加載的方法
     *
     * @return
     */
    String[] methodMatchRegex() default { AsyncLoadAnnotationConstants.ALL_METHODS };
}

註解@EnableAsyncClassMethodInfo表示的是開啓異步並行調用對應的類和方法信息,就是開啓哪些能夠被異步並行的方法信息(注意:一個是調用方A是開啓異步並行調用,另一個是B和C定義了能夠被並行異步調用,對於定義了能夠進行異步並行調用的方法,只有在調用方開啓了異步調用才起作用),對應的註解屬性信息如下:註解@EnableAsyncClassMethodInfo對應的屬性

  • 註解@EnableAsyncMethod
@Documented
@Retention(RUNTIME)
@Target(METHOD)
/**
 * @author yujiakui
 *
 *         下午3:54:02
 *
 */
public @interface EnableAsyncMethod {

    /**
     * 異步並行類方法信息列表
     *
     * @return
     */
    EnableAsyncClassMethodInfo[] classMethodInfos() default { @EnableAsyncClassMethodInfo };

}

註解@ EnableAsyncMethod開啓異步並行調用的方法,即是被這個開啓異步並行方法調用的方法開啓對應的異步並行調用,比如如果方法A開啓了異步並行調用,並行方法A調用了方法B和C,且B和C都是定義了能夠進行異步並行調用的,則可以在方法A中實現B和C對應的異步並行方法調用(前提是A開啓的方法對應的屬性配置中包括B和C),註解EnableAsyncMethod對應的屬性如下表所示:註解@ EnableAsyncMethod對應的屬性信息

  • 類AsyncAnnotationParserFactory
    類AsyncAnnotationParserFactory主要的功能則是解析註解AsyncClassDef,AsyncMethodDef和AsyncThreadPoolConfig,通過解析他們獲得那些定義了能夠進行異步並行調用的配置信息;並且此類還可以從全局的配置信息中獲取對應的異步並行全局的線程池配置。
  • 類AsyncLoadHandleFactory
    類AsyncLoadHandleFactory主要的功能是根據類AsyncAnnotationParserFactory解析註解得到的異步並行調用的配置信息,來對具體方法調用進行攔截並開啓對應的異步並行調度(開啓線程池和cglib包裝對應的返回結果)。
  • 類AsyncLoadHandlerAdvice
    類AsyncLoadHandlerAdvice主要的功能是攔截標記了註解@AsyncClassDef的類,並對應其中標記了@AsyncMethodDef的方法進行異步並行調用,在進行異步並行調用之前,還要經過是否開啓異步並行調用的判斷,如果沒有開啓,則不會進行異步並行調用。
  • 類AsyncLoadEnableAdvice
    類AsyncLoadEnableAdvice主要的功能是攔截標記了註解@ EnableAsyncClass的類,並對註解@EnableAsyncClassMethodInfo和@EnableAsyncMethod進行解析獲得對應的開啓異步並行調用的配置信息,這個配置信息通過ThreadLocal傳給類AsyncLoadHandlerAdvice進行異步並行調用之前的開啓功能判斷。

2.2對應的處理流程

對應整體調用的序列圖如下:整體流程圖

3. 使用

  • 定義可以進行異步並行調用的方法,如下所示:
@Component
@AsyncClassDef
public class AsyncLoadAnnotationTestServiceImpl extends AsyncLoadTestServiceImpl {

    @Override
    @AsyncMethodDef(timeout = 10)
    public AsyncLoadTestModel getRemoteModel(String name, long sleep) {
        return super.getRemoteModel(name, sleep);
    }
}
  • 開啓對應的異步並行調用,如下所示:
@Component
@EnableAsyncClass
public class AsyncLoadAnnotationMultiMethodTest {

    @Autowired
    private AsyncLoadAnnotationTestServiceImpl asyncLoadAnnotationTestServiceImpl;

    @EnableAsyncMethod
    public List<AsyncLoadTestModel> multiHandler(String name, long sleep) {

        List<AsyncLoadTestModel> results = Lists.newArrayList();
        for (int i = 0; i < 5; i++) {
            AsyncLoadTestModel model = asyncLoadAnnotationTestServiceImpl.getRemoteModel(name,
                    sleep);

            results.add(model);
        }
        return results;
    }
}
  • 測試
public class AsyncLoadAnnotationMultiTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(
                "com.alibaba.asyncload.impl.annotation",
                "com.alibaba.asyncload.annotation",
                "com.alibaba.asyncload.domain");
        // 執行測試
        AsyncLoadAnnotationMultiMethodTest service = annotationConfigApplicationContext
                .getBean(AsyncLoadAnnotationMultiMethodTest.class);
        List<AsyncLoadTestModel> models = service.multiHandler("xxx", 10000);
        long start = 0, end = 0;
        for (AsyncLoadTestModel model : models) {
            start = System.currentTimeMillis();
            System.out.println(model.getDetail());
            end = System.currentTimeMillis();
            System.out.println("costTime:" + (end - start));
        }
    }
}

四、源碼地址

https://github.com/lwjaiyjk/asyncload.git

參考:
[1] https://github.com/alibaba/asyncload.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章