Java注解

1.注解的概念Java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法,
  要清晰概念首先要了解注解的本质其实就是接口。
2.什么是元数据?
  元数据是指用来描述数据的数据,更通俗一点,就是描述代码间关系,或者代码与其他资源(例如数据库表)之间内在联系的数据。
3.注解类型
  既然元数据是指用来描述数据的数据,那么元注解就是注解的注解(在注解中再添加一层注解)
JAVA元注解有四种:
@ Retention
  注解的声明周期,用于定义注解的存活阶段,可以存活在源码级别、编译级别(字节码级别)、运行时级别
  SOURCE:源码级别,注解只存在源码中,一般用于和编译器交互,用于检测代码。如 @ Override, @ SuppressWarings。
  CLASS:字节码级别,注解存在于源码和字节码文件中,主要用于编译时生成额外的文件,如XML,Java文件等,但运行时无法获得。 如mybatis生成实 体和映射文件,这个级别需要添加JVM加载时候的代理(javaagent),使用代理来动态修改字节码文件。
  RUNTIME:运行时级别,注解存在于源码、字节码、java虚拟机中,主要用于运行时,可以使用反射获取相关的信息。
例: @ Retention(RetentionPolicy.RUNTIME)
@ Target
  用于定义注解可以在什么地方使用,默认可以在任何地方使用,也可以指定使用的范围,开发中将注解用在类上(如 @ Controller)、字段上(如 @ Autowire)、方法上(如 @ RequestMapping)、方法的参数上(如 @ RequestParam)等比较常见。
  TYPE: 类、接口或enum声明
  FIELD: 域(属性)声明
  METHOD: 方法声明
  PARAMETER: 参数声明
  CONSTRUCTOR: 构造方法声明
  LOCAL_VARIABLE: 局部变量声明
  ANNOTATION_TYPE: 注释类型声明
  PACKAGE: 包声明
例: @ Target(ElementType.ANNOTATION_TYPE)
@ Document
  用于标记在生成javadoc时,是否将注解包含进去,可以看到这个注解和 @ Override一样,注解中空空如也,什么东西都没有
@ Inherited
  允许子类继承父类中的注解,可以通过反射获取到父类的注解
@ Constraint
  用于校验属性值是否合法
4.注解的内容
  注解的内容的语法格式: 数据类型 属性名()default默认值,
  数据类型用于描述属性的数据类型,
  默认值是说当没有给属性赋值时使用默认值,一般String使用空字符串作为默认值,数组一般使用空数组作为默认值.
5.注解的使用场景
  可以通过注解的声明周期来分析注解的使用场景:
1.SOURCE源码级别:给编译器使用,如 @ Override、 @ Deprecated 等, 这部分开发者应该使用的场景不多
2.CLASS:字节码级别,这部分也很少见到
3.RUNTIME:运行时级别,这个是最多的,几乎开发者使用到的注解都是运行时级别,运行时注解常用的有以下几种情况:
注解中没有任何属性的,空的注解,这部分注解通常起到一个标注的作用,如 @ Test、 @ Before、 @ After,通过获取这些标记注解在逻辑上做一些特殊的处理
可以使用约束注解 @ Constraint来对属性值进行校验,如 @ Email, @ NotNull等
可以通过在注解中使用属性来配置一些参数,然后可以使用反射获取这些参数,这些注解没有其他特殊的功能,只是简单的代替xml配置的方式来配置一些参数。使用注解来配置参数这在Springboot中得到了热捧

6.Java注解和反射基本API

 

// 获取某个类型的注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass);
// 获取所有注解(包括父类中被Inherited修饰的注解)
public Annotation[] getAnnotations(); 
// 获取声明的注解(但是不包括父类中被Inherited修饰的注解)
public Annotation[] getDeclaredAnnotations();
// 判断某个对象上是否被某个注解进行标注
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 获取某个类声明的所有字段
public Field[] getDeclaredFields() throws SecurityException;
// 获取某个方法
public Method getMethod(String name, Class<?>... parameterTypes);

7.自定义注解

使用自定义注解+拦截器或者是AOP等可以进行权限的控制。
下面通过定义一个注解用来限制当用户访问接口时必须要登录的示例
步骤一:定义注解 :RequiresLogin.java

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

步骤二:使用注解

public class UserController {
  @RequiresLogin
  @RequestMapping(value = "/list", produces = {"application/json;charset=UTF-8;"})
  public String getUserList(){
    System.out.println("--------------");
    return "[{'id': 1, 'username':'xiaoqiao'}]";
  }
}

步骤三:使用AOP进行拦截,解析注解

public class LoginAdvices {

@Pointcut(value = "@annotation(com.ren.anno.RequiresLogin)")
public void pointcut(){}

@Before(value="pointcut()&&@annotation(RequiresLogin)")
public void before(JoinPoint joinPoint) throws Exception{
    Object target = joinPoint.getTarget();
    String methodName = joinPoint.getSignature().getName();
    System.out.println(target + "-------" + methodName);
    Method method = target.getClass().getMethod(methodName);
    boolean annotationPresent = method.isAnnotationPresent(RequiresLogin.class);
    if (annotationPresent) {
      // 用户必须登录
      boolean isLogin = false;
      if (!isLogin) {
        throw new Exception("访问该接口必须先登录");
      } else {
        System.out.println("已登录...");
      }
    }
  }
}

除此之外还可以定义多个切点在不同的场景下使用。

 

posted @ 2020-04-16 16:30  上官兰夏  阅读(163)  评论(0编辑  收藏  举报