您的關注是我最大的動力
隨着軟件開發的發展,xml配置已經被註解所取代,註解被越來越多的運用到我們的代碼中了。如果我們想要使自己定義的註解來進行一些操作該怎麼做呢?
自定義註解
在項目中新建Java文件是選擇Annotation類型則會爲我們創建一個註解文件。關於註解的詳細介紹可以看之前寫的註解詳解文章。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Scope("prototype")
public @interface XyhBean {
}
上面創建的這個註解表名這是一個在運行時起作用的註解,並且只能作用於類上,而且作用的類不是一個單例。
使用場景
在我們的項目中可能會遇到這樣的情況,需要一個工廠或者Map來存儲一些類的信息,在之後的使用過程中通過工廠或者Map來獲取到我們所需要的類。在一般情況下我們可能就會使用Map來進行這個操作。但是每當項目中新增一個類就要往Map中也操作一次,這樣會非常的麻煩並且容易出現問題,因此我們使用自定義註解通過spring來幫我們操作。
ApplicationListener
在一些業務場景中,當容器初始化完成之後,需要處理一些操作,比如一些數據的加載、初始化緩存、特定任務的註冊等等。這個時候我們就可以使用Spring提供的ApplicationListener來進行操作。
@Component
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
public static Map<String, Object> beanMap = new HashMap<>();
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
beanMap = event.getApplicationContext().getBeansWithAnnotation(XyhBean.class);
}
}
項目啓動之後,讀取所有註解了XyhBean註解的類放進我們事先定義好的Map中。
通過反射處理註解
上面的方法是通過Spring來幫助我們實現了一個簡單的自定義註解場景,如果有更加複雜的場景的話就需要藉助Java的反射來完成了。
註解處理器類庫(java.lang.reflect.AnnotatedElement):
Java使用Annotation接口來代表程序元素前面的註解,該接口是所有Annotation類型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,該接口代表程序中可以接受註解的程序元素,該接口主要有如下幾個實現類:
- Class:類定義
- Constructor:構造器定義
- Field:累的成員變量定義
- Method:類的方法定義
- Package:類的包定義
java.lang.reflect 包下主要包含一些實現反射功能的工具類,實際上,java.lang.reflect 包所有提供的反射API擴充了讀取運行時Annotation信息的能力。當一個Annotation類型被定義爲運行時的Annotation後,該註解才能是運行時可見,當class文件被裝載時被保存在class文件中的Annotation纔會被虛擬機讀取。
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過反射獲取了某個類的AnnotatedElement對象之後,程序就可以調用該對象的如下四個個方法來訪問Annotation信息:
方法1. <T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回該程序元素上存在的、指定類型的註解,如果該類型註解不存在,則返回null。
方法2. Annotation[] getAnnotations():返回該程序元素上存在的所有註解。
方法3. boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的註解,存在則返回true,否則返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在於此元素上的所有註釋。與此接口中的其他方法不同,該方法將忽略繼承的註釋。(如果沒有註釋直接存在於此元素上,則返回長度爲零的一個數組。)該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響。
public class AnnotationUtil {
public static boolean getFruitInfo(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(XyhBean.class)) {
return true;
}
}
return false;
}
}
以上代碼可以用來判斷傳進來的類是否註解了我們自己定義的註解。具體使用的方法需要根據使用場景來進行選擇。