最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java自定注解完整示例代碼

 更新時(shí)間:2026年01月14日 10:56:18   作者:隨忄不隨性  
Java注解是一種元數(shù)據(jù),可以提供有關(guān)程序代碼的額外信息,它們可以用于標(biāo)記類、方法、字段等元素,它允許我們?cè)谠创a中嵌入元數(shù)據(jù)這篇文章主要介紹了java自定注解的相關(guān)資料,需要的朋友可以參考下

1 理解Java注解

實(shí)際上Java注解與普通修飾符(public、static、void等)的使用方式并沒(méi)有多大區(qū)別,下面的例子是常見(jiàn)的注解:

public class AnnotationDemo {
    //@Test注解修飾方法A
    @Test
    public static void A(){
        System.out.println("Test.....");
    }

    //一個(gè)方法上可以擁有多個(gè)不同的注解
    @Deprecated
    @SuppressWarnings("uncheck")
    public static void B(){

    }
}

@Test實(shí)際上是一種標(biāo)記注解,起標(biāo)記作用,運(yùn)行時(shí)告訴測(cè)試框架該方法為測(cè)試方法。
而對(duì)于@Deprecated和@SuppressWarnings(“uncheck”),則是Java本身內(nèi)置的注解,在代碼中,可以經(jīng)??匆?jiàn)它們。

2 Java內(nèi)置標(biāo)準(zhǔn)注解

JavaSE中內(nèi)置三個(gè)標(biāo)準(zhǔn)注解,定義在java.lang中:

  • @Override:用于修飾此方法覆蓋了父類的方法;
  • @Deprecated:用于修飾已經(jīng)過(guò)時(shí)的方法;
  • @SuppressWarnnings:用于通知java編譯器禁止特定的編譯警告。

2.1@Override

用于標(biāo)明此方法覆蓋了父類的方法。

2.2@Deprecated

用于標(biāo)明已經(jīng)過(guò)時(shí)的方法或類。用 @Deprecated 注釋的程序元素,不鼓勵(lì)程序員使用這樣的元素,通常是因?yàn)樗芪kU(xiǎn)或存在更好的選擇。在使用不被贊成的程序元素或在不被贊成的代碼中執(zhí)行重寫時(shí),編譯器會(huì)發(fā)出警告。

2.3@SuppressWarnnings

用于有選擇的關(guān)閉編譯器對(duì)類、方法、成員變量、變量初始化的警告。SuppressWarnings annotation類型只定義了一個(gè)單一的成員,所以只有一個(gè)簡(jiǎn)單的value={…}作為name=value對(duì)。又由于成員值是一個(gè)數(shù)組,故使用大括號(hào)來(lái)聲明數(shù)組值。

其數(shù)組的值可以為下來(lái)枚舉:

  • deprecation:使用了不贊成使用的類或方法時(shí)的警告;
  • unchecked:執(zhí)行了未檢查的轉(zhuǎn)換時(shí)的警告,例如當(dāng)使用集合時(shí)沒(méi)有用泛型 (Generics) 來(lái)指定集合保存的類型;
  • fallthrough:當(dāng) Switch 程序塊直接通往下一種情況而沒(méi)有 Break 時(shí)的警告;
  • path:在類路徑、源文件路徑等中有不存在的路徑時(shí)的警告;
  • serial:當(dāng)在可序列化的類上缺少 serialVersionUID 定義時(shí)的警告;
  • finally:任何 finally 子句不能正常完成時(shí)的警告;
  • all:關(guān)于以上所有情況的警告。

注意:我們可以在下面的情況中縮寫annotation:當(dāng)annotation只有單一成員,并成員命名為"value=“。這時(shí)可以省去"value=”。如:

    @SuppressWarnings({"unchecked","deprecation"})
    public void test1() {
    }

3 注解基礎(chǔ)

3.1 注解分類

根據(jù)注解參數(shù)的個(gè)數(shù),注解分為標(biāo)記注解、單值注解、完整注解三類。

(1)標(biāo)記注解:一個(gè)沒(méi)有成員定義的Annotation類型被稱為標(biāo)記注解。如:@Test,@Inherited,@Documented

(2)單值注解:只有一個(gè)值

(3)完整注解:擁有多個(gè)值。

根據(jù)注解使用方法和用途:

(1)JDK內(nèi)置系統(tǒng)注解

(2)元注解

(3)自定義注解

3.2 元注解

所謂元注解就是標(biāo)記其他注解的注解。

Java5.0定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類型,它們被用來(lái)提供對(duì)其它 annotation類型作說(shuō)明。

3.2.1 @Target

表示該注解用于什么地方,可能的值在枚舉類ElemenetType。

