自定义注解详细介绍

目录

1.注解介绍

2.怎样自定义注解

2.1 注解基本语法

2.2 常用的元注解

2.2.1 @Target

2.2.2 @Retention

2.2.3 @Documented

2.2.4 @Inherited

 3.自定义注解的使用

3.1定义注解

3.2 使用注解

3.3注解解析器 

 4.反射操作获取注解 


1.注解介绍

  1. 注解是一种元数据形式,即注解是属于java的一种数据类型,和类、接口、数组、枚举类似。
  2. 注解用来修饰,类、方法、变量、参数、包。
  3. 注解不会对所修饰的代码产生直接的影响。

2.怎样自定义注解

  • 定义注解
  • 使用注解(将注解打在需要的代码上)
  • 解析注解(检测到标记并进行特殊操作)

2.1 注解基本语法

注解类型声明

注解在Java中,与类、接口、枚举类似,因此其声明语法基本一致,只是所使用的关键字有所不同@interface在底层实现上,所有定义的注解都会自动继承java.lang.annotation.Annotation接口

public @interface MyLog {
  String value() default "";    
}

注解元素声明

  • 访问修饰符必须为public,不写默认为public;
  • 该元素的类型只能是基本数据类型、String、Class、枚举类型;
  • 该元素的名称一般定义为名词,如果注解中只有一个元素,请把名字起为value(后面使用会带来便利操作);
  • ()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法;
  • default代表默认值,值必须和第2点定义的类型一致;
  • 如果没有默认值,代表后续使用注解时必须给该类型元素赋值。

2.2 常用的元注解

一个最基本的注解定义就只包括了上面的两部分内容:1、注解的名字;2、注解包含的类型元素。但是我们在使用注解的时候发现,有些注解只能写在方法上面;有些却可以写在类的上面 等等....那么这些是如何做的呢?

2.2.1 @Target

@Target注解,是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的。

public enum ElementType {
    /** 类,接口(包括注解类型)或枚举的声明 */
    TYPE,

    /** 属性的声明 */
    FIELD,

    /** 方法的声明 */
    METHOD,

    /** 方法形式参数声明 */
    PARAMETER,

    /** 构造方法的声明 */
    CONSTRUCTOR,

    /** 局部变量声明 */
    LOCAL_VARIABLE,

    /** 注解类型声明 */
    ANNOTATION_TYPE,

    /** 包的声明 */
    PACKAGE
}
package com.wyy.Annotation;

import java.lang.annotation.*;

@Inherited
//当前注解只能放在方法以及类上
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog {
    String value() default "";
}

2.2.2 @Retention

@Retention注解,定义注解的保留策略。

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * (注解将被编译器忽略掉)
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * (注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为)
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     * (注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到)
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

当注解被定义为RetentionPolicy.SOURCE,那么此注解只会出现Java源文件中,这个注解即不会参与编译也不会在运行时起任何作用。

当注解被定义为RetentionPolicy.CLASS,那么此注解将会被编译到class文件中,在运行期间同样不起任何作用。

当注解被定义为RetentionPolicy.RUNTIME,那么此注解可以在运行期间被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解及注解中的属性。

2.2.3 @Documented

@Documented注解,指定被修饰的该Annotation可以被javadoc工具提取成文档。

2.2.4 @Inherited

@Inherited注解,指定被修饰的Annotation将具有继承性 。

 3.自定义注解的使用

3.1定义注解

package com.wyy.Annotation;

import java.lang.annotation.*;

@Inherited
//当前注解只能放在方法以及类上
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog {
    String value() default "";
}

3.2 使用注解


    @MyLog
    @RequestMapping("/hello")
    public String hello(){

        return "hello";
    }

3.3注解解析器 

这里以给方法添加日志为例

package com.wyy.Aspect;

import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Log4j2
public class MyLogAnnotation {

    
    @Pointcut("@annotation(com.wyy.Annotation.MyLog)")
    public void Mylog() {
    }

    /**
     * @param proceedingJoinPoint
     */
    @Around("Mylog()")
    public Object Mylogs(ProceedingJoinPoint proceedingJoinPoint) {
        //当前方法
        Signature methodName = proceedingJoinPoint.getSignature();
        //日志输出
        log.info(methodName + "方法开始执行");
        Object proceed = null;
        try {
            //执行方法
            proceed = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //日志输出
        log.info(methodName + "方法执行结束");
        return proceed;

    }

}

当执行hello方法时 

 4.反射操作获取注解 

public static void main(String[] args) {
        Annotation[] annotations = HelloController.class.getAnnotations();
        Arrays.asList(annotations).stream().forEach(System.out::println);

        try {
            Method hello = HelloController.class.getMethod("hello");
            if( hello.isAnnotationPresent(MyLog.class)){
                System.out.println("hello方法上配置MyLog注解");
                MyLog annotation = hello.getAnnotation(MyLog.class);
                String value = annotation.value();
                System.out.println("MyLog注解value参数的值:"+value);
            }else{
                System.out.println("hello方法上没有配置MyLog注解");
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
  • isAnnotationPresent(Class<? extends Annotation> annotationClass)方法是专门判断该元素上是否配置有某个指定的注解。
  • getAnnotation(Class<A> annotationClass)方法是获取该元素上指定的注解。
  • 反射对象上还有一个方法getAnnotations(),该方法可以获得该对象身上配置的所有的注解。
     

运行结果:

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值