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

一文詳解Java如何實(shí)現(xiàn)自定義注解

 更新時(shí)間:2024年07月19日 10:15:02   作者:kkkkatoq  
Java實(shí)現(xiàn)自定義注解其實(shí)很簡(jiǎn)單,跟類定義差不多,只是屬性的定義可能跟我們平時(shí)定義的屬性略有不同,這篇文章主要給大家介紹了關(guān)于Java如何實(shí)現(xiàn)自定義注解的相關(guān)資料,需要的朋友可以參考下

一、@interface 關(guān)鍵字

我們想定義一個(gè)自己的注解 需要使用 @interface 關(guān)鍵字來定義。

如定義一個(gè)叫 MyAnnotation 的注解:

public @interface MyAnnotation { }

二、元注解

  光加上 @interface 關(guān)鍵字 還不夠,我們還需要了解5大元注解

  • @Retention
  • @Target
  • @Documented
  • @Inherited(JDK8 引入)
  • @Repeatable(JDK8 引入)

 1)  @Retention 指定注解的生命周期    

@Retention(RetentionPolicy.SOURCE)

其中Retention是一個(gè)枚舉類:

  • RetentionPolicy.SOURCE : 注解只保留在源文件,當(dāng)Java文件編譯成class文件的時(shí)候,注解被遺棄(.java文件)
  • RetentionPolicy.CLASS :注解被保留到class文件,但jvm加載class文件時(shí)候被遺棄,這是默認(rèn)的生命周期(.class文件)
  • RetentionPolicy.RUNTIME: 注解不僅被保存到class文件中,jvm加載class文件之后,仍然存在(內(nèi)存中的字節(jié)碼)

2) @Target指定注解可以修飾的元素類型

@Target(ElementType.Field)
  • ElementType.ANNOTATION_TYPE - 標(biāo)記的注解可以應(yīng)用于注解類型。
  • ElementType.CONSTRUCTOR - 標(biāo)記的注解可以應(yīng)用于構(gòu)造函數(shù)。
  • ElementType.FIELD - 標(biāo)記的注解可以應(yīng)用于字段或?qū)傩浴?/li>
  • ElementType.LOCAL_VARIABLE - 標(biāo)記的注解可以應(yīng)用于局部變量。
  • ElementType.METHOD - 標(biāo)記的注解可以應(yīng)用于方法。
  • ElementType.PACKAGE - 標(biāo)記的注解可以應(yīng)用于包聲明。
  • ElementType.PARAMETER - 標(biāo)記的注解可以應(yīng)用于方法的參數(shù)。
  • ElementType.TYPE - 標(biāo)記的注解可以應(yīng)用于類的任何元素。

 3)@Documented指定注解會(huì)被JavaDoc工具提取成文檔。默認(rèn)情況下,JavaDoc是不包括文檔的

 4)@Inherited表示該注解會(huì)被子類繼承,注意,僅針對(duì)類,成員屬性、方法并不受此注釋的影響。

 5)@Repeatable表示注解可以重復(fù)使用,為了解決同一個(gè)注解不能重復(fù)在同一類/方法/屬性上使用的問題。

其中最常用的就是 @Retention 跟 @Target。

三、簡(jiǎn)單實(shí)現(xiàn)

例如實(shí)現(xiàn)一個(gè)簡(jiǎn)單,在標(biāo)記注解的地方打印一句日志。

定義一個(gè) MyAnnotation 注解,并且定義一個(gè)屬性 message 默認(rèn)值是 ”aaa“。先將該注解加到字段上,看能不能獲取到。

//注解用于字段上
@Target(ElementType.FIELD)
//運(yùn)行時(shí)使用
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String message() default  "aaa";
}

定義一個(gè)Student類用于測(cè)試: 

@Data
public class Student {
    @JSONField(ordinal =0)
    @MyAnnotation(message = "AAAAAAAAA")
    public String name;
    @MyAnnotation(message = "AAAAAAAAA")
    public Integer score;
}