類型枚舉說(shuō)明
ElemenetType.CONSTRUCTOR標(biāo)明注解可以用于構(gòu)造函數(shù)聲明
ElemenetType.FIELD標(biāo)明該注解可以用于字段(域)聲明,包括enum實(shí)例
ElemenetType.LOCAL_VARIABLE標(biāo)明注解可以用于局部變量聲明
ElemenetType.METHOD標(biāo)明該注解可以用于方法聲明
ElemenetType.PACKAGE標(biāo)明注解可以用于包聲明
ElemenetType.PARAMETER標(biāo)明該注解可以用于參數(shù)聲明
ElemenetType.TYPE標(biāo)明該注解可以用于類、接口(包括注解類型)或enum聲明
ElemenetType.ANNOTATION_TYPE標(biāo)明注解可以用于注解聲明(應(yīng)用于另一個(gè)注解上)
ElemenetType.TYPE_PARAMETER標(biāo)明注解可以用于類型參數(shù)聲明(1.8新加入)
ElemenetType.TYPE_USE類型使用聲明(1.8新加入)

示例1:

@Target(ElementType.TYPE)
public @interface Table {
    /**
     * 數(shù)據(jù)表名稱注解,默認(rèn)值為類名稱
     * @return
     */
    public String tableName() default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn {
}

@Table 可以用于注解類、接口(包括注解類型) 或enum聲明,而@NoDBColumn僅可用于注解類的成員變量。

3.2.2 @Retention

用來(lái)約束注解的生命周期??蛇x的參數(shù)值在枚舉類型RetentionPolicy中,分別有三個(gè)值,源碼級(jí)別(source),類文件級(jí)別(class)或者運(yùn)行時(shí)級(jí)別(runtime)。

類型枚舉說(shuō)明
RetentionPolicy.SOURCE注解將被編譯器丟棄(該類型的注解信息只會(huì)保留在源碼里,源碼經(jīng)過(guò)編譯后,注解信息會(huì)被丟棄,不會(huì)保留在編譯好的class文件里,如@Override
RetentionPolicy.CLASS注解在class文件中可用,但會(huì)被VM丟棄(該類型的注解信息會(huì)保留在源碼里和class文件里,在執(zhí)行的時(shí)候,不會(huì)加載到虛擬機(jī)中),請(qǐng)注意,當(dāng)注解未定義Retention值時(shí),默認(rèn)值是CLASS
RetentionPolicy.RUNTIME注解信息將在運(yùn)行期(JVM)也保留,因此可以通過(guò)反射機(jī)制讀取注解的信息(源碼、class文件和執(zhí)行的時(shí)候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。這也是我們常用的。

示例1:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField";
    public boolean defaultDBValue() default false;
}

Column注解的的RetentionPolicy的屬性值是RUTIME,這樣注解處理器可以通過(guò)反射,獲取到該注解的屬性值,從而去做一些運(yùn)行時(shí)的邏輯處理。

3.2.3 @Documented

用于描述其它類型的annotation應(yīng)該被作為被標(biāo)注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個(gè)標(biāo)記注解,沒(méi)有成員。

3.2.4 @Inherited

@Inherited元注解是一個(gè)標(biāo)記注解,@Inherited闡述了某個(gè)被標(biāo)注的類型是被繼承的。如果一個(gè)使用了@Inherited修飾的annotation類型被用于一個(gè)class,則這個(gè)annotation將被用于該class的子類。

注意:@Inherited annotation類型是被標(biāo)注過(guò)的class的子類所繼承。類并不從它所實(shí)現(xiàn)的接口繼承annotation,方法并不從它所重載的方法繼承annotation。
 
當(dāng)@Inherited annotation類型標(biāo)注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強(qiáng)了這種繼承性。如果我們使用java.lang.reflect去查詢一個(gè)@Inherited annotation類型的annotation時(shí),反射代碼檢查將展開工作:檢查class和其父類,直到發(fā)現(xiàn)指定的annotation類型被發(fā)現(xiàn),或者到達(dá)類繼承結(jié)構(gòu)的頂層。

3.3 注解支持的數(shù)據(jù)類型

注解支持的元素?cái)?shù)據(jù)有:

  • 所有基本類型(int,float,boolean,byte,double,char,long,short)
  • String
  • Class
  • enum
  • Annotation
  • 上述類型的數(shù)組

注意:倘若使用了其他數(shù)據(jù)類型,編譯器將會(huì)丟出一個(gè)編譯錯(cuò)誤,注意,聲明注解元素時(shí)可以使用基本類型但不允許使用任何包裝類型,同時(shí)還應(yīng)該注意到注解也可以作為元素的類型,也就是嵌套注解(SpringBoot中多為嵌套注解)。

示例1

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Reference{
    boolean next() default false;
}

public @interface AnnotationElementDemo {
    //枚舉類型
    enum Status {FIXED,NORMAL};

    //聲明枚舉
    Status status() default Status.FIXED;

    //布爾類型
    boolean showSupport() default false;

    //String類型
    String name()default "";

    //class類型
    Class<?> testCase() default Void.class;

    //注解嵌套
    Reference reference() default @Reference(next=true);

    //數(shù)組類型
    long[] value();
}

3.4 編譯器對(duì)默認(rèn)值的限制

