5分鐘搞懂java注解@Annotation的具體使用
首先一句話結(jié)論:注解就是一種通過(guò)在類、方法、或者屬性等上使用類似@xxx的方式進(jìn)行“打標(biāo)簽”,然后可以通過(guò)反射機(jī)制對(duì)標(biāo)簽的內(nèi)容進(jìn)行解析并進(jìn)行相應(yīng)處理的手段。
注解是java中的一個(gè)重要知識(shí)點(diǎn),從java5后開(kāi)始引入,尤其在spring框架中大量使用。比較常用的有@controller、@service等等各種,本文將從注解的實(shí)現(xiàn)原理出發(fā),通過(guò)一些demo代碼的實(shí)現(xiàn),進(jìn)行分析。
一、 注解定義方式
直接上代碼,看看spring中@Service注解的定義就知道了:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { String value() default ""; }
可以看到注解的定義和接口定義很像,但是多了@字符,注解的定義上有以下約定:
- 只能定義屬性名,不能定義方法
- 屬性的可見(jiàn)性只有public和default,不寫則默認(rèn)后者
- 屬性的類型只能支持:基本數(shù)據(jù)類型、string、class、enum、Annotation類型及以上類型的數(shù)組
- 可以加上defult關(guān)鍵字指明默認(rèn)值,當(dāng)某字段不指明默認(rèn)值時(shí),必須在進(jìn)行注解標(biāo)注的時(shí)候進(jìn)行此字段值的指定。
- 當(dāng)使用value作為屬性名稱時(shí),可以不顯式指定value=“xxx”,如可以直接使用@Service("xxxService")
二、元注解
所謂元注解就是java中默認(rèn)實(shí)現(xiàn)的專門對(duì)注解進(jìn)行注解的注解。元注解的總數(shù)就5個(gè),下面我們以上面講到的@Service注解為例子各個(gè)擊破:
1.@Target
此注解用于表示當(dāng)前注解的使用范圍,@Target({ElementType.TYPE})就代表著@Service這個(gè)注解是專門用來(lái)注解到類、接口、或者枚舉類型上面的,當(dāng)在方法上面加這個(gè)注解時(shí),就會(huì)報(bào)錯(cuò)??梢钥吹阶⒔馕恢檬且粋€(gè)枚舉類型,完整定義如下
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE }
2.@Retention
此注解用于表示當(dāng)前注解的生命周期,說(shuō)人話就是這個(gè)注解作用會(huì)保留到什么時(shí)候,如@Retention(RetentionPolicy.RUNTIME)就表示在程序運(yùn)行期間依然有效,此時(shí)就可以通過(guò)反射拿到注解的信息,完整的枚舉定義如下
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
3.@Documented
當(dāng)被此注解所注解時(shí),使用javadoc工具生成文檔就會(huì)帶有注解信息。
4.@Inherited
此注解與繼承有關(guān),當(dāng)A注解添加此注解后,將A注解添加到某類上,此類的子類就會(huì)繼承A注解。
@Inherited public @interface A{ } @A public class Parent{} public class Son entends Parant{}//Son類繼承了父類的A注解
5.@Repeatable
此注解顧名思義是擁有可以重復(fù)注解的能力。想象這樣一個(gè)場(chǎng)景,我們需要定時(shí)執(zhí)行某個(gè)任務(wù),需要在每周一和周三執(zhí)行,并且這個(gè)時(shí)間是可以靈活調(diào)整的,此時(shí)這個(gè)元注解就能派上用場(chǎng):
@Repeatable(Schedules.class) public @interface Schedule { String date(); } public @interface Schedules { Schedule[] value(); } @Schedule(date = "周一") @Schedule(date = "周三") public class Executor { }
注意看到此元注解后面括號(hào)里內(nèi)容,在這指定的類叫做容器注解,意思是保存這多個(gè)注解的容器,故我們創(chuàng)建一個(gè)@Schedules注解作為@Schedule的容器注解,容器注解必須含有一個(gè)名字為value,返回類型為需放入此容器的注解數(shù)組的屬性。
三、自定義實(shí)現(xiàn)一個(gè)注解
下面我們以web項(xiàng)目中非常常見(jiàn)的鑒權(quán)場(chǎng)景為例自己實(shí)現(xiàn)一個(gè)自定義注解。
首先我們定義系統(tǒng)的使用人員身份,有超級(jí)管理員、管理員、訪客三種身份。
public enum IdentityEnums { SUPER_ADMIN, ADMIN, VISIVOR }
接下來(lái)我們定義一個(gè)權(quán)限注解:
@Target({ElementType.TYPE,ElementType.METHOD}) @Documented @Retention(RetentionPolicy.RUNTIME) public @interface Authorization { IdentityEnums[] value(); }
然后使用攔截器的方式,對(duì)所有頁(yè)面進(jìn)行統(tǒng)一的鑒權(quán)管理,此處只展示一些關(guān)鍵代碼:
public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { IdentityEnums user = getIdentityFromRequset(request);//這里從request里獲取賬號(hào)信息并判斷身份,自己實(shí)現(xiàn) Authorization auth =((HandlerMethod) handler).getMethodAnnotation(Authorization.class);//獲取方法上面的注解 if (!Arrays.asList(auth.value()).contains(user)){ return false; } } return true; } }
最后在spring配置文件中對(duì)攔截器進(jìn)行配置開(kāi)啟攔截器:
<!-- 攔截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 匹配的是url路徑, 如果不配置或/**,將攔截所有的Controller --> <mvc:mapping path="/**" /> <!-- 攔截器類 --> <bean class="com.xx.xx.AuthInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
在實(shí)際使用中,我們將在方法上面添加此自定義注解,當(dāng)身份權(quán)限符合時(shí),才能對(duì)頁(yè)面進(jìn)行訪問(wèn),使用方式如下:
@ResponseBody
@RequestMapping(value = "/management") @Authorization({IdentityEnums.ADMIN,IdentityEnums.SUPER_ADMIN}) public String management(HttpServletRequest request, HttpServletResponse response) { log.info("has permission!"); }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java注解之Retention、Documented、Inherited介紹
- java教程之java注解annotation使用方法
- Java注解Annotation與自定義注解詳解
- Java注解機(jī)制之Spring自動(dòng)裝配實(shí)現(xiàn)原理詳解
- Java注解@Transactional事務(wù)類內(nèi)調(diào)用不生效問(wèn)題及解決辦法
- 基于Java注解(Annotation)的自定義注解入門介紹
- 詳解Java注解教程及自定義注解
- 創(chuàng)建自定義的Java注解類的方法
- 深入理解Java注解類型(@Annotation)
- 輕松掌握J(rèn)ava注解,讓編程更智能、更優(yōu)雅
相關(guān)文章
springboot 按月分表的實(shí)現(xiàn)方式
本文主要介紹了springboot 按月分表的實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Java基本數(shù)據(jù)類型(動(dòng)力節(jié)點(diǎn)java學(xué)院整理)
Java數(shù)據(jù)類型(type)可以分為兩大類:基本類型(primitive types)和引用類型(reference types)。下面是動(dòng)力節(jié)點(diǎn)給大家整理java基本數(shù)據(jù)類型相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧2017-03-03Spring實(shí)現(xiàn)類私有方法的幾個(gè)問(wèn)題(親測(cè)通用解決方案)
現(xiàn)實(shí)的業(yè)務(wù)場(chǎng)景中,可能需要對(duì)Spring的實(shí)現(xiàn)類的私有方法進(jìn)行測(cè)試。本文給大家分享Spring實(shí)現(xiàn)類私有方法面臨的幾個(gè)問(wèn)題及解決方案,感興趣的朋友跟隨小編一起看看吧2021-06-06修改SpringBoot啟動(dòng)圖標(biāo)banner的兩種方式
Banner即橫幅標(biāo)語(yǔ),我們?cè)趩?dòng)SpringBoot項(xiàng)目時(shí)會(huì)將Banner信息打印至控制臺(tái),我們可以輸出一些圖形、SpringBoot版本信息等內(nèi)容,有很多小伙伴想知道如何修改SpringBoot啟動(dòng)圖標(biāo)banner,接下來(lái)由小編給大家介紹一下吧2024-08-08Java?Spring?事件監(jiān)聽(tīng)詳情解析
這篇文章主要介紹了Java?Spring?事件監(jiān)聽(tīng)詳情解析,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07