在字段上標(biāo)注該注解,然后編寫一個(gè)main方法獲取該注解的屬性:

    public static void main(String[] args) {
        Class<?> studentClass = Student.class;
        Field[] fields = studentClass.getDeclaredFields();//獲取所有的類成員變量字段
        for (Field field : fields) {
            String fieldName = field.getName(); //獲取該類成員變量的名字
            System.out.println("成員變量名是:" + fieldName);
            Annotation[] annotations = field.getAnnotations(); //獲取該類成員變量上所有聲明周期是運(yùn)行時(shí)的注解
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> annotationType = annotation.annotationType();
                String annotationName = annotationType.getSimpleName();//注解的簡(jiǎn)短名稱
                System.out.println(" 使用的注解是:" + annotationName);
                //判斷該注解是不是 MyAnnotation 注解,是的話打印其 id 和 describe 屬性
                if (annotationType.equals(MyAnnotation.class)) {
                    MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
                    String message = myAnnotation.message();
                    System.out.println("    MyAnnotation注解中的message是:" + message);

                }
            }
            System.out.println();
        }
    }

 執(zhí)行后打印的內(nèi)容:

以上就是一個(gè)注解的簡(jiǎn)單實(shí)現(xiàn)。

四、使用切面執(zhí)行自定義注解邏輯

在開發(fā)中一般加上注解之后會(huì)自動(dòng)執(zhí)行一些邏輯,大部分實(shí)現(xiàn)的原理是使用切面來實(shí)現(xiàn)注解的邏輯的。

1) 首先將剛才的注解修改成放在方法上的:

//注解用于方法
@Target(ElementType.METHOD)
//運(yùn)行時(shí)使用
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String message() default  "aaa";

}

2) 定義一個(gè)切面類:

@Component
@Aspect
@Slf4j
public class MyAnnotationAspect {
    /*
     * 這是一個(gè)切入點(diǎn)
     * */
    @Pointcut("@annotation(com.demo.aaa.annotation.MyAnnotation)")
    public void cutMethod(){
    }
    /**
     * 切點(diǎn)之前
     */
    @Before("cutMethod()")
    public void before(JoinPoint joinPoint) throws Throwable {
        log.info("============ before ==========");
    }
    /**
     * 切點(diǎn)之后
     */
    @After("cutMethod()")
    public void after() throws Throwable {
        log.info("============ after ==========");
    }
    /**
     * 切點(diǎn)返回內(nèi)容后
     */
    @AfterReturning("cutMethod()")
    public void afterReturning() throws Throwable {
        log.info("============ afterReturning ==========");
    }
    /**
     * 切點(diǎn)拋出異常后
     */
    @AfterThrowing("cutMethod()")
    public void afterThrowing() throws Throwable {
        log.info("============ afterThrowing ==========");
    }
    @Around("cutMethod() && @annotation(myAnnotation)")
    public Object around(ProceedingJoinPoint point, MyAnnotation myAnnotation) throws Throwable {
        log.info("============ around1 ==========");
        Object  obj= point.proceed(point.getArgs());
        log.info("============ around2 ==========");
        return obj;
    }
}

在使用aop之前需要先引入一個(gè)依賴: 

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>

   簡(jiǎn)單說一下各個(gè)注解代表什么含義:

  • @Aspect:作用是把當(dāng)前類標(biāo)識(shí)為一個(gè)切面供容器讀取 ,也就是加上這個(gè)注解,spring才知道你這是一個(gè)切面類,用于處理切點(diǎn)的邏輯的。
  • @Pointcut:切入點(diǎn),@Pointcut切點(diǎn)表達(dá)式非常豐富,可以將 方法(method)、類(class)、接口(interface)、包(package) 等作為切入點(diǎn),非常靈活,常用的有@annotation、@within、execution等方式,上面的示例使用的是@annotation方式,意思就是說被Spring掃描到方法上帶有@annotation中的注解 就會(huì)執(zhí)行切面通知。
  • @Before:該注解標(biāo)注的方法在業(yè)務(wù)模塊代碼執(zhí)行之前執(zhí)行,其不能阻止業(yè)務(wù)模塊的執(zhí)行,除非拋出異常;
  • @AfterReturning:該注解標(biāo)注的方法在業(yè)務(wù)模塊代碼執(zhí)行之后執(zhí)行;
  • @AfterThrowing:該注解標(biāo)注的方法在業(yè)務(wù)模塊拋出指定異常后執(zhí)行;
  • @After:該注解標(biāo)注的方法在所有的 Advice 執(zhí)行完成后執(zhí)行,無(wú)論業(yè)務(wù)模塊是否拋出異常,類似于 finally 的作用;
  • @Around:該注解功能最為強(qiáng)大,其所標(biāo)注的方法用于編寫包裹業(yè)務(wù)模塊執(zhí)行的代碼,通知的第一個(gè)參數(shù)必須是 ProceedingJoinPoint 類型。在通知體內(nèi),調(diào)用 ProceedingJoinPoint 的 proceed () 方法使得連接點(diǎn)方法執(zhí)行如果不調(diào)用 proceed () 方法,連接點(diǎn)方法則不會(huì)執(zhí)行。無(wú)論是調(diào)用前邏輯還是調(diào)用后邏輯,都可以在該方法中編寫,甚至其可以根據(jù)一定的條件而阻斷業(yè)務(wù)模塊的調(diào)用;      如果切面中使用了@Around 注解,如果不調(diào)用 ProceedingJoinPoint 的 proceed () 方法的話,那么 @Before  和 @After 直接標(biāo)注的方法也不會(huì)被觸發(fā)。@Around 注解標(biāo)注的方法,在 ProceedingJoinPoint 的 proceed () 方法 前的邏輯是比@Before的邏輯還要靠前, 在proceed () 方法之后的邏輯比 @After 的邏輯還要靠后。
  • Joint Point:JointPoint是程序運(yùn)行過程中可識(shí)別的點(diǎn),這個(gè)點(diǎn)可以用來作為AOP切入點(diǎn)。JointPoint對(duì)象則包含了和切入相關(guān)的很多信息。比如切入點(diǎn)的對(duì)象,方法,屬性等。我們可以通過反射的方式獲取這些點(diǎn)的狀態(tài)和信息,用于追蹤tracing和記錄logging應(yīng)用信息。

 3)將注解放入到接口方法中測(cè)試:

    @GetMapping("/aaa")
    @MyAnnotation(message = "成功拉?。。。。。。。。。。?!")
    public void test() {
        System.out.println("執(zhí)行代碼邏輯");
    }

   調(diào)用接口之后打印