編譯器對(duì)元素的默認(rèn)值有些過(guò)分挑剔。首先,元素不能有不確定的值。也就是說(shuō),元素必須要么具有默認(rèn)值,要么在使用注解時(shí)提供元素的值。其次,對(duì)于非基本類型的元素,無(wú)論是在源代碼中聲明,還是在注解接口中定義默認(rèn)值,都不能以null作為值,這就是限制,沒(méi)有什么利用可言,但造成一個(gè)元素的存在或缺失狀態(tài),因?yàn)槊總€(gè)注解的聲明中,所有的元素都存在,并且都具有相應(yīng)的值,為了繞開這個(gè)限制,只能定義一些特殊的值,例如空字符串或負(fù)數(shù),表示某個(gè)元素不存在。
如:@Test

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Test {

    /**
     * Default empty exception
     */
    static class None extends Throwable {
        private static final long serialVersionUID = 1L;

        private None() {
        }
    }

    Class<? extends Throwable> expected() default None.class;

    long timeout() default 0L;
}

3.5 注解不支持繼承

注解是不支持繼承的,因此不能使用關(guān)鍵字extends來(lái)繼承某個(gè)@interface,但注解在編譯后,編譯器會(huì)自動(dòng)繼承java.lang.annotation.Annotation接口。

3.6 快捷方式

所謂的快捷方式就是注解中定義了名為value的元素,并且在使用該注解時(shí),如果該元素是唯一需要賦值的一個(gè)元素,那么此時(shí)無(wú)需使用key=value的語(yǔ)法,而只需在括號(hào)內(nèi)給出value元素所需的值即可。這可以應(yīng)用于任何合法類型的元素,記住,這限制了元素名必須為value。

如:2.3節(jié)的示例中。

4 自定義注解

使用@interface自定義注解時(shí),自動(dòng)繼承了java.lang.annotation.Annotation接口,由編譯程序自動(dòng)完成其他細(xì)節(jié)。在定義注解時(shí),不能繼承其他的注解或接口。

4.1 注解示例

先看一個(gè)Java的注解類@Deprecated的源碼:

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

(1)首先,使用@interface聲明了Deprecated注解

(2)其次,使用@Target注解傳入{CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}參數(shù),來(lái)標(biāo)明@Deprecated可以用在構(gòu)造器,字段,局部變量,方法,包,參數(shù),類或接口上。

(3)再者,使用@Retention(RetentionPolicy.RUNTIME)則用來(lái)表示該注解生存期是運(yùn)行時(shí)。

(4)最后,使用@Documented則用來(lái)表明,當(dāng)前注解在生成javadoc時(shí)需要展示,否則不予顯示。

從代碼上看注解的定義很像接口的定義,確實(shí)如此,畢竟在編譯后也會(huì)生成Deprecated.class文件。對(duì)于@Target@Retention,@Documented是由Java提供的元注解。

4.2 定義注解格式

@interface用來(lái)聲明一個(gè)注解,其中的每一個(gè)方法實(shí)際上是聲明了一個(gè)配置參數(shù)。方法的名稱就是參數(shù)的名稱,返回值類型就是參數(shù)的類型(返回值類型只能是基本類型、Class、String、enum)。可以通過(guò)default來(lái)聲明參數(shù)的默認(rèn)值。
public @interface 注解名{定義體s}

4.3 注解參數(shù)(即方法)

注解里面的每一個(gè)方法實(shí)際上就是聲明了一個(gè)配置參數(shù),其規(guī)則如下:

①修飾符

只能用public或默認(rèn)(default)這兩個(gè)訪問(wèn)權(quán)修飾 ,默認(rèn)為default

②類型

注解參數(shù)只支持以下數(shù)據(jù)類型:

  • 基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short);
  • String類型;
  • Class類型;
  • enum類型;
  • Annotation類型;
  • 以上所有類型的數(shù)組

③命名

對(duì)取名沒(méi)有要求,如果只有一個(gè)參數(shù)成員,最好把參數(shù)名稱設(shè)為"value",后加小括號(hào)。

④參數(shù)

注解中的方法不能存在參數(shù)

⑤默認(rèn)值

可以包含默認(rèn)值,使用default來(lái)聲明默認(rèn)值。

4.4 示例

以下舉兩個(gè)例子:

LogTreadAnnotation 使用Log4j2時(shí),控制多線程中線程日志數(shù)據(jù)的注解。

