JAVA 笔记 11 注解

简介

注解(元数据)是一种描述数据的数据,用于对代码(包、类、接口、字段、方法参数、局部变量等)进行说明。从Jdk 1.5 版本引入。

注解的属性

注解中只有属性(成员变量),没有方法,变量名就是使用注解括号中对应的参数名,变量返回值注解括号中对应参数类型。

@Repeatable注解中的变量则类型则是对应Annotation(接口)的泛型Class。

/**注解Repeatable源码*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    /**
     * Indicates the <em>containing annotation type</em> for the
     * repeatable annotation type.
     * @return the containing annotation type
     */
    Class<? extends Annotation> value();
} 

注解用途

  • 生成文档,通过@Documented生成 javadoc 文档;
  • 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证(如:@Autowired);
  • 编译时动态处理,编译时通过代码里标识的元数据动态处理(如:动态生成代码);
  • 运行时动态处理,运行时通过代码里标识的元数据动态处理(如:使用反射注入实例)。

使用

注解属性赋值

    @Documented
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface MyTestAnnotation {
        String name() default "mao";
        int age() default 18;
    }
    
    @MyTestAnnotation(name = "father", age = 50)
    public class Father {
    }

获取注解属性

可以通过反射获取注解属性。

    /**是否存在对应 Annotation 对象*/
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return GenericDeclaration.super.isAnnotationPresent(annotationClass);
    }
    
    /**获取 Annotation 对象*/
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
        Objects.requireNonNull(annotationClass);
        return (A) annotationData().annotations.get(annotationClass);
    }
    
    /**获取所有 Annotation 对象数组*/   
    public Annotation[] getAnnotations() {
        return AnnotationParser.toArray(annotationData().annotations);
    }
    
    /**获取类注解属性*/
    Class<Father> fatherClass = Father.class;
    boolean annotationPresent = fatherClass.isAnnotationPresent(MyTestAnnotation.class);
    if(annotationPresent){
        MyTestAnnotation annotation = fatherClass.getAnnotation(MyTestAnnotation.class);
        System.out.println(annotation.name());
        System.out.println(annotation.age());
    }
    
    /**获取方法注解属性*/
    try {
        Field age = fatherClass.getDeclaredField("age");
        boolean annotationPresent1 = age.isAnnotationPresent(Age.class);
        if(annotationPresent1){
            Age annotation = age.getAnnotation(Age.class);
            System.out.println(annotation.value());
        }
    
        Method play = PlayGame.class.getDeclaredMethod("play");
        if (play!=null){
            People annotation2 = play.getAnnotation(People.class);
            Game[] value = annotation2.value();
            for (Game game : value) {
                System.out.println(game.value());
            }
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }

注解的本质

注解就是一个由@interface修饰的类,编译后会自动继承java.lang.annotation.Annotation接口,定义方法就相当于注解属性(成员变量)。

/**Annotation接口源码*/
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    Class<? extends Annotation> annotationType();
} 

注意:注解不支持继承,不能使用关键字extends来继承某个@interface

注解分类

一、预置注解,使用这些注解后编译器就会进行检查;

  • @Deprecated 过时/废弃
  • @Override 重写
  • @SuppressWarnings 忽略警告
  • @SafeVarargs 参数安全类型(Java 1.7)
  • @FunctionalInterface 函数式接口( Java 1.8 )

二、元注解,用于定义注解的注解

@Documented 文档

将注解中的元素包含到 Javadoc 中。

@Retention 保留期

  • RetentionPolicy.SOURCE:注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS:注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。如@Override、@Deprecated、@SuppressWarnning等
  • RetentionPolicy.RUNTIME:注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。如SpringMvc中的@Controller、@Autowired、@RequestMapping等。

@Target 目标(限定运用场景)

  • ElementType.ANNOTATION_TYPE:可以给一个注解进行注解
  • ElementType.CONSTRUCTOR:可以给构造方法进行注解
  • ElementType.FIELD:可以给属性进行注解
  • ElementType.LOCAL_VARIABLE:可以给局部变量进行注解
  • ElementType.METHOD:可以给方法进行注解
  • ElementType.PACKAGE:可以给一个包进行注解
  • ElementType.PARAMETER:可以给一个方法内的参数进行注解
  • ElementType.TYPE:可以给一个类型进行注解,比如类、接口、枚举

@Inherited 继承

如果一个类(非接口、非方法)用上了@Inherited修饰的注解,那么其子类也会继承这个注解。

@Repeatable 重复(Java 1.8)

在需要对同一种注解多次使用时,往往需要借助@Repeatable。

三、自定义注解,可以根据自己的需求定义注解

注解通常配合反射或者切面一起使用来实现相应的业务逻辑。

定义一个系统日志注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {

    /**
     * 操作说明
     */
    String value() default "";

}

找到使用了注解的方法,利用切面进行日志记录。

这里有些类或者参数只做演示,没有给出具体的实现(如SysLogMapper、SysLogEntity等),以看懂注解配合切面使用为目的。

@Aspect
@Component
public class SysLogAspect {

    @Autowired
    private SysLogMapper sysLogMapper;

    @Pointcut("@annotation(com.jourwon.annotation.SysLog)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //执行方法
        Object result = point.proceed();
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;

        //保存日志
        saveSysLog(point, time);

        return result;
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SysLogEntity sysLog = new SysLogEntity();
        SysLog syslog = method.getAnnotation(SysLog.class);
        if (syslog != null) {
            //注解上的描述
            sysLog.setOperation(syslog.value());
        }

        //保存系统日志
        sysLogMapper.insertSelective(sysLog);
    }

}

在方法中使用注解

@SysLog("保存用户")
@PostMapping("/save")
public Result save(@RequestBody SysUserEntity user) {
    sysUserService.save(user);

    return Result.ok();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值