上面就是自定義注解最簡(jiǎn)單的示例。

五、切點(diǎn)表達(dá)式

我們定義切點(diǎn)除了使用 @Pointcut() 之外,我們還有豐富的切點(diǎn)表達(dá)式可以定義切點(diǎn)。

1)切點(diǎn)表達(dá)式簡(jiǎn)介      

2)通配符合與邏輯運(yùn)算符

 @AspectJ 支持三種通配符:

邏輯運(yùn)算符: 切點(diǎn)表達(dá)式由切點(diǎn)函數(shù)組成,切點(diǎn)函數(shù)之間還可以進(jìn)行邏輯運(yùn)算,組成復(fù)合切點(diǎn)。

3)切點(diǎn)表達(dá)式:

1.arg() :匹配切入點(diǎn)方法的參數(shù)類型,匹配的上才是切點(diǎn)。

語(yǔ)法:args(param-pattern)   param-pattern:參數(shù)類型的全路徑。

注意:要先匹配到某些類,不然會(huì)報(bào)錯(cuò),也就是不能單獨(dú)用

 示例:

@Pointcut("args(java.lang.String)")  //這樣就是錯(cuò)的,不能單獨(dú)使用要匹配到某些類

@Pointcut("within(com.example.demo.service.impl.UserServiceImpl) && args(java.lang.String,java.lang.String)") //要像這樣使用 within 先匹配到某個(gè)具體的類,在使用args匹配到某個(gè)類型參數(shù)的方法

2.@args:匹配切入點(diǎn)方法上的參數(shù)的類上,參數(shù)的類必須要有指定的注解

語(yǔ)法:@args(annotation-type)   annotation-type:注解類型的全路徑

注意:也不能單獨(dú)使用,必須先指定到類,而且匹配參數(shù)個(gè)數(shù)至少有一個(gè)且為第一個(gè)參數(shù)的類含有該注解才能匹配的上

示例:

@Pointcut("within(com.demo.RedisTest) &amp;&amp; @args(com.demo.aaa.annotation.MyAnnotation)")

3.within:匹配切入點(diǎn)的指定類的任意方法,不能匹配接口。

語(yǔ)法:within(declaring-type)   參數(shù)為全路徑的類名(可使用通配符),表示匹配當(dāng)前表達(dá)式的所有類都將被當(dāng)前方法環(huán)繞

注意: 這個(gè)是指定到具體的類

示例:

//within表達(dá)式的粒度為類,其參數(shù)為全路徑的類名(可使用通配符),表示匹配當(dāng)前表達(dá)式的所有類都將被當(dāng)前方法環(huán)繞。如下是within表達(dá)式的語(yǔ)法:
@Pointcut(within(declaring-type-pattern))

//within表達(dá)式只能指定到類級(jí)別,如下示例表示匹配com.spring.service.BusinessObject中的所有方法:
@Pointcut(within(com.spring.service.BusinessObject))
      
