在 Java 中,並非全部的類型信息都能在編譯階段明確,有一些類型信息須要在運行時才能肯定,這種機制被稱爲 RTTI,英文全稱爲 Run-Time Type Identification
,即運行時類型識別,有沒有一點「知行合一」的味道?運行時類型識別主要由Class類實現。html
Java註解是一系列元數據,它提供數據用來解釋程序代碼,可是註解並不是是所解釋的代碼自己的一部分。註解對於代碼的運行效果沒有直接影響。
網絡上對註解的解釋過於嚴肅、刻板,這並非我喜歡的風格。儘管這樣的解釋聽起來很是的專業。前端
爲了緩解你們對「註解」的陌生感,我來講點有意思的。其實我對「註解」這個詞的第一印象並非Java的註解,而是朱熹的名做《四書章句集註》。爲何我會有這麼大的腦洞呢?由於當我試着去翻譯Annotation
這個單詞的時候,獲得的結果是「註釋」而不是「註解」。《四書章句集註》正是朱熹對《大學》、《中庸》、《論語》、《孟子》四書作出的重要的註釋。要知道,該書但是明清之後科舉考試的題庫和標準答案!java
註解(Annotation
)是在 Java SE 5.0 版本中開始引入的概念,同class
和interface
同樣,也屬於一種類型。不少開發人員認爲註解的地位不高,但其實不是這樣的。像@Transactional
、@Service
、@RestController
、@RequestMapping
、@CrossOrigin
等等這些註解的使用頻率愈來愈高。web
爲何要使用註解呢?讓咱們從另一個問題提及。跨域
「跨域」這兩個字就像一塊狗皮膏藥黏在每個前端開發者的身上;我也不例外,雖然我並非一個純粹的前端開發者。瀏覽器
跨域問題的出現,源於瀏覽器的同源策略——限制一個源加載的腳本去訪問另一個源的資源,可有效地隔離潛在的惡意文件,是一種重要的安全機制。安全
跨域問題的解決方案也有不少,好比說:微信
1)JSONP網絡
2)Nginx代理app
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 { @Override public void destroy() { } @Override public 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); } @Override public void init(FilterConfig arg0) throws ServletException { } }
看到這樣的解決方案,我真的是蠻崩潰的。不就一個跨域問題嘛,用得着這麼多代碼嗎?
我對這樣的解決方案很是的不滿意。因而下定決心要好好的研究一番,大概花了半天的時間吧,我終於搞清楚了「跨域」問題,以及它的標準解決方案CORS
。而且找到了一個極爲簡潔的解決方案——@CrossOrigin
,只要在Controller類上加上這個註解,就能夠輕鬆地解決跨域問題。
代碼以下。
@RestController @RequestMapping("course") @CrossOrigin public class CourseController { }
若是沒有找到@CrossOrigin
這個註解,我真的就要按照同窗提供的方案去解決跨域的問題了。但那樣作就好像,咱們賣掉家裏的小汽車,而後出行的時候駕一輛馬車同樣。
這也正是我想告訴你的,爲何要使用註解的緣由:它讓咱們的代碼看起來更簡潔,更有時代的進步感。
註解須要經過@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就可以在運行時對這個類自動加上解決跨域問題的過濾器。
註解是能夠經過反射獲取的。
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]
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)還有不少不少,就再也不一一列舉了。
我想說的是,註解有許多用處,主要有:
下一篇:Java I/O 入門篇
微信搜索「沉默王二」公衆號,關注後回覆「免費視頻」獲取 500G 高質量教學視頻(已分門別類)。