轉載請標明出處:
blog.csdn.net/forezp/arti…
本文出自方誌朋的部落格
在使用SpringBoot作為Web敏捷開發的框架之後,SpringBoot除了自動裝配配置的便捷之外,在很多時候需要基於註解來開發。註解不僅增加了程式碼的可讀性,還增加了開發的速度。這篇文章主要講述Java 註解。
元註解
元註解用於註解其他註解的。Java 5.0定義了4個標準的元註解,如下:
- @Target
- @Retention
- @Documented
- Inherited
現在來說說這四個元註解有什麼作用。
@Target
@Target註解用於宣告註解的作用範圍,例如作用範圍為類、介面、方法等。它的取值以及值所對應的範圍如下:
- CONSTRUCTOR:用於描述構造器
- FIELD:用於描述域
- LOCAL_VARIABLE:用於描述區域性變數
- METHOD:用於描述方法
- PACKAGE:用於描述包
- PARAMETER:用於描述引數
- TYPE:用於描述類、介面(包括註解型別) 或enum宣告
@Retention
該註解宣告瞭註解的生命週期,即註解在什麼範圍內有效。
- SOURCE:在原始檔中有效
- CLASS:在class檔案中有效
- RUNTIME:在執行時有效(即執行時保留)
大多數註解都為RUNTIME
@Documented
是一個標記註解,有該註解的註解會在生成 java 文件中保留。
@Inherited
該註解表明子類是有繼承了父類的註解。比如一個註解被該元註解修飾,並且該註解的作用在父類上,那麼子類有持有該註解。如果註解沒有被該元註解修飾,則子類不持有父類的註解。
自定義註解
在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
參考資料
慕課網視訊
原始碼下載
關注我的公眾號
精彩內容不能錯過!