Java註解詳解

在使用SpringBoot做爲Web敏捷開發的框架以後,SpringBoot除了自動裝配配置的便捷以外,在不少時候須要基於註解來開發。註解不只增長了代碼的可讀性,還增長了開發的速度。這篇文章主要講述Java 註解。java

元註解
元註解用於註解其餘註解的。Java 5.0定義了4個標準的元註解,以下:sql

@Target
@Retention
@Documented
Inherited
如今來講說這四個元註解有什麼做用。app

@Target
@Target註解用於聲明註解的做用範圍,例如做用範圍爲類、接口、方法等。它的取值以及值所對應的範圍以下:框架

CONSTRUCTOR:用於描述構造器
FIELD:用於描述域
LOCAL_VARIABLE:用於描述局部變量
METHOD:用於描述方法
PACKAGE:用於描述包
PARAMETER:用於描述參數
TYPE:用於描述類、接口(包括註解類型) 或enum聲明
@Retention
該註解聲明瞭註解的生命週期,即註解在什麼範圍內有效。ui

SOURCE:在源文件中有效
CLASS:在class文件中有效
RUNTIME:在運行時有效(即運行時保留)
大多數註解都爲RUNTIME.net

@Documented
是一個標記註解,有該註解的註解會在生成 java 文檔中保留。對象

@Inherited
該註解代表子類是有繼承了父類的註解。好比一個註解被該元註解修飾,而且該註解的做用在父類上,那麼子類有持有該註解。若是註解沒有被該元註解修飾,則子類不持有父類的註解。blog

自定義註解
在Java開發者,JDK自帶了一些註解,在第三方框架Spring 帶了大量的註解,這些註解稱爲第三方註解。在不少實際開發過程當中,咱們須要定義本身的註解。那麼如今以案例的方式來說解自定義註解。繼承

在註解中,須要使用四種元註解來聲明註解的做用範圍、生命週期、繼承,是否生成文檔等。另外在註解中也能夠有本身的成員變量,若是一個註解沒有成員變量則稱爲標記註解。註解的成員變量,只支持原始類型、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

相關文章
相關標籤/搜索