<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          快來(lái)自定義一個(gè)屬于你自己的java注解吧

          共 14038字,需瀏覽 29分鐘

           ·

          2021-05-21 21:45

          大家好,我是公眾號(hào):【java小杰要加油】,最近在項(xiàng)目中,發(fā)現(xiàn)了很多地方都用到了自定義注解, 根據(jù)自定義的注解,再去做一些個(gè)性化的操作,非常方便,今天來(lái)分享給大家

          • 話不多說,直接開車

          注解大致介紹

          首先,讓我們來(lái)聲明一個(gè)注解


          // 注解可以作用在哪里
          @Target({ElementType.TYPE})
          //  該注解的生命周期
          @Retention(RetentionPolicy.RUNTIME)
          // 指示默認(rèn)情況下,帶有類型的注釋將由javadoc *和類似工具來(lái)記錄
          @Documented
          // 可以繼承父類注解
          @Inherited   
          // bean
          @Component
          public @interface DIYClassAnnotation {
              DIYEnum diyEnum();
              // 年齡默認(rèn)24 歲
              int age() default 24;

          }

          可以注意到,我們聲明的這個(gè)注解,他自己又帶著很多元注解,我們依此來(lái)解釋下,對(duì)應(yīng)可取的值也如下

          • @Target : 指此注解可以標(biāo)注在哪些地方,是字段?還是類?還是方法?
            • TYPE :類,接口(包括注釋類型)或枚舉聲明
            • FIELD:字段聲明(包括枚舉常量)
            • METHOD:方法聲明
            • PARAMETER:形式參數(shù)聲明
            • CONSTRUCTOR:構(gòu)造函數(shù)聲明
            • LOCAL_VARIABLE:局部變量聲明
            • ANNOTATION_TYPE:注釋類型聲明
            • PACKAGE:包聲明
            • TYPE_PARAMETER:類型參數(shù)聲明
            • TYPE_USE:使用類型
          • @Retention :指該注解的生命周期,存活在哪個(gè)階段
            • SOURCE:批注將被編譯器丟棄
            • CLASS:注釋將由編譯器記錄在類文件中,但不必在運(yùn)行時(shí)由VM保留。這是默認(rèn)的行為。
            • RUNTIME:注釋將由編譯器記錄在類文件中,并在運(yùn)行時(shí)由VM保存*,因此可以通過反射方式讀取它們
          • @Documented :指是默認(rèn)情況下,帶有類型的注釋將由javadoc *和類似工具來(lái)記錄
          • @Inherited :可以繼承父類注解
          • 里面的值只能用基本類型boolean、int、double、float、long、byte、short、charString、Enum、Class以及一些其他注解

          我們一般寫注解的時(shí)候。就是用圖中上面那幾個(gè)加粗顏色的屬性和值

          實(shí)戰(zhàn)演練

          • 其實(shí)使用這個(gè)自定義注解,千言萬(wàn)語(yǔ)就一句話
          1. 聲明一個(gè)自定義的注解
          2. 通過反射等方式取出這個(gè)注解,再根據(jù)這個(gè)注解中自己設(shè)定的值去做一些定制化的操作
          • 本文將演示三種類型的自定義注解怎么用,平常開發(fā)也就這三種了(我接觸的)

          一、自定義類注解

          @Target({ElementType.TYPE})
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          @Inherited
          @Component
          public @interface DIYClassAnnotation {
              // 自定義枚舉類型
              DIYEnum diyEnum();
              // 年齡默認(rèn)24 歲
              int age() default 24;
          }

          看一下這個(gè)枚舉類型


          public enum DIYEnum {
              xiaoJie("小杰","打代碼"),
              TEACHER("老師","教書"),
              CHEF("廚師","做飯");

              private String name;
              private String worker;

              DIYEnum(String name,String worker) {
                  this.name = name;
                  this.worker = worker;
              }

              public String getWorker() {
                  return worker;
              }

              public void setWorker(String worker) {
                  this.worker = worker;
              }

              public String getName() {
                  return name;
              }

              public void setName(String name) {
                  this.name = name;
              }


          }

          二、自定義字段注解


          // 注解到什么地方  屬性 上
          @Target({ElementType.FIELD})
          //  該注解的生命周期
          @Retention(RetentionPolicy.RUNTIME)
          // 指示默認(rèn)情況下,帶有類型的注釋將由javadoc *和類似工具來(lái)記錄
          @Documented
          // 可以繼承父類注解
          @Inherited
          // bean
          @Component
          public @interface DIYFieldAnnotation {
              // 性別
              String sex();

          }

          三、自定義方法注解


          // 注解到什么地方  方法 上
          @Target({ElementType.METHOD})
          //  該注解的生命周期
          @Retention(RetentionPolicy.RUNTIME)
          // 指示默認(rèn)情況下,帶有類型的注釋將由javadoc *和類似工具來(lái)記錄
          @Documented
          // 可以繼承父類注解
          @Inherited
          // bean
          @Component
          public @interface DIYMethodAnnotation {
              // 是否校驗(yàn)
              int verification();

              // 接口名稱
              String interfaceName();
          }

          • 其實(shí)我們注意到,感覺大家都大差不差啊,是的沒錯(cuò),也就是target作用域不一樣罷了

          我們自定義注解定義完了,下面要開始真正使用啦

          • 定義個(gè)抽象父類Person
          // 抽象父類
          public abstract class Person {
            public  abstract void hobby();
          }

          • 定義學(xué)生Student子類
          @DIYClassAnnotation(diyEnum = DIYEnum.xiaoJie,age=23 )
          public class Student extends Person {

              @DIYFieldAnnotation(sex = "男")
              private String sex;

              @Override
              public void hobby() {
                  System.out.println(DIYEnum.xiaoJie.getWorker());
              }
          }
          • 定義老師Teacher子類
          @DIYClassAnnotation(diyEnum = DIYEnum.TEACHER,age=46 )
          public class Teacher extends Person {

              @DIYFieldAnnotation(sex = "女")
              private String sex;

              @Override
              public void hobby() {
                  System.out.println(DIYEnum.TEACHER.getWorker());
              }
          }
          • 定義廚師Chef子類
          @DIYClassAnnotation(diyEnum = DIYEnum.CHEF,age=50 )
          public class Chef extends Person {

              @DIYFieldAnnotation(sex = "男")
              private String sex;


              @Override
              public void hobby() {
                  System.out.println(DIYEnum.CHEF.getWorker());
              }
          }

          再來(lái)一個(gè)注解工具類



          public class DIYAnnotationUtils {
              public static Person getPerson(Person ...persons){

                  for (Person person:persons) {
                      // 判斷這個(gè)類是否有這個(gè)注解
                      if (person.getClass().isAnnotationPresent(DIYClassAnnotation.class)){
                          // 得到這個(gè)自定義的注解
                          DIYClassAnnotation workerAnnotation = person.getClass().getAnnotation(DIYClassAnnotation.class);
                          // 判斷這個(gè)自定義注解注解的值是否是我們想要的
                          if (DIYEnum.xiaoJie.getName().equals(workerAnnotation.diyEnum().getName())){
                              // 反射得到這個(gè)對(duì)象的屬性
                              Field[] fields = person.getClass().getDeclaredFields();
                              for (Field field:fields) {
                                  // 如果這個(gè)字段有這個(gè)注解
                                  if (field.isAnnotationPresent(DIYFieldAnnotation.class)){
                                      // 打印出這個(gè)屬性上有這個(gè)注解的值
                                      DIYFieldAnnotation annotation = field.getAnnotation(DIYFieldAnnotation.class);
                                      System.out.println(annotation.sex());
                                  }
                              }
                              return person;
                          }
                      }
                  }
                  return null;
              }
          }

          最主要的就是這個(gè)工具類(用到反射),其中根據(jù)傳進(jìn)來(lái)的對(duì)象判斷符合不符合我們的要求 (注解時(shí)的名字是不是小杰),如果符合的話,把注解在屬性上的注解拿出來(lái)

          • 我們通過測(cè)視類來(lái)調(diào)用一下

          public class Test {
              public static void main(String[] args) {
                  Student student =new Student();
                  Chef chef = new Chef() ;
                  Teacher teacher = new Teacher();
                  Person person = DIYAnnotationUtils.getPerson(student, chef, teacher);
                  if (person != null){
                      person.hobby();
                  }
              }
          }

          輸出結(jié)果是


          打代碼
          • 下面我們來(lái)演示下怎么在方法上使用這注解,最常見的組合就是自定義注解+AOP

          下面來(lái)看下controller


          @RestController
          public class Controller {
               // 此方法需要校驗(yàn)
               @DIYMethodAnnotation(verification = 1,interfaceName = "學(xué)生愛好接口")
               @RequestMapping("/verification")
               public   String   verificationMethod(String id){
                   new Student().hobby();
                   return "校驗(yàn)";
              }

              // 此方法不需要校驗(yàn)
              @DIYMethodAnnotation(verification = 0,interfaceName = "老師愛好接口")
              @RequestMapping("/noVerification")
              public   String   noVerificationMethod(String id){
                  new Teacher().hobby();

                  return "不校驗(yàn)";
              }

              // 此方法沒有注解
              @RequestMapping("/noAnnotation")
              public   String   noAnnotationMethod(String id){
                  new Chef().hobby();

                  return "無(wú)注解";
              }

          }

          再看下切面類 本文注重講解注解,這個(gè)切面類還有很多完善的地方不過不在本文范圍內(nèi)


          @Component
          @Aspect
          public class LogAspect {
              // 注解的位置
              @Pointcut("@annotation(com.example.demo.annotation.DIYMethodAnnotation)")
              public void diyPointCut(){};

              @Around("diyPointCut()")
              public Object diyAround(ProceedingJoinPoint joinPoint){
                  //獲得被增強(qiáng)的方法相關(guān)信息
                  MethodSignature signature = (MethodSignature)joinPoint.getSignature();
                  // 獲得這個(gè)方法
                  Method method = signature.getMethod();
                  // 獲得這個(gè)方法上面的注解
                  DIYMethodAnnotation diyMethodAnnotation = method.getAnnotation(DIYMethodAnnotation.class);
                  // 根據(jù)注解自定義的一些屬性去做自定義的操作
                  if (diyMethodAnnotation.verification() == 1){
                      System.out.println("當(dāng)前校驗(yàn)的是:"+diyMethodAnnotation.interfaceName());
                      System.out.println("方法名稱是:"+method.getName());
                      System.out.println("傳遞參數(shù)是:"+JSON.toJSONString(joinPoint.getArgs()));
                  }

                  System.out.println("aop 攔截器里 verification:"+diyMethodAnnotation.verification() );


                  try {
                      return joinPoint.proceed();
                  } catch (Throwable throwable) {
                      throwable.printStackTrace();
                      return null;
                  }
              }
          }

          我們將項(xiàng)目跑起來(lái),分別訪問兩個(gè)打了注解的接口

          • 需要校驗(yàn)的接口
          http://localhost:8081/verification?id=1

          當(dāng)前校驗(yàn)的是:學(xué)生愛好接口
          方法名稱是:verificationMethod
          傳遞參數(shù)是:["1"]
          aop 攔截器里 verification:1
          打代碼

          • 不需要校驗(yàn)的接口
          http://localhost:8081/noVerification?id=1

          aop 攔截器里 verification:0
          做飯
          • 沒有注解的接口
          http://localhost:8081/noAnnotation?id=1

          做飯

          由輸出結(jié)果可以得出一個(gè)結(jié)論,

          • 沒有注解的接口,走不到AOP,因?yàn)槲覀傾OP配置的是只有注解的接口才進(jìn)行AOP校驗(yàn),
          • 如果接口上有注解的話,又有兩種情況(這是我們自己設(shè)置的)
            • 輸出 ”當(dāng)前校驗(yàn)的是,方法名稱是,傳遞參數(shù)是
            • verification 0 的時(shí)候 這個(gè)注解也不進(jìn)行特別的操作
            • verification 1 的時(shí)候 這個(gè)注解進(jìn)行特別的操作

          綜上所述,我們?cè)谌粘i_發(fā)中,如果對(duì)某個(gè)類/字段/方法有什么特殊的要求的話可以使用自定義注解,再通過反射獲取到此注解,再根據(jù)這個(gè)注解中自定義的值在進(jìn)行我們自定義的操作

          好文推薦

          最后

          再貼一張最近火爆全網(wǎng)同時(shí)也對(duì)我觸動(dòng)很大的話

          • 自助者,天助之

          我是【java小杰要加油】,歡迎大家關(guān)注,有什么想說的想看的評(píng)論區(qū)里留言呀,我們下期見。


          瀏覽 58
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩视频专区 | wwwav91网站免费在线观看视频 懂色av无码任你操久久久久蜜桃av | 精品人妻无码 | 国产精品色婷婷7777777 | 学生妹一级片,黄色的学生妹一级片 |