在使用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