在 Java 中,并非全部的类型信息都能在编译阶段明确,有一些类型信息须要在运行时才能肯定,这种机制被称为 RTTI,英文全称为 Run-Time Type Identification
,即运行时类型识别,有没有一点“知行合一”的味道?运行时类型识别主要由Class类实现。html
Java注解是一系列元数据,它提供数据用来解释程序代码,可是注解并不是是所解释的代码自己的一部分。注解对于代码的运行效果没有直接影响。前端
网络上对注解的解释过于严肃、刻板,这并非我喜欢的风格。尽管这样的解释听起来很是的专业。java
为了缓解你们对“注解”的陌生感,我来讲点有意思的。其实我对“注解”这个词的第一印象并非Java的注解,而是朱熹的名做《四书章句集注》。为何我会有这么大的脑洞呢?由于当我试着去翻译Annotation
这个单词的时候,获得的结果是“注释”而不是“注解”。《四书章句集注》正是朱熹对《大学》、《中庸》、《论语》、《孟子》四书作出的重要的注释。要知道,该书但是明清之后科举考试的题库和标准答案!web
注解(Annotation
)是在 Java SE 5.0 版本中开始引入的概念,同class
和interface
同样,也属于一种类型。不少开发人员认为注解的地位不高,但其实不是这样的。像@Transactional
、@Service
、@RestController
、@RequestMapping
、@CrossOrigin
等等这些注解的使用频率愈来愈高。跨域
为何要使用注解呢?让咱们从另一个问题提及。浏览器
“跨域”这两个字就像一块狗皮膏药黏在每个前端开发者的身上;我也不例外,虽然我并非一个纯粹的前端开发者。安全
跨域问题的出现,源于浏览器的同源策略——限制一个源加载的脚本去访问另一个源的资源,可有效地隔离潜在的恶意文件,是一种重要的安全机制。微信
跨域问题的解决方案也有不少,好比说:网络
1)JSONPapp
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 { @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 高质量教学视频(已分门别类)。