//within表達(dá)式路徑和類名都可以使用通配符進(jìn)行匹配,比如如下表達(dá)式將匹配com.spring.service包下的所有類,不包括子包中的類:
@Pointcut(within(com.spring.service.*))

//如下表達(dá)式表示匹配com.spring.service包及子包下的所有類:
@Pointcut(within(com.spring.service..*))

4.@within:表示匹配帶有指定注解的類。

語(yǔ)法:@within(annotation-type)   注解的全類名

注意:這個(gè)是指定到帶有某個(gè)注解的類

示例:

//如下所示示例表示匹配使用com.spring.annotation.BusinessAspect注解標(biāo)注的類:
@within(com.spring.annotation.BusinessAspect)

5.@annotation() :匹配帶有指定注解的連接點(diǎn)

語(yǔ)法:@annotation(annotation-type)  annotation-type:注解類型的全路徑

示例:

@Pointcut("@annotation(com.test.annotations.LogAuto)")

6.execution() 用于匹配是連接點(diǎn)的執(zhí)行方法,Spring 切面粒度最小是達(dá)到方法級(jí)別,而 execution 表達(dá)式可以用于明確指定方法返回類型,類名,方法名和參數(shù)名等與方法相關(guān)的配置,所以是使用最廣泛的。

用法:

  • modifiers-pattern:方法的可見性修飾符,如 public,protected,private;
  • ret-type-pattern:方法的返回值類型,如 int,void 等;
  • declaring-type-pattern:方法所在類的全路徑名,如 com.spring.Aspect;
  • name-pattern:方法名,如 getOrderDetail();
  • param-pattern:方法的參數(shù)類型,如 java.lang.String;
  • throws-pattern:方法拋出的異常類型,如 java.lang.Exception;

示例:

modifiers-pattern:方法的可見性修飾符,如 public,protected,private;
ret-type-pattern:方法的返回值類型,如 int,void 等;
declaring-type-pattern:方法所在類的全路徑名,如 com.spring.Aspect;
name-pattern:方法名,如 getOrderDetail();
param-pattern:方法的參數(shù)類型,如 java.lang.String;
throws-pattern:方法拋出的異常類型,如 java.lang.Exception;
示例:

// 匹配目標(biāo)類的所有 public 方法,第一個(gè) * 代表返回類型,第二個(gè) * 代表方法名,..代表方法的參數(shù)
execution(public * *(..))

// 匹配目標(biāo)類所有以 User 為后綴的方法。第一個(gè) * 代表返回類型,*User 代表以 User 為后綴的方法
execution(* *User(..))

// 匹配 User 類里的所有方法
execution(* com.test.demo.User.*(..))

// 匹配 User 類及其子類的所有方法
execution(* com.test.demo.User+.*(..)) :

// 匹配 com.test 包下的所有類的所有方法
execution(* com.test.*.*(..))

// 匹配 com.test 包下及其子孫包下所有類的所有方法
execution(* com.test..*.*(..)) :

// 匹配 getOrderDetail 方法,且第一個(gè)參數(shù)類型是 Long,第二個(gè)參數(shù)類型是 String
execution(* getOrderDetail(Long, String))

六、切面中獲取各個(gè)參數(shù)

示例:

   @Around(value = "@annotation(basisLogAnnotation)")
    public Object demoAop(ProceedingJoinPoint proceedingJoinPoint, final BasisLogAnnotation basisLogAnnotation) throws Throwable {
 
        logger.debug("執(zhí)行前:");
 
        Object object = proceedingJoinPoint.proceed();  //執(zhí)行連接點(diǎn)方法,object:方法返回值
 
        logger.debug("執(zhí)行后:");
 
 
        // 類名
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        //方法名
        String methodName = proceedingJoinPoint.getSignature().getName();
        //參數(shù)(我這里是對(duì)象,具體根據(jù)個(gè)人的參數(shù)類型來強(qiáng)轉(zhuǎn))
        BasisUser basisUser = (BasisUser)proceedingJoinPoint.getArgs()[0];
        return object;
    }

總結(jié)  

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

