天天看點

jdk8環境下,添加重複注解的美好體驗

為了實作業務層緩存,定義了幾個注解:@Cache.able、@Cache.put、@Cache.del

分别實作對業務方法的 緩存檢測、緩存插入 和 緩存清除。

public @interface Cache {

    /**
     * 緩存檢測
     * @author netwild
     */
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    public static @interface able{ String cache() default ""; String key() default ""; }


    /**
     * 緩存插入
     * @author netwild
     */
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    public static @interface put{ String cache() default ""; String key() default ""; }

    /**
     * 緩存清除
     * @author netwild
     */
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    public static @interface del{ String cache() default ""; String key() default "" }
    
}      

對一個業務方法來說,前兩個注解沒必要添加多個,但 緩存清除 的注解在有些時候需要多次引用,比如:

@Override
@Cache.del(key="#(id)")
@Cache.del(key="ItemMap")
public boolean deleteById(String id) {
    return super.deleteById(id);
}      

以上的業務方法很簡單,就是根據ID删除指定的Model

但對于緩存來說,不僅要清除相應Key值的單條資料,還要清除包含這個Model的集合資料

是以就需要為這個業務方法添加兩個 @Cache.del 注解來實作上面的需求

但此時會發現IDE的錯誤提示:

Duplicate annotation of non-repeatable type @Cache.del. 
Only annotation types marked @Repeatable can be used multiple times at one target.      

我的環境是JDK8,支援重複注解就是JDK8的一個新特性,下面就來試驗一下

按照提示,給 @Cache.del 增加 @Repeatable 子注解,同時建立一個包含 @Cache.del 的容器注解:

/**
     * 緩存清除
     * @author netwild
     */
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    @Repeatable(Cache.dels.class)    //支援重複注解,同時指定容器注解
    public static @interface del{ String cache() default ""; String key() default "" }

    /**
     * 緩存清除容器 
     * @author netwild
     */
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    public static @interface dels{ Cache.del[] value(); }  //容器内定義指定類型的數組      

代碼中的紅色部分是需要特殊注意的

其中對于原有的 @Cache.del 增加了 @Repeatable 子注解,說明該注解可以重複使用,同時指定了重複注解的 資料儲存容器

之後增加的 @Cache.dels 就是容器注解,隻在擷取注解資料時使用,平時這個注解屬于隐身狀态

上面的修改完成之後,會發現之前在業務方法上添加的重複注解不再提示錯誤了,OK

最後看看如何擷取重複注解的資料:

Annotation[] annos = method.getAnnotations();
if(annos.length > 0){
    Arrays.stream(annos).forEach(anno -> {
        if(anno instanceof Cache.del){ //單條清除注解
            Cache.del temp = (Cache.del)anno;
            String cacheName = buildCacheName(temp.cache());
            String cacheKey = buildCacheKey(temp.key());
            //具體處理邏輯
        }else if(anno instanceof Cache.dels){ //多條清除注解
            Cache.dels dels = (Cache.dels)anno;
            Cache.del[] delarr = dels.value();
            Arrays.stream(delarr).forEach(temp -> {
                String cacheName = temp.cache();
                String cacheKey = temp.key();
                //具體處理邏輯
            }
        }
    });
}      

在周遊注解時,需要同時判斷單條注解和重複注解兩種情況

如果業務方法隻添加了一個@Cache.del注解,那麼不會執行注解容器;否則需要從容器中獲得重複注解的資料

看到最後,我們才發現,JDK8對于重複注解的實作其實就是個文法糖,内部實作還是注解嵌套的模式

但在開發體驗上确實比以前好多了!

寵辱不驚,看庭前花開花落;去留無意,望天上雲卷雲舒