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)还有很多很多,就不再一一列举了。
05)最后
我想说的是,注解有许多用处,主要有:
提供信息给编译器: 编译器可以利用注解来探测错误和警告信息。
编译阶段时的处理: 软件工具可以利用注解信息来生成代码、HTML文档。
运行时的处理: 某些注解可以在程序运行的时候接受代码的提取。