前言:
在看到网络上对注释的解释之后,就觉得很专业,有所感悟,然后就想着记录下来。
Java 注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注释对于代码的运行效果没有直接影响。
注解(Annotation)是在 Java SE 5.0 版本中开始引入的概念,同 class 和 interface 一样,也属于一种类型。就在最开始的时候我还认为注解的地位不高,但是最终发现不是这样子的。像 @Transaction、@Service、@RestController、@RequestMapping、@CrossOrigin 等等这些注解的使用频率在我后面的学习当中,越来越高。
为什么要使用注解呢?
让我们从另外一个问题说起。
“跨域” 这两个字就像一块狗皮膏药粘在每一个开发者的身上;而对于蚊子这样一个小菜鸡来说,更是如此。
跨域问题的出现,源于浏览器的同源策略—-限制一个源加载的脚本去访问另一个源的资源,可有效地隔离潜在的恶意文件,是一种重要的安全机制。
跨域问题的解决方案也有很多,比方说:
1)JSONP
2)Nginx 代理
3)“跨域资源共享”(Cross-origin resource sharing),简称 CORS,可以说是处理跨域问题的标准做法。
记得第一次遇到跨域问题的时候,我特意向学长请教了一个解决方案,他告诉我的答案如下:
第一步,在 web.xml 添加 filter。
1 | <filter> |
第二步,实现 WebContextFilter 类。
1 | public class WebContextFilter implements Filter { |
看到这样的解决方案,我其实蛮头痛的,因为这样的一个跨域问题,居然需要这么多的代码,头痛.jpg
我对这样的解决方案并不是很满意。于是决定好好的研究一下,然后花费了大概一天多的时间吧,我终于搞清楚了 “跨域” 问题,以及它的标准解决返港 CORS。并且找到了一个简介的解决方案----@CrossOrigin,只要在 Controller 类上加上这个注解,就可以轻松的解决跨域问题。
代码如下:
1 |
|
如果没有找到 @CrossOrigin 这个注解,我估计就真的会按照学长的方案去解决这个跨域问题。但那样做的话,就感觉很繁琐、冗杂。
这也正是我第一个体会到的,为什么要使用注解的原因:它会让我们的代码看起来更加简洁、更有时代的进步感。
该如何定义注解呢?
注解需要通过 @interface 关键字(形式和接口非常的相似,只是前面多了一个 @ )进行定义。我们可以打开 @CrossOrigin 的源码来看一下。
1 | ({ ElementType.METHOD, ElementType.TYPE }) |
从上面的代码可以看出来,“注解” 真的很 “注解”,除了注释多和 “元注解” 多之外,真没别的了。
“元注解”?什么是 “元注解” 呢?
“元注解” 是用来注解(动词)注解(名词)的注解(名词)。emmmmmm~ 这个说法我自己都很汗颜。。。。。。
而 @Target、@Retention、@Documented 就是所谓的元注解。
1)@Tartget
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 中。
当我们了解了元注解的概念之后,再回头看 @CorssOrigin 的源码,就会觉得清晰了许多。
如果能够细致的读一读源码中的注释,就会看到 WebContextFilter 类中出现的关键字,比如 Access-Control-Allow-Origin、Access-Control-Allow-Headers、Access-Control-Methods。也就是说,当我们通过 @CrossOrigin 对 Controller 类注解后,Spring MVC 就能够在运行时对这个类自动加上解决跨域问题的过滤器。
注解可以反射吗?
注释是可以通过反射获取的。
1)可以通过 Class 对象的 isAnnotationPresent() 方法判断该类是否应用了某个指定的注解。
2)通过 getAnnotation() 方法来获取注解对象。
3)当获取到注解对象后,就可以获取使用注解时定义的属性值。
实例如下:
1 | "https://www.baidu.com", allowedHeaders = "accept,content-type", methods = { RequestMethod.GET, RequestMethod.POST }) (origins = |
注解经常用在哪里呢?
1)@Transactional:Spring 为事务管理提供的功能支持。
2)@Service:Spring 在进行包扫描的时候,会自动将这个类注册到 Spring 容器中。
3)@RestController:是在 @ResponseBody 和 @Controller 的组合注解。
也就是说,下面这段代码与之后的一段代码等同:
1 |
|
4)@ResquestMapping:Spring Web 应用程序中常用的注解之一,将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上。
5)@Select:MyBatis 提供的查询语句注解。示例如下:
1 | "select * from city") ( |
。。。。后面还有很多,就不一一举例了
最后,注解还有很多用处,主要有:
- 提供信息给编译器:编译器可以利用注解来探测错误和警告信息。
- 编译阶段时的处理:软件工具可以利用注解信息来生产代码、HTML文档。
- 运行时的处理:某些注解可以在程序运行的时候接受代码的提取。