美文网首页
Java注解解析

Java注解解析

作者: Mr丶sorrow | 来源:发表于2018-01-16 18:20 被阅读0次

    概念

    注解是Java提供的一种 源程序中的元素关联任何信息和任何元数据的途径和方法。

    Java常见注解

    • JDK自带注解

      1. @Override 覆盖父类的方法

      2. @Deprecated 让方法过时

      3. @Suppvisewarnings 忽略警告

    • 常见第三方注解(Spring为例)

      1. @Autowired 可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。通过 @Autowired的使用来消除set ,get方法。

      2. @Service 用于标注业务层组件。定义某个类为一个bean,则在这个类的类名前一行使用@Service("XXX"),就相当于讲这个类定义为一个bean,bean名称为XXX。而无需去xml文件内去配置。

      3. @Repository 用于标注数据访问组件,即DAO组件。

    注解分类

    • 按运行机制分

      1. 源码注解:注解只在源码中存在,编译成.class文件就不存在了

      2. 编译时注解:注解在源码和.class文件中都存在(如:JDK内置系统注解)

      3. 运行时注解:在运行阶段还起作用,甚至会影响运行逻辑的注解(如:Spring中@Autowried)

    • 按照来源分

      1. JDK内置注解

      2. 自定义注解

      3. 第三方注解

    • 元注解——注解的注解

    自定义注解

    • 自定义注解的语法要求

      1. 使用@interface关键字定义注解

      2. 成员以无参无异常方式声明

      3. 可以用default为成员指定一个默认值

    image.png

    4. 如果注解只有一个成员,则成员名必须取名value(),在使用时可以忽略成员名和赋值

    号(=);

    5. 成员类型是受限的,合法的类型包括原始数据类型和String,Class,Annotation,Enumeration

    6. 注解类可以没有成员,没有成员的注解称为标识注解

    image.png
    • 元注解(注解里的注解)

      1. @Target({ElementType.FIELD,ElementType.METHOD}):定义注解的作用域

      • CONSTRUCTOR 构造方法声明

      • FIELD 字段声明

      • LOCAL_VARIABLE 局部变量声明

      • METHOD 方法声明

      • PACKAGE 包声明

      • PARAMETER 参数声明

      • TYPE 类接口

      2. @Retention(RetentionPolicy.RUNTIME):定义生命周期

      • SOURCE 只在源码显示,编译时会丢弃

      • CLASS 编译时会记录到class中,运行时忽略

      • RUNTIME 运行时存在,可以通过反射读取

      3. @Inherited:允许子类继承父类上的注解。只能用在类上,如果用在接口上将不会起作用。也只能继承类上的注解,方法上的不能被继承。

      4. @Documented:生成javadoc的时候包含注解

    使用自定义注解

    
    /* 自定义的注解类 */
    
    import java.lang.annotation.Documented;
    
    import java.lang.annotation.ElementType;
    
    import java.lang.annotation.Inherited;
    
    import java.lang.annotation.Retention;
    
    import java.lang.annotation.RetentionPolicy;
    
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
    
    @Retention(RetentionPolicy.RUNTIME)
    
    @Inherited
    
    @Documented
    
    public @interface Description{
    
      int age() default 10;
    
      String author();
    
      String desc();
    
    }
    
    --------------------------------------------------------------------------------
    
    /*
    
    使用注解的语法:
    
    @<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,...)
    
    */
    
    @Description(desc="I am eyeColor",author="Mooc boy",age=18)
    
    public String eyeColor(){
    
      return "red";
    
    }
    
    

    解析注解

    概念:通过反射获取类、函数或成员的运行时注解信息,从而实现动态控制程序运行的逻辑。

    步骤

    • 使用类加载器加载类

    • 找到类上边的注解

    • 拿到注解实例

    • 遍历方法上的注解

    示例

    
    //自定义注解 Description.java
    
    import java.lang.annotation.Documented;
    
    import java.lang.annotation.ElementType;
    
    import java.lang.annotation.Inherited;
    
    import java.lang.annotation.Retention;
    
    import java.lang.annotation.RetentionPolicy;
    
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
    
    @Retention(RetentionPolicy.RUNTIME)
    
    @Inherited
    
    @Documented
    
    public @interface Description{
    
      int age() default 10;
    
      String author();
    
      String desc();
    
    }
    
    
    
    // Person.class 用自定义注解修饰
    
    @Description(desc="human class", author="wgp", age=20)
    
    public class Person {
    
      @Description(desc="walk method", author="gp", age=21)
    
      public void walk(){
    
        System.out.println("human can walk!");
    
      }
    
    }
    
    
    
    // 注解解析类 Test.class
    
    import java.lang.annotation.Annotation;
    
    import java.lang.reflect.Method;
    
    public class Test {
    
    public static void main(String[] args) {
    
      try {
    
        //1\. 使用类加载器加载类
    
        Class c = Class.forName("Person");
    
        //2\. 找到类上面的注解
    
        boolean isExist=c.isAnnotationPresent(Description.class);//isAnnotationParse()判断类上是否存在Description这样的注解
    
        if(isExist){
    
          //3.获得注解实例
    
          Description d = (Description)c.getAnnotation(Description.class);
    
          System.out.println(d.desc());
    
        }
    
        //4.找到方法上的注解
    
        Method[] mts = c.getMethods();
    
        for (Method mt : mts) {
    
          if(mt.isAnnotationPresent(Description.class)){
    
            Description d2 = (Description)mt.getAnnotation(Description.class);
    
            System.out.println(d2.author());
    
          }
    
        }
    
        //另外一种获取类上的注解的途径
    
        Annotation[] annos = c.getAnnotations();
    
        for (Annotation anno : annos) {
    
          if(anno instanceof Description){
    
            System.out.println(((Description) anno).author());
    
          }
    
        }
    
        //另一种获取方法上的注解的途径
    
        for (Method mt : mts){
    
          Annotation[] annos2 = mt.getAnnotations();
    
          for (Annotation anno : annos2) {
    
            if(anno instanceof Description){
    
              System.out.println(((Description) anno).desc());
    
            }
    
          }
    
        }
    
      } catch (Exception e) {
    
        //TODO: handle exception
    
      }
    
    }
    
    }
    
    

    项目案例

    说明

    代替Hibernate的解决方案,用在项目的持久层,核心代码就是用自定义注解实现的。

    需求

    1. 有一张用户表,字段包含id,用户名,密码,地址,手机号;

    2. 方便的对每个字段或者每个字段的组合进行检索,并打印出SQL。

    分析

    1. 首先肯定有一个关于用户的JavaBean,包含所有用户信息;

    2. 有了JavaBean需要将属性与字段匹配,也就是ORM;

    3. 匹配完相当于拼接SQL语句时,知道表名和字段名称了,还缺少where中的字段值是多少;

    4. 通过用户类的getter方法来获取字段值为多少,拼接完整SQL语句。

    代码实现

    1. 用户类,我们希望用@Table和@Cloumn来绑定;

    
    /**
    
    * User:用户JavaBean
    
    */
    
    @Table("user")
    
    public class User {
    
      @Column("id")
    
      public Integer id;
    
      @Column("user_name")
    
      public String userName;
    
      @Column("password")
    
      public String passWord;
    
      @Column("address")
    
      public String address;
    
      @Column("phone_num")
    
      public String phoneNum;
    
      public void setId(Integer id) {
    
        this.id = id;
    
      }
    
      public void setUserName(String userName) {
    
        this.userName = userName;
    
      }
    
      public void setPassWord(String passWord) {
    
        this.passWord = passWord;
    
      }
    
      public void setAddress(String address) {
    
        this.address = address;
    
      }
    
      public void setPhoneNum(String phoneNum) {
    
        this.phoneNum = phoneNum;
    
      }
    
      public Integer getId() {
    
        return id;
    
      }
    
      public String getUserName() {
    
        return userName;
    
      }
    
      public String getPassWord() {
    
        return passWord;
    
      }
    
      public String getAddress() {
    
        return address;
    
      }
    
      public String getPhoneNum() {
    
        return phoneNum;
      
      }
    
    }
    
    

    2. 自定义@Table注解和@Column注解;

    
    import java.lang.annotation.ElementType;
    
    import java.lang.annotation.Retention;
    
    import java.lang.annotation.RetentionPolicy;
    
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE)
    
    @Retention(RetentionPolicy.RUNTIME)
    
    public @interface Table{
    
      String value();
    
    }
    
    --------------------------------------------------------------------------
    
    import java.lang.annotation.ElementType;
    
    import java.lang.annotation.Retention;
    
    import java.lang.annotation.RetentionPolicy;
    
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD)
    
    @Retention(RetentionPolicy.RUNTIME)
    
    public @interface Column{
    
      String value();
    
    }
    
    

    3. 根据反射来拼接出全部的SQL语句。

    
    import java.lang.reflect.Field;
    
    import java.lang.reflect.Method;
    
    public class UserDao {
    
      public static void main(String[] args) {
    
        User user1 = new User();
    
        user1.setId(0);
    
        User user2 = new User();
    
        user2.setUserName("ping");
    
        User user3 = new User();
    
        user3.setAddress("beijing");
    
        user3.setPhoneNum("10101010101");
    
        String sql1 = query(user1); //查询id为0用户
    
        String sql2 = query(user2); //查询用户名含有ping的用户
    
        String sql3 = query(user3); //查询满足多个条件的用户
    
        System.out.println(sql1);
    
        System.out.println(sql2);
    
        System.out.println(sql3);
      }
    
      public static String query(User user) {
    
        StringBuilder sBuilder = new StringBuilder();
    
        Class clazz = user.getClass();
    
        // 获取表名
    
        if(!clazz.isAnnotationPresent(Table.class)){
    
          return null;
    
        }
    
        Table table = (Table) clazz.getAnnotation(Table.class);
    
        String tableName = table.value();
    
        sBuilder.append("select * from ").append(tableName).append(" where 1 = 1");
    
        // 获取所有字段名+值
    
        Field[] fields = clazz.getDeclaredFields();
    
        for (Field field : fields) {
    
          if(!field.isAnnotationPresent(Column.class)){
    
            continue;
    
          }
    
          Column column = field.getAnnotation(Column.class);
    
          String columnName = column.value(); //字段名
    
          String fieldName = field.getName(); //属性名
    
          String getMethodName = "get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); //get方法名
    
          Object fieldValue = null; //属性值(先提升为Object类型)
    
          try {
    
            Method getMethod = clazz.getMethod(getMethodName);
    
            fieldValue = getMethod.invoke(user); //执行get方法获取值
    
          } catch (Exception e) {
    
            e.printStackTrace();
    
          }
    
          //继续拼接SQL
    
          if(fieldValue == null){
    
            continue;
    
          }
    
          sBuilder.append(" and ").append(columnName);
    
          if(fieldValue instanceof String){
    
            sBuilder.append("='").append(fieldValue).append("'");
    
          } else if(fieldValue instanceof Integer){
    
            sBuilder.append("=").append(fieldValue);
    
          }
    
        }
    
        return sBuilder.toString();
      }
    
    }
    

    参考资料

    相关文章

      网友评论

          本文标题:Java注解解析

          本文链接:https://www.haomeiwen.com/subject/brheoxtx.html