彻底搞懂 Java 中的注解 Annotation
Java注解是一系列元數據,它提供數據用來解釋程序代碼,但是注解并非是所解釋的代碼本身的一部分。注解對于代碼的運行效果沒有直接影響。
網絡上對注解的解釋過于嚴肅、刻板,這并不是我喜歡的風格。盡管這樣的解釋聽起來非常的專業。
為了緩解大家對“注解”的陌生感,我來說點有意思的。其實我對“注解”這個詞的第一印象并不是Java的注解,而是朱熹的名作《四書章句集注》。為什么我會有這么大的腦洞呢?因為當我試著去翻譯Annotation這個單詞的時候,得到的結果是“注釋”而不是“注解”。《四書章句集注》正是朱熹對《大學》、《中庸》、《論語》、《孟子》四書做出的重要的注釋。要知道,該書可是明清以后科舉考試的題庫和標準答案!
注解(Annotation)是在 Java SE 5.0 版本中開始引入的概念,同class和interface一樣,也屬于一種類型。很多開發人員認為注解的地位不高,但其實不是這樣的。像@Transactional、@Service、@RestController、@RequestMapping、@CrossOrigin等等這些注解的使用頻率越來越高。
01、為什么要使用注解呢?
為什么要使用注解呢?讓我們從另外一個問題說起。
“跨域”這兩個字就像一塊狗皮膏藥黏在每一個前端開發者的身上;我也不例外,雖然我并不是一個純粹的前端開發者。
跨域問題的出現,源于瀏覽器的同源策略——限制一個源加載的腳本去訪問另外一個源的資源,可有效地隔離潛在的惡意文件,是一種重要的安全機制。
跨域問題跨域問題的解決方案也有很多,比如說:
1)JSONP
2)Nginx代理
3)"跨域資源共享"(Cross-origin resource sharing),簡稱CORS,可以說是處理跨域問題的標準做法。
記得第一次遇到跨域問題的時候,我特意向一個同學請教了解決方案,他告訴我的答案如下。
第一步,在web.xml添加filter。
<filter><filter-name>contextfilter</filter-name><filter-class>com.cmower.filter.WebContextFilter</filter-class> </filter> <filter-mapping><filter-name>contextfilter</filter-name><url-pattern>/*</url-pattern> </filter-mapping>第二步,實現WebContextFilter類。
public?class?WebContextFilter?implements?Filter?{@Overridepublic?void?destroy()?{}@Overridepublic?void?doFilter(ServletRequest?request,?ServletResponse?response,?FilterChain?chain)throws?IOException,?ServletException?{HttpServletResponse??httpServletResponse?=?(HttpServletResponse)?response;httpServletResponse.setHeader("Access-Control-Allow-Origin",?"*");httpServletResponse.setHeader("Access-Control-Allow-Headers",?"accept,content-type");?httpServletResponse.setHeader("Access-Control-Allow-Methods",?"OPTIONS,GET,POST,DELETE,PUT");?chain.doFilter(request,?httpServletResponse);}@Overridepublic?void?init(FilterConfig?arg0)?throws?ServletException?{}}看到這樣的解決方案,我真的是蠻崩潰的。不就一個跨域問題嘛,用得著這么多代碼嗎?
我對這樣的解決方案非常的不滿意。于是下定決心要好好的研究一番,大概花了半天的時間吧,我終于搞清楚了“跨域”問題,以及它的標準解決方案CORS。并且找到了一個極為簡潔的解決方案——@CrossOrigin,只要在Controller類上加上這個注解,就可以輕松地解決跨域問題。
代碼如下。
@RestController @RequestMapping("course") @CrossOrigin public?class?CourseController?{ }如果沒有找到@CrossOrigin這個注解,我真的就要按照同學提供的方案去解決跨域的問題了。但那樣做就好像,我們賣掉家里的小汽車,然后出行的時候駕一輛馬車一樣。
這也正是我想告訴你的,為什么要使用注解的原因:它讓我們的代碼看起來更簡潔,更有時代的進步感。
02、該如何定義注解呢?
注解需要通過@interface關鍵字(形式和接口非常的相似,只是前面多了一個@)進行定義。我們可以打開@CrossOrigin的源碼來看一下。
@Target({?ElementType.METHOD,?ElementType.TYPE?}) @Retention(RetentionPolicy.RUNTIME) @Documented public?@interface?CrossOrigin?{/***?List?of?allowed?origins,?e.g.?{@code?"http://domain1.com"}.*?<p>These?values?are?placed?in?the?{@code?Access-Control-Allow-Origin}*?header?of?both?the?pre-flight?response?and?the?actual?response.*?{@code?"*"}?means?that?all?origins?are?allowed.*?<p>If?undefined,?all?origins?are?allowed.*?@see?#value*/@AliasFor("value")String[]?origins()?default?{};/***?List?of?request?headers?that?can?be?used?during?the?actual?request.*?<p>This?property?controls?the?value?of?the?pre-flight?response's*?{@code?Access-Control-Allow-Headers}?header.*?{@code?"*"}??means?that?all?headers?requested?by?the?client?are?allowed.*?<p>If?undefined,?all?requested?headers?are?allowed.*/String[]?allowedHeaders()?default?{};/***?List?of?supported?HTTP?request?methods,?e.g.*?{@code?"{RequestMethod.GET,?RequestMethod.POST}"}.*?<p>Methods?specified?here?override?those?specified?via?{@code?RequestMapping}.*?<p>If?undefined,?methods?defined?by?{@link?RequestMapping}?annotation*?are?used.*/RequestMethod[]?methods()?default?{}; }從上面的代碼可以看得出來,“注解”真的很“注解”,除了注釋多和“元注解”多之外,真沒有別的了。
“元注解”?什么是“元注解”呢?
“元注解”是用來注解(動詞)注解(名詞)的注解(名詞)。請感受漢語的博大精深。@Target、@Retention和@Documented就是所謂的元注解。
1)@Target
Target是目標的意思,@Target指定了注解運用的場景。都有哪些場景值呢?
ElementType.ANNOTATION_TYPE:可以給注解進行注解
ElementType.CONSTRUCTOR:可以給構造方法進行注解
ElementType.FIELD:可以給字段進行注解
ElementType.LOCAL_VARIABLE:可以給局部變量進行注解
ElementType.METHOD:可以給方法進行注解
ElementType.PACKAGE:可以給包進行注解
ElementType.PARAMETER:可以給方法內的參數進行注解
ElementType.TYPE:可以給類型進行注解,比如類、接口和枚舉
2)@Retention
Retention這個單詞的意思為保留期。也就是說,當@Retention應用到一個注解上的時候,它解釋說明了這個注解的存活時間。來看它的取值范圍。
RetentionPolicy.SOURCE:注解只在源碼階段保留,在編譯器進行編譯時它將被丟棄忽視。
RetentionPolicy.CLASS:注解只被保留到編譯進行的時候,并不會被加載到 JVM 中。
RetentionPolicy.RUNTIME:注解可以保留到程序運行的時候,它會被加載進入到 JVM 中,所以在程序運行時可以獲取到它們。
3)@Documented
Documented就比較容易理解,它和文檔有關。作用就是能夠將注解中的元素包含到 Javadoc 中。
當我們了解了元注解的概念后,再回頭看一下@CrossOrigin的源碼,是不是感覺清晰多了呢?
如果能夠細致地讀一讀源碼中的注釋,你就會看到WebContextFilter類中出現的關鍵字,諸如Access-Control-Allow-Origin、Access-Control-Allow-Headers、Access-Control-Allow-Methods。也就是說,當我們通過@CrossOrigin對Controller類注解后,SpringMVC就能夠在運行時對這個類自動加上解決跨域問題的過濾器。
03、注解可以反射嗎?
注解是可以通過反射獲取的。
1)可以通過 Class 對象的 isAnnotationPresent() 方法判斷該類是否應用了某個指定的注解。
2)通過 getAnnotation() 方法來獲取注解對象。
3)當獲取到注解對象后,就可以獲取使用注解時定義的屬性值。
示例如下:
@CrossOrigin(origins?=?"http://qingmiaokeji.com",?allowedHeaders?=?"accept,content-type",?methods?=?{?RequestMethod.GET,?RequestMethod.POST?}) public?class?TestController?{public?static?void?main(String[]?args)?{Class?c?=?TestController.class;if?(c.isAnnotationPresent(CrossOrigin.class))?{CrossOrigin?crossOrigin?=?(CrossOrigin)?c.getAnnotation(CrossOrigin.class);System.out.println(Arrays.asList(crossOrigin.allowedHeaders()));System.out.println(Arrays.asList(crossOrigin.methods()));System.out.println(Arrays.asList(crossOrigin.origins()));}} }//?輸出:[accept,content-type] //?[GET,?POST] //?[http://qingmiaokeji.com]04、注解經常用在哪里呢?
1)@Transactional:Spring 為事務管理提供的功能支持。
2)@ Service:Spring在進行包掃描的時候,會自動將這個類注冊到Spring容器中。
3)@RestController:是@ResponseBody和@Controller的組合注解。
也就是說,下面這段代碼與下下面的代碼等同。
@RestController public?class?HelloController?{@RequestMapping(value="hello")public?String?sayHello(){return?"hello";} } @Controller @ResponseBody public?class?HelloController?{@RequestMapping(value="hello")public?String?sayHello(){return?"hello";} }4)@RequestMapping :Spring Web 應用程序中最常用到的注解之一,將 HTTP 請求映射到 MVC 和 REST 控制器的處理方法上。
5)@Select:MyBatis提供的查詢語句注解。示例如下:
@Select("select?*?from?city") List<City>?getCitys();6)還有很多很多,就不再一一列舉了。
最后
我想說的是,注解有許多用處,主要有:
提供信息給編譯器: 編譯器可以利用注解來探測錯誤和警告信息。
編譯階段時的處理: ?軟件工具可以利用注解信息來生成代碼、HTML文檔。
運行時的處理: ?某些注解可以在程序運行的時候接受代碼的提取。
別忘了:
四書章句集注近期熱點推薦
Java 最常見的 200+ 面試題
Java 200+ 面試題補充③ Dubbo 模塊
Java 200+ 面試題補充② Netty 模塊
Java 200+ 面試題補充 ThreadLocal 模塊
面試題 == 和 equals 的區別
面試經驗分享|精華篇
精美簡歷合集II
精美簡歷合集I
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的彻底搞懂 Java 中的注解 Annotation的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阅读源码的 4 个绝技,我必须分享给你!
- 下一篇: Java 中的 String 有没有长度