/**
 * @author pangzi
 * @version V1.0
 * @Description log4j多線程日志輸出注解
 *    使用該注解的方法,其運(yùn)行日志除了在正常的log文件中輸出外。
 *    還會(huì)在 thread目錄下 job:uuid-YYYYMMDD.log 文件中輸出。
 * @date 2019-11-02 16:34
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogTreadAnnotation {
}

DataSource 多數(shù)據(jù)源切換注解

/**
 * @author pangzi
 * @version V1.0
 * @Description 用于aop類中當(dāng)作切入點(diǎn)來(lái)選擇數(shù)據(jù)源
 * @date 2019-06-03 14:43
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    DataSourceEnum value() default DataSourceEnum.MYSQL;
}

5 注解處理器

如果沒(méi)有用來(lái)讀取注解的方法和工作,那么注解也就不會(huì)比注釋更有用處了。使用注解的過(guò)程中,很重要的一部分就是創(chuàng)建于使用注解處理器。

5.1 反射機(jī)制

Retention.RUNTIME時(shí),Java使用Annotation接口來(lái)代表程序元素前面的注解,該接口是所有Annotation類型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,該接口代表程序中可以接受注解的程序元素,該接口主要有如下幾個(gè)實(shí)現(xiàn)類:

  • Class:類定義
  • Constructor:構(gòu)造器定義
  • Field:類的成員變量定義
  • Method:類的方法定義
  • Package:類的包定義

java.lang.reflect 包下主要包含一些實(shí)現(xiàn)反射功能的工具類,實(shí)際上,java.lang.reflect 包所有提供的反射API擴(kuò)充了讀取運(yùn)行時(shí)Annotation信息的能力。當(dāng)一個(gè)Annotation類型被定義為運(yùn)行時(shí)的Annotation后,該注解才能是運(yùn)行時(shí)可見(jiàn),當(dāng)class文件被裝載時(shí)被保存在class文件中的Annotation才會(huì)被虛擬機(jī)讀取。

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過(guò)反射獲取了某個(gè)類的AnnotatedElement對(duì)象之后,程序就可以調(diào)用該對(duì)象的如下四個(gè)個(gè)方法來(lái)訪問(wèn)Annotation信息(以上5個(gè)類都實(shí)現(xiàn)以下的方法):

返回值方法名稱說(shuō)明
getAnnotation(Class annotationClass)該元素如果存在指定類型的注解,則返回這些注解,否則返回 null。
Annotation[]getAnnotations()返回此元素上存在的所有注解,包括從父類繼承的
booleanisAnnotationPresent(Class<? extends Annotation> annotationClass)如果指定類型的注解存在于此元素上,則返回 true,否則返回 false。
Annotation[]getDeclaredAnnotations()返回直接存在于此元素上的所有注解,注意,不包括父類的注解,調(diào)用者可以隨意修改返回的數(shù)組;這不會(huì)對(duì)其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響,沒(méi)有則返回長(zhǎng)度為0的數(shù)組
Annotation[]getAnnotationsByType(Class annotationClass)JDK1.8新增
Annotation[]getDeclaredAnnotationsByType(Class annotationClass)JDK1.8新增

示例:

/***********注解聲明***************/
/**
 * 水果名稱注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}
/**
 * 水果顏色注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    /**
     * 顏色枚舉
     * @author peida
     *
     */
    public enum Color{ BULE,RED,GREEN};
    /**
     * 顏色屬性
     * @return
     */
    Color fruitColor() default Color.GREEN;
}

/**
 * 水果供應(yīng)者注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
    /**
     * 供應(yīng)商編號(hào)
     * @return
     */
    public int id() default -1;
    /**
     * 供應(yīng)商名稱
     * @return
     */
    public String name() default "";
    /**
     * 供應(yīng)商地址
     * @return
     */
    public String address() default "";
}
/***********注解使用***************/
public class Apple {
    @FruitName("Apple")
    private String appleName;
    @FruitColor(fruitColor=Color.RED)
    private String appleColor;
    @FruitProvider(id=1,name="陜西紅富士集團(tuán)",address="陜西省西安市延安路89號(hào)紅富士大廈")
    private String appleProvider;
}
/***********注解處理器***************/
public class FruitInfoUtil {
    public static void getFruitInfo(Class</> clazz){

        String strFruitName=" 水果名稱:";
        String strFruitColor=" 水果顏色:";
        String strFruitProvicer="供應(yīng)商信息:";

        Field[] fields = clazz.getDeclaredFields();

        for(Field field :fields){
            if(field.isAnnotationPresent(FruitName.class)){
                FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
                strFruitName=strFruitName+fruitName.value();
                System.out.println(strFruitName);
            }
            else if(field.isAnnotationPresent(FruitColor.class)){
                FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
                strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
                System.out.println(strFruitColor);
            }
            else if(field.isAnnotationPresent(FruitProvider.class)){
                FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);
                strFruitProvicer=" 供應(yīng)商編號(hào):"+fruitProvider.id()+" 供應(yīng)商名稱:"+fruitProvider.name()+" 供應(yīng)商地址:"+fruitProvider.address();
                System.out.println(strFruitProvicer);
            }
        }
    }
}
/***********輸出結(jié)果***************/
public class FruitRun {
    /**
     * @param args
     */
    public static void main(String[] args) {
        FruitInfoUtil.getFruitInfo(Apple.class);
    }
}

5.2 SpringAOP

除了通過(guò)反射工具自定義注解解釋器外,在日常開發(fā)中用的最多的就是注解與Spring AOP結(jié)合完成特定的工作。

示例

下面以4.4節(jié)中的日志注解為例介紹。

LogTreadAnnotation主要的通途就是,當(dāng)標(biāo)注@LogTreadAnnotation方法執(zhí)行時(shí),會(huì)根據(jù)方法參數(shù)判斷,如果參數(shù)不一致,則整個(gè)方法及后續(xù)方法的日志都輸出在一個(gè)log文件中,即每次標(biāo)注@LogTreadAnnotation方法的日志都會(huì)在不同的日志文件中。