相關(guān)文章

  • java實(shí)現(xiàn)獲取網(wǎng)站的keywords,description

    java實(shí)現(xiàn)獲取網(wǎng)站的keywords,description

    這篇文章主要介紹了java實(shí)現(xiàn)獲取網(wǎng)站的keywords,description的相關(guān)資料,需要的朋友可以參考下
    2015-03-03
  • SpringBoot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)

    SpringBoot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)

    這篇文章主要為大家詳細(xì)介紹了SpringBoot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • 怎么用idea創(chuàng)建一個(gè)SpringBoot項(xiàng)目

    怎么用idea創(chuàng)建一個(gè)SpringBoot項(xiàng)目

    本文介紹了在IDEA中創(chuàng)建Spring Boot項(xiàng)目的步驟,包括環(huán)境準(zhǔn)備(JDK 1.8+、Maven 3.2.5+)、使用Spring Initializr生成項(xiàng)目結(jié)構(gòu)、配置啟動(dòng)端口、創(chuàng)建控制器及測(cè)試方法,強(qiáng)調(diào)依賴管理與注解處理,感興趣的朋友一起看看吧
    2025-06-06
  • 解決mybatis generator MySQL自增ID出現(xiàn)重復(fù)問題MySQLIntegrityConstraintViolationException

    解決mybatis generator MySQL自增ID出現(xiàn)重復(fù)問題MySQLIntegrityC

    在MySQL中使用MyBatis時(shí),可能會(huì)遇到由于主鍵重復(fù)導(dǎo)致的插入失敗問題,此問題通常發(fā)生在連續(xù)插入多條數(shù)據(jù)時(shí),如果selectKey的order配置錯(cuò)誤,如使用BEFORE而不是AFTER,將會(huì)導(dǎo)致獲取的ID未更新,引起主鍵重復(fù)錯(cuò)誤,正確的配置應(yīng)使用AFTER
    2024-10-10
  • 強(qiáng)烈推薦IDEA提高開發(fā)效率的必備插件

    強(qiáng)烈推薦IDEA提高開發(fā)效率的必備插件

    這篇文章主要介紹了強(qiáng)烈推薦IDEA提高開發(fā)效率的必備插件,文中有非常詳細(xì)的圖文示例,對(duì)想要提高企業(yè)開發(fā)效率的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • Mybatis實(shí)體類屬性與數(shù)據(jù)庫(kù)不一致解決方案

    Mybatis實(shí)體類屬性與數(shù)據(jù)庫(kù)不一致解決方案

    這篇文章主要介紹了Mybatis實(shí)體類屬性與數(shù)據(jù)庫(kù)不一致解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • JDK安裝方法和Linux常見設(shè)置詳細(xì)版教程

    JDK安裝方法和Linux常見設(shè)置詳細(xì)版教程

    這篇文章主要給大家介紹了關(guān)于JDK安裝方法和Linux常見設(shè)置的相關(guān)資料,文章詳細(xì)介紹了如何在Linux系統(tǒng)中設(shè)置靜態(tài)IP、用戶名和主機(jī)名,配置防火墻,安裝JDK以及如何創(chuàng)建系統(tǒng)快照,需要的朋友可以參考下
    2024-11-11
  • Java匿名對(duì)象與匿名內(nèi)部類

    Java匿名對(duì)象與匿名內(nèi)部類

    本篇文章給大家詳細(xì)講解了Java匿名對(duì)象與匿名內(nèi)部類的相關(guān)知識(shí)點(diǎn),有興趣的讀者一起學(xué)習(xí)下。
    2018-03-03
  • Java使用wait/notify實(shí)現(xiàn)線程間通信上篇

    Java使用wait/notify實(shí)現(xiàn)線程間通信上篇

    wait()和notify()是直接隸屬于Object類,也就是說所有對(duì)象都擁有這一對(duì)方法,下面這篇文章主要給大家介紹了關(guān)于使用wait/notify實(shí)現(xiàn)線程間通信的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • Java編程接口調(diào)用的作用及代碼分享

    Java編程接口調(diào)用的作用及代碼分享

    這篇文章主要介紹了Java編程接口調(diào)用的作用及代碼分享,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11

最新評(píng)論

泉州市| 浮山县| 茌平县| 永寿县| 汉川市| 香港 | 隆安县| 泗阳县| 荆门市| 贞丰县| 山东省| 连云港市| 奉新县| 土默特左旗| 嘉荫县| 阿克苏市| 和田市| 邓州市| 尼勒克县| 安乡县| 江川县| 明星| 潮州市| 富阳市| 衡南县| 察哈| 珠海市| 启东市| 连平县| 崇文区| 宁远县| 仁怀市| 清涧县| 和龙市| 福州市| 图们市| 灵丘县| 曲靖市| 汾西县| 玛曲县| 桑日县|