java 注解和自定义注解详解

定义

注解是在JDK1.5之后引入的新特性位于​java.lang.annotation​,注解其实就是对代码进行一种特殊的标记,这些标记可以在编译,类加载和运行时被读取,并执行相应的处理。

第三方注解

在Java开发者,JDK自带了一些注解,在第三方框架Spring  带了大量的注解,这些注解称为第三方注解

1、Jdk通用注解

  1. @Override注解:编译检查,告诉编译器这个是个覆盖父类的方法。如果父类删除了该方法,则子类会报错。

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.SOURCE)

public @interface Override {

}

  1. @Deprecated 注解:编译检查,表示被注解的元素已被弃用

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD,

                ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE})

public @interface Deprecated {

}

上面两个注解除了都有一些元注解之外,没有任何的东西,但是我们加了这两个注解后,编译器就能够识别,可以将其理解为是一个标签,它并没有实际的逻辑处理,而实现逻辑的就是注解的用户。它本质就是一个 『标记式注解』,仅被编译器可知 ,这就是注解的工作原理。

注解的本质就是一个接口,该接口默认继承了java.lang.annotation.Annotation接口。

public interface Annotation {

        boolean equals(Object var1);

        int hashCode();

        String toString();

        Class<? extends Annotation> annotationType();

}

2、元注解

元注解用于注解其他注解的。Java 5.0定义了4个标准的元注解,如下:

  1. @Target
  1. @Retention
  1. @Documented
  1. @Inherited

2.1@Target

@Target注解用于声明注解的作用范围,例如作用范围为类、接口、方法等。源码:

package java.lang.annotation;

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.ANNOTATION_TYPE})

public @interface Target {

        ElementType[] value();

}

其中ElementType表明了该注解可以使用的位置:

public enum ElementType {

        TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE;

}

具体解释:

枚举 作用
ElementType.PACKAGE 注解用在包
ElementType.TYPE 注解作用于类型(类,接口,注解,枚举)
ElementType.ANNOTATION_TYPE 注解作用于注解
ElementType.CONSTRUCTOR 注解作用于构造方法
ElementType.METHOD 注解作用于方法
ElementType.PARAMETER 注解作用于方法参数
ElementType.FIELD 注解作用于属性
ElementType.LOCAL_VARIABLE 注解作用于局部变量

2.2@Retention

@Retention注解的作用就是指定注解的生命周期。比如在编译时可以处理运行时可以处理等。源码:

@Documented

@Retention(value = RetentionPolicy.RUNTIME)

@Target(value = {ElementType.ANNOTATION_TYPE})

public @interface Retention {

        public RetentionPolicy value();

}

它的枚举类为​RetentionPolicy​,只有三个可选值

枚举 作用
RetentionPolicy.SOURCE 源码中保留,编译期可以处理
RetentionPolicy.CLASS Class文件中保留,Class加载时可以处理
RetentionPolicy.RUNTIME 运行时保留,运行中可以处理

2.3@Documented

是一个标记注解,有该注解的注解会在生成 java 文档中保留

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.ANNOTATION_TYPE})

public @interface Documented {

}

2.4@Inherited

@Inherited 注解修饰的注解时具有可继承性的,就是说我们用 @Inherited 修饰了一个类,那么这个类的子类也会默认继承此注解。

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.ANNOTATION_TYPE})

public @interface Inherited {

}

自定义注解

在第三方注解没法满足我们业务要求的时候,需要我们自己写注解,这个时候就是自定义注解。

1.1、自定义注解语法

在注解中,需要使用四种元注解来声明注解的作用范围、生命周期、继承,是否生成文档等。另外在注解中也可以有自己的成员变量,如果一个注解没有成员变量则称为标记注解。

@Retention(RetentionPolicy.RUNTIME)

@Target({ ElementType.METHOD })

@Documented

public @interface CxmAction {

    String code() default "";// 权限码

String descrption() default "";// 描述

String prompt() default ""; // 权限提示

}

1.2、注解使用说明

1.2.1、AOP + 注解

使用AOP是一种常见的处理方式,首选,需要定义切面类

@Aspect

@Component

@Slf4j

@Order(-1)

public class CxmLogbackAspect {

/***

 * 定义controller切入点拦截规则,拦截SystemLog注解的业务方法

 */

@Pointcut("@annotation(com.cxm.common.annotation.SystemLog)")

public void logPointcut(){

}

/**

 * 环绕

 * @param proceedingJoinPoint

 * @return

 * @throws Throwable

 */

@Around("logPointcut()")

public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

    // 执行具体的业务逻辑

}

}

  • 1.2.2、HandlerInterceptor + 注解

使用Spring的拦截器HandlerInterceptorAdapter,也可以实现注解的业务,比如系统中使用这种方式配合SkipCertification,实现了某些指定接口跳过token验证的功能

@Slf4j

@Component

public class PermissionInterceptor extends HandlerInterceptorAdapter {

/**

 * 

  * @Title: preHandle 

  * @Description: 在Controller执行之前调用,如果返回false,controller不执行

  * @param  @param request

  * @param  @param response

  * @param  @param handler

  * @param  @return

  * @param  @throws Exception 

  * @throws 

  *

 */

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    if (!(handler instanceof HandlerMethod)) {// 如果不是HandlerMethod而是静态资源的请求,就直接跳过去

        return true;

    }

    HandlerMethod method = (HandlerMethod) handler;

    SkipCertification  certification = method.getMethodAnnotation(SkipCertification.class);

    if (null != certification) {// 跳过token验证

        return true;

    } else {

         // 执行校验  

    }

}

}

1.2.3、java反射 + 注解

通过反射,可以获取添加注解的属性值

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {

    TestAnnotation testAnnotation = new TestAnnotation();

    Field[] fields = obj.getClass().getDeclaredFields();

      for(Field field : fields) {

          field.setAccessible(true);

          if(field.isAnnotationPresent(testAnnotation )) {

              map.put(field.getName(),field.get(obj));

           }

        }

    }

1.2.4、 Filter + 注解

使用过滤器也可以实现直接的功能,比如利用fastJSON的AfterFilter,实现属性增强

public void doWrite(List<Field> fields, Object object) {

    for (int i = 0; i < fields.size(); i++) {

        Field field = fields.get(i);

        Stall stallAnn = AnnotationUtils.getAnnotation(field, Stall.class);

        if (stallAnn != null) {

                Object value = ReflectionUtils.getField(field, object);

                if (value != null) {

                        this.doWrite(field, value);

                }

        }

    }

}

猜你喜欢

转载自blog.csdn.net/Crystalqy/article/details/106146818