/**
 * @author pangzi
 * @version V1.0
 * @Description log4j多線程日志輸出注解
 *    使用該注解的方法,其運(yùn)行日志除了在正常的log文件中輸出外。
 *    還會(huì)在 thread目錄下 job:uuid-YYYYMMDD.log 文件中輸出。
 * @date 2019-11-02 16:34
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogTreadAnnotation {
}

/**
 * @author pangzi
 * @version V1.0
 * @Description log4j多線程日志控制切面
 * @date 2019-11-02 16:30
 */
@Component      //聲明組件
@Aspect         //聲明切面
@ComponentScan  //組件自動(dòng)掃描
@EnableAspectJAutoProxy //spring自動(dòng)切換JDK動(dòng)態(tài)代理和CGLIB
public class LogTreadRecordAspect {

    @Pointcut("@annotation(com.zznode.gum.task.core.aop.LogTreadAnnotation)")
    public void addLogTread(){}

    @Before("addLogTread()")
    public void beforeAdvide(){
        //TODO 操作日志@Before 方法執(zhí)行前
    }

    @After("addLogTread()")
    public void afterAdvide() {
        //TODO 操作日志@After 方法執(zhí)行后
    }

    @Around("addLogTread()")
    public void aroundAvide(ProceedingJoinPoint pjp) throws Throwable {
        //操作日志@Around 方法執(zhí)行前
        Object[] args = pjp.getArgs();
        if(args != null && args.length >1) {
           String jobId = args[0].toString();
           String uuid = args[1].toString();
           LogUtils.logThreadBegin(jobId+":"+uuid);
        }
        //方法執(zhí)行
        pjp.proceed();

        //操作日志@Around 方法執(zhí)行后
        LogUtils.logTreadEnd();
    }
}

/**
 * @author pangzi
 * @version V1.0
 * @Description Log4j2多線程輸出日志工具類
 * @date 2019-11-02 15:07
 */
public class LogUtils {

    /**
     * 開始日志輸出到指定線程
     * @param key
     */
    public static void logThreadBegin(String key) {
        ThreadContext.put("JobUUID",key);
    }

    /**
     * 結(jié)束日志輸出
     */
    public static void logTreadEnd() {
        ThreadContext.remove("JobUUID");
    }
}

使用

/**
 * @author pangzi
 * @version V1.0
 * @Description 數(shù)據(jù)匯聚計(jì)算Controller
 * @date 2019-09-16 14:20
 */
@Slf4j
@RestController
@RequestMapping("/dataConverge")
@Api(value = "數(shù)據(jù)計(jì)算任務(wù)RESTFUL")
public class DataConvergeController {

    @Autowired
    private DataConvergeService dataConvergeService;

    @ApiOperation(value = "報(bào)表指標(biāo)天匯聚計(jì)算任務(wù)", notes = "報(bào)表指標(biāo)天匯聚計(jì)算任務(wù)")
    @GetMapping("/rptIndexDayConverge")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "jobId", value = "任務(wù)編號(hào)", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "uuid", value = "任務(wù)實(shí)例編號(hào)", required = true, dataType = "String", paramType = "query")
    })
    @ResponseBody
    @LogTreadAnnotation
    protected Result<String> rptIndexDayConverge(@RequestParam(name="jobId") String  jobId,
                                                 @RequestParam(name="uuid") String  uuid) {
        dataConvergeServiceAh.rptIndexDayConverge(jobId,uuid);
        //返回處理中
        return new Result<>(EnumResult.EXECUTING.getIndex(), EnumResult.EXECUTING.getName());
    }

