Java注解详解

转载请标明出处:
blog.csdn.net/forezp/arti…
本文出自方志朋的博客html

在使用SpringBoot做为Web敏捷开发的框架以后,SpringBoot除了自动装配配置的便捷以外,在不少时候须要基于注解来开发。注解不只增长了代码的可读性,还增长了开发的速度。这篇文章主要讲述Java 注解。java

元注解

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

  • @Target
  • @Retention
  • @Documented
  • Inherited

如今来讲说这四个元注解有什么做用。github

@Target

 @Target注解用于声明注解的做用范围,例如做用范围为类、接口、方法等。它的取值以及值所对应的范围以下:sql

  • CONSTRUCTOR:用于描述构造器
  • FIELD:用于描述域
  • LOCAL_VARIABLE:用于描述局部变量
  • METHOD:用于描述方法
  • PACKAGE:用于描述包
  • PARAMETER:用于描述参数
  • TYPE:用于描述类、接口(包括注解类型) 或enum声明

@Retention

该注解声明了注解的生命周期,即注解在什么范围内有效。bash

  • SOURCE:在源文件中有效
  • CLASS:在class文件中有效
  • RUNTIME:在运行时有效(即运行时保留)

大多数注解都为RUNTIMEapp

@Documented

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

@Inherited

该注解代表子类是有继承了父类的注解。好比一个注解被该元注解修饰,而且该注解的做用在父类上,那么子类有持有该注解。若是注解没有被该元注解修饰,则子类不持有父类的注解。ui

自定义注解

在Java开发者,JDK自带了一些注解,在第三方框架Spring 带了大量的注解,这些注解称为第三方注解。在不少实际开发过程当中,咱们须要定义本身的注解。那么如今以案例的方式来说解自定义注解。spa

在注解中,须要使用四种元注解来声明注解的做用范围、生命周期、继承,是否生成文档等。另外在注解中也能够有本身的成员变量,若是一个注解没有成员变量则称为标记注解。注解的成员变量,只支持原始类型、Class、Enumeration、Annoation。

如今定义一个@Writer注解,该注解被Retention、Documented、Inherited、Target修饰,代表该注解的做用范围为类、接口和方法,生命周期为运行时、该注解生成文档,而且子类可继承该注解。该注解有2个成员变量,一个为name一个为 age,代码以下:

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface Writer {

    String name();

    int age();

}复制代码

那么有了该注解,怎么用呢?

该注解的做用范围为类、方法,写一个WriterTest,代码以下:

@Writer(name = "forezp", age = 12)
public class WriterTest {

    @Writer(name = "miya", age = 10)
    public void writeBlog() {
        System.out.println("writing blog");
    }

  }复制代码

该类有了这个注解有何用?

通常来讲,用该类修饰的类,须要经过反射来作一下逻辑的开发的工做,可普遍用于AOP、程序的配置等。如今写一个方法经过反射来解析该注解:

public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("com.forezp.annotation.WriterTest");
        if (c.isAnnotationPresent(Writer.class)) {
            Writer w = (Writer) c.getAnnotation(Writer.class);
            System.out.println("name:" + w.name() + " age:" + w.age());
        }
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Writer.class)) {
                Writer w = method.getAnnotation(Writer.class);
                System.out.println("name:" + w.name() + " age:" + w.age());
            }
        }
    }复制代码

这些代码基本为反射的内容,由于反射在另外一篇文章已经详细讲述过,再也不重复,运行该Main方法,控制台打印出以下内容:

name:forezp age:12

name:miya age:10

案例实战

有了上述的讲解,你可能对注解有所了解,可是对注解的具体应用并非很深入。如今以一个案例来详细讲述。

你们都对ORM框架Mybitis都很是的熟悉,在这个框架中用了大量的注解。如今模仿这个框架,经过自定义注解,来解析sql 的查询语句。实现过程大概以下:

  • 定义@Table @Colum注解
  • 定义一个实体User,定义一些基本的字段,并用注解修饰
  • 用User类new对象,给对象的某些字段赋值
  • 经过反射和注解来生成sql 的查询语句

首先定义个一个Table注解,它的做用范围为类,代码以下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
public @interface Table {
    String value() default "";
}复制代码

定义一个Column注解,做用范围为字段,代码以下:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Column {
    String value();
}复制代码

定义一个User类,在该类的加上@Table注解,在具体的字段上 @Column注解,代码以下:

@Table("user")
public class User {
    @Column("id")
    private int id;
    @Column("name")
    private String name;
    @Column("age")
    private int age;
    @Column("address")
    private String address;
    ..//省略getter setter
   }复制代码

写一个生成sql语句的类,它是经过反射来获取表名、字段名,加上判断实体对象的字段值来生成 查询的 sql 语句的。代码以下:

public class GenUserSql {

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        User u1 = new User();
        User u2 = new User();
        u1.setId(1);
        u2.setName("forezp");
        genSql(u2);
        genSql(u1);
    }

    private static void genSql(User user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class c = user.getClass();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("select * from ");
        if (c.isAnnotationPresent(Table.class)) {
            Table table = (Table) c.getAnnotation(Table.class);
            String tableName = table.value();
            stringBuilder.append(tableName).append(" where 1=1 and ");
        }
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            String columnName;
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                columnName = column.value();
            } else {
                continue;
            }
            String fieldName = field.getName();
            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                       Method method = c.getMethod(getMethodName);
            Object fieldValue = method.invoke(user);
            if (fieldValue == null || ((fieldValue instanceof Integer) && (Integer) fieldValue == 0)) {
                continue;
            }
            if (fieldValue instanceof Integer) {
                stringBuilder.append(columnName + "=" + fieldValue);
            }
            if (fieldValue instanceof String) {
                stringBuilder.append(columnName + "=" + "'" + fieldValue + "'");
            }

        }
        System.out.println(stringBuilder.toString());

    }
}复制代码

运行程序,控制台打印以下:

>

select * from user where 1=1 and name='forezp'

select * from user where 1=1 and id=1

参考资料

www.cnblogs.com/peida/archi…

慕课网视频

源码下载

github.com/forezp/java…

关注个人公众号

精彩内容不能错过!

forezp.jpg
forezp.jpg
相关文章
相关标签/搜索