另附 log4j2.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN" monitorInterval="60">
    <Properties>
        <Property name="PATTERN">%d{DEFAULT} [%t] %-5p %c{1.}.%M %L - %msg%xEx%n</Property>
    </Properties>
    <appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
            <PatternLayout pattern="${PATTERN}" />
        </Console>

        <RollingFile name="TRACE" fileName="${sys:app.log.home}/task-all.log" filePattern="${sys:app.log.home}/$${date:yyyy-MM}/task-all-%d{MM-dd-yyyy}-%i.log.gz">
            <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY" />
            <PatternLayout pattern="${PATTERN}" />
            <SizeBasedTriggeringPolicy size="20MB" />
        </RollingFile>

        <RollingFile name="DEBUG" fileName="${sys:app.log.home}/task-debug.log" filePattern="${sys:app.log.home}/$${date:yyyy-MM}/task-debug-%d{MM-dd-yyyy}-%i.log.gz">
            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
            <PatternLayout pattern="${PATTERN}" />
            <SizeBasedTriggeringPolicy size="20MB" />
        </RollingFile>

        <RollingFile name="INFO" fileName="${sys:app.log.home}/task-info.log" filePattern="${sys:app.log.home}/$${date:yyyy-MM}/task-info-%d{MM-dd-yyyy}-%i.log.gz">
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
            <PatternLayout pattern="${PATTERN}" />
            <SizeBasedTriggeringPolicy size="20MB" />
        </RollingFile>

        <RollingFile name="ERROR" fileName="${sys:app.log.home}/task-error.log" filePattern="${sys:app.log.home}/$${date:yyyy-MM}/task-error-%d{MM-dd-yyyy}-%i.log.gz">
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />
            <PatternLayout pattern="${PATTERN}" />
            <SizeBasedTriggeringPolicy size="20MB" />
        </RollingFile>

        <Routing name="thread">
            <Routes pattern="$${ctx:JobUUID}">
                <Route>
                    <File name="File-${ctx:JobUUID}" fileName="${sys:app.log.home}/threads/${ctx:JobUUID}.log">
                        <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
                        <PatternLayout pattern="${PATTERN}" />
                    </File>
                </Route>
            </Routes>
        </Routing>
    </appenders>

    <!--然后定義logger,只有定義了logger并引入的appender,appender才會(huì)生效 -->
    <loggers>
        <!--過(guò)濾掉spring和mybatis的一些無(wú)用的DEBUG信息 -->
        <logger name="org.springframework" level="INFO" />
        <logger name="org.mybatis" level="debug" />
        <logger name="springfox.documentation" level="ERROR" />
        <logger name="io.netty" level="INFO" />
        <logger name="org.apache" level="info" />
        <logger name="reactor.util" level="info" />
        <logger name="org.flowable" level="info" />
        <logger name="com.test" level="debug" />
        <logger name="io.lettuce" level="info" />
        <logger name="org.quartz" level="info" />
        <logger name="org.hibernate.validator" level="info" />

        <root level="trace">
            <appender-ref ref="Console" />
            <appender-ref ref="TRACE" />
            <appender-ref ref="DEBUG" />
            <appender-ref ref="INFO" />
            <appender-ref ref="ERROR" />
            <appender-ref ref="thread" />
        </root>
    </loggers>
</configuration>

5.3 Spring IOC

除了配置AOP之外,其次就是結(jié)合IOC,直接從IOC容器中拿取標(biāo)注了指定注解的Bean。

5.3.1 注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ColumnCommandOrder {
    /**
     * 默認(rèn)值處理順序
     * @return 序號(hào)
     */
    int valueOrder() default 99;

    /**
     * 檢查處理順序
     * @return 序號(hào)
     */
    int checkOrder() default 99;

    /**
     * 指定報(bào)文類型。
     * 只有指定的報(bào)文類型,才使用該Command
     * @return 報(bào)文類型數(shù)組
     */
    String[] telexType() default {AnalyseConstants.TELEX_TYPE_NOTAMNCR};
}

5.3.2 注解解析

通過(guò)IOC獲取標(biāo)注了該注解的類實(shí)例。

(1)ApplicationContext的工具類

@Component
public class AnalyseServiceContext implements ApplicationContextAware {

    private static ApplicationContext applicationContext=null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        AnalyseServiceContext.applicationContext = applicationContext;
    }

    public static <T> T getBean(String beanName) {
        return (T)applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    public static Map<String,Object> getBeanMap(Class<? extends Annotation> tClass) {
          return applicationContext.getBeansWithAnnotation(tClass);
    }

    public static <T> Map<String,T> getBeansOfType(Class<T> clazz) {
        return applicationContext.getBeansOfType(clazz);
    }
}

注解解析

public class TelexBusinessCheckParserHandler implements ITelexParserHandler{
    @Override
    public void parserTelex(ITelexBusinessHandler businessHandler) {
        if (businessHandler.isErrorOut()) {
            return;
        }
        TreeMap<Integer, ITelexColumnParserCommand> commandTreeMap= Maps.newTreeMap();
        Map<String,Object> maps = AnalyseServiceContext.getBeanMap(ColumnCommandOrder.class);
        for (Map.Entry<String, Object> bean: maps.entrySet()) {
            Object obj = bean.getValue();
            ColumnCommandOrder annotation = obj.getClass().getAnnotation(ColumnCommandOrder.class);
            if (null!=annotation) {
                int order = annotation.checkOrder();
                commandTreeMap.put(order, (ITelexColumnParserCommand) obj);
            }
        }

        commandTreeMap.forEach((k,v)->{
            v.setBusinessHandler(businessHandler);
            if (log.isDebugEnabled()) {
                log.debug("業(yè)務(wù)規(guī)則判斷{},處理類{}",k,v.getClass().getSimpleName());
            }
            try {
                ColumnCommandOrder annotation = v.getClass().getAnnotation(ColumnCommandOrder.class);
                if (ArrayUtils.contains(annotation.telexType(),
                        businessHandler.getOutputType().getApplicationCode())) {
                    v.columnCheckHandler();
                }
            } catch (Exception e) {
                log.error("業(yè)務(wù)規(guī)則判斷{},處理類{},異常{}",k,v.getClass().getSimpleName(),e);
            }
        });
    }
}

5.3.3 注解標(biāo)注

@Slf4j
@Component
@ColumnCommandOrder(valueOrder = 12,checkOrder = 12)
public class ItemBParserCommand extends AbstractColunmParserCommand {
...
}

6 Java 8中注解增強(qiáng)

對(duì)于元注解,Java 8 主要有兩點(diǎn)改進(jìn):類型注解和重復(fù)注解。

6.1 重復(fù)注解

元注解@Repeatable是JDK1.8新加入的,它表示在同一個(gè)位置重復(fù)相同的注解。在沒(méi)有該注解前,一般是無(wú)法在同一個(gè)類型上使用相同的注解的。

//Java8前無(wú)法這樣使用
@FilterPath("/web/update")
@FilterPath("/web/add")
public class A {}

Java8前如果是想實(shí)現(xiàn)類似的功能,我們需要在定義@FilterPath注解時(shí)定義一個(gè)數(shù)組元素接收多個(gè)值如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FilterPath {
    String [] value();
}

//使用
@FilterPath({"/update","/add"})
public class A { }

但在Java8新增了@Repeatable注解后就可以采用如下的方式定義并使用了

//使用Java8新增@Repeatable原注解
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(FilterPaths.class)//參數(shù)指明接收的注解class
public @interface FilterPath {
    String  value();
}

// 自定義一個(gè)包裝類FilterPaths注解用來(lái)放置一組具體的FilterPath注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface FilterPaths {
    FilterPath[] value();
}

// 使用案例新方法
@FilterPath("/web/update")
@FilterPath("/web/add")
class AA{ }

// 使用案例舊方法
@FilterPaths ({@FilterPath("/web/update"), @FilterPath("/web/add")}) 
class AA{ }

見(jiàn)5.1節(jié),為了處理上述的新增注解,Java8還在AnnotatedElement接口新增了getDeclaredAnnotationsByType() getAnnotationsByType()兩個(gè)方法并在接口給出了默認(rèn)實(shí)現(xiàn),在指定@Repeatable的注解時(shí),可以通過(guò)這兩個(gè)方法獲取到注解相關(guān)信息。

注意:

  • 舊版API中的getDeclaredAnnotation()getAnnotation()是不對(duì)@Repeatable注解的處理的(除非該注解沒(méi)有在同一個(gè)聲明上重復(fù)出現(xiàn))。
  • getDeclaredAnnotationsByType方法獲取到的注解不包括父類,其實(shí)當(dāng) getAnnotationsByType()方法調(diào)用時(shí),其內(nèi)部先執(zhí)行了getDeclaredAnnotationsByType方法,只有當(dāng)前類不存在指定注解時(shí),getAnnotationsByType()才會(huì)繼續(xù)從其父類尋找,但請(qǐng)注意如果@FilterPath@FilterPaths沒(méi)有使用了@Inherited的話,仍然無(wú)法獲取。

6.2 類型注解

6.2.1 注解使用的范圍。

在java 8之前,注解只能是在聲明的地方所使用,java8開始,注解可以應(yīng)用在任何地方。

  • TYPE_USE則可以用于標(biāo)注任意類型(不包括class)
// 用于構(gòu)造函數(shù),創(chuàng)建類實(shí)例
new@Interned MyObject();

// 用于強(qiáng)制類型轉(zhuǎn)換和instanceof檢查,注意這些注解中用于外部工具,它們不會(huì)對(duì)類型轉(zhuǎn)換或者instanceof的檢查行為帶來(lái)任何影響。
myString = (@NonNull String) str;
if(input instanceof @NonNull String)

// 用于父類或者接口
class Image implements @Rectangular Shape { }

// 用于指定異常
void monitorTemperature() throws @Critical TemperatureException { ... }
  • TYPE_PARAMETER 標(biāo)注在類型參數(shù)上
// 標(biāo)注在類型參數(shù)上
class D<@Parameter T> { }

注意:

  • 在Java 8里面,當(dāng)類型轉(zhuǎn)化甚至分配新對(duì)象的時(shí)候,都可以在聲明變量或者參數(shù)的時(shí)候使用注解。
  • Java注解可以支持任意類型。
  • 類型注解只是語(yǔ)法而不是語(yǔ)義,并不會(huì)影響java的編譯時(shí)間,加載時(shí)間,以及運(yùn)行時(shí)間,也就是說(shuō),編譯成class文件的時(shí)候并不包含類型注解。

由上面的注解使用范圍的變更,引出ElementType新增的兩個(gè)類型。

6.2.2 新增的兩種ElementType

新增的兩個(gè)注釋的程序元素類型 ElementType.TYPE_USEElementType.TYPE_PARAMETER用來(lái)描述注解的新場(chǎng)合 。

  • ElementType.TYPE_PARAMETER 表示該注解能寫在類型變量的聲明語(yǔ)句中。
  • ElementType.TYPE_USE 表示該注解能寫在使用類型的任何語(yǔ)句中(eg:聲明語(yǔ)句、泛型和強(qiáng)制轉(zhuǎn)換語(yǔ)句中的類型)。
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@interface MyAnnotation {}

6.2.3 類型注解的作用

類型注解被用來(lái)支持在Java的程序中做強(qiáng)類型檢查。配合第三方插件工具Checker Framework,可以在編譯的時(shí)候檢測(cè)出runtime error(eg:UnsupportedOperationException; NumberFormatException;NullPointerException異常等都是runtime error),以提高代碼質(zhì)量。這就是類型注解的作用。

注意:

使用Checker Framework可以找到類型注解出現(xiàn)的地方并檢查。

總結(jié)

到此這篇關(guān)于java自定注解的文章就介紹到這了,更多相關(guān)java自定注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java如何實(shí)現(xiàn)判斷并輸出文件大小

    Java如何實(shí)現(xiàn)判斷并輸出文件大小

    這篇文章主要介紹了Java如何實(shí)現(xiàn)判斷并輸出文件大小問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 使用Java將Excel中的數(shù)字轉(zhuǎn)換為文本或?qū)⑽谋拘蛿?shù)字轉(zhuǎn)換為數(shù)字

    使用Java將Excel中的數(shù)字轉(zhuǎn)換為文本或?qū)⑽谋拘蛿?shù)字轉(zhuǎn)換為數(shù)字

    在 Excel 中,數(shù)字有時(shí)會(huì)以文本的形式存儲(chǔ),這可能會(huì)影響數(shù)據(jù)的計(jì)算、排序和處理,無(wú)論是將數(shù)字轉(zhuǎn)換為文本,還是將文本型數(shù)字轉(zhuǎn)換為數(shù)字,這兩種操作在處理 Excel 數(shù)據(jù)時(shí)都非常常見(jiàn)且重要,本文將介紹如何使用 Java 完成這兩個(gè)任務(wù),需要的朋友可以參考下
    2025-12-12
  • java中申請(qǐng)不定長(zhǎng)度數(shù)組ArrayList的方法

    java中申請(qǐng)不定長(zhǎng)度數(shù)組ArrayList的方法

    今天小編就為大家分享一篇java中申請(qǐng)不定長(zhǎng)度數(shù)組ArrayList的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Java人機(jī)猜拳實(shí)現(xiàn)的思路及方法實(shí)例

    Java人機(jī)猜拳實(shí)現(xiàn)的思路及方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Java人機(jī)猜拳實(shí)現(xiàn)的思路及方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 簡(jiǎn)單剖析Java中動(dòng)態(tài)線程池的擴(kuò)容以及縮容操作

    簡(jiǎn)單剖析Java中動(dòng)態(tài)線程池的擴(kuò)容以及縮容操作

    這篇文章主要為大家詳細(xì)介紹了Java中動(dòng)態(tài)線程池的擴(kuò)容以及縮容操作的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-01-01
  • JAVA實(shí)現(xiàn)線程的三種方法

    JAVA實(shí)現(xiàn)線程的三種方法

    這篇文章介紹了JAVA實(shí)現(xiàn)線程的三種方法,有需要的朋友可以參考一下
    2013-09-09
  • MyBatis-Plus聯(lián)表查詢及分頁(yè)代碼舉例

    MyBatis-Plus聯(lián)表查詢及分頁(yè)代碼舉例

    本文介紹了mybatis-plus-join工具的使用,該工具可以簡(jiǎn)化mybatis-plus的聯(lián)表查詢,使得開發(fā)者可以以類似QueryWrapper的方式進(jìn)行聯(lián)表查詢,無(wú)需手動(dòng)編寫xml文件,感興趣的朋友跟隨小編一起看看吧
    2025-03-03
  • java lambda表達(dá)式用法總結(jié)

    java lambda表達(dá)式用法總結(jié)

    這篇文章主要介紹了java lamda表達(dá)式用法總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Caffeine中本地緩存的最佳實(shí)踐與性能優(yōu)化指南

    Caffeine中本地緩存的最佳實(shí)踐與性能優(yōu)化指南

    作為 Java 生態(tài)中性能優(yōu)異的本地緩存實(shí)現(xiàn),Caffeine 提供了更高的吞吐量和更低的延遲,本文將深入剖析 Caffeine 的核心原理、源碼實(shí)現(xiàn)和實(shí)際應(yīng)用,希望對(duì)大家有所幫助
    2025-09-09
  • IDEA自定義Maven archetype的方法步驟

    IDEA自定義Maven archetype的方法步驟

    在創(chuàng)建Maven的項(xiàng)目時(shí)我們發(fā)現(xiàn)了一個(gè)很不方便的問(wèn)題,就是每次創(chuàng)建Maven的工程的時(shí)候,都需要選擇一個(gè)骨架,本文主要介紹了IDEA自定義Maven archetype的方法步驟,感興趣的可以了解一下
    2022-03-03

最新評(píng)論

湘潭市| 洛浦县| 宿松县| 宁国市| 靖州| 宜君县| 武乡县| 涿州市| 巍山| 平顺县| 尼木县| 从江县| 鄂州市| 建德市| 静安区| 嘉黎县| 兰考县| 平乡县| 湘潭县| 手机| 汨罗市| 阿拉善左旗| 双鸭山市| 黄大仙区| 武城县| 高雄县| 湄潭县| 宁安市| 什邡市| 保亭| 绍兴市| 陇川县| 葫芦岛市| 遂宁市| 澜沧| 崇明县| 聊城市| 西昌市| 宜兰县| 盐山县| 金坛市|