Java注解浅谈
注解定义(来自百度百科):指示编译器如何对待您的自定义 Annotation,预设上编译器会将Annotation资讯留在class档案中,但不被虚拟机器读取,而仅用于编译器或工具程式运行时提供资讯。
随着零配置的流行,注解的使用也越来越大众化,注解的学习也很有必要。最近学习了下Spring的几个注解,这里与大家分享下自己对注解的理解。
首先我们来看下@Controller这个注解的源码:
|
1
2
3
4
5
6
7
8
9
10
|
package org.springframework.stereotype;// 省略import以及一些注释@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { String value() default ""; } |
不难看出,注解的关键字是@interface,很像一个接口,是不能够实例化的,然而我们在实际使用的时候,通常通过反射机制,得到注解接口的一个实例,进行逻辑处理,后面的样例会看到这种使用。(命名为value的注解方法有一个比较特别的用法,后面会提到。)
它的主体部分,定义了一个value()方法,实际上,它不仅是一个方法定义,也是注解的一个属性定义。我们使用注解进行标注的时候,是这样的:@Controller(value="MyController"),而在解析判断时,会通过controller.value()方法,得到这个具体的value值"MyController"。再看看value()后面跟着的default,这个default表面上的意思是默认值为某个值,实际上还有一个功效,表示value属性可以不输入。因此我们使用Controller的时候,可以直接@Controller这样使用,不需要给定value,若去掉default,不指定value,会编译失败。
再看看这个注解定义前面的注解。@Target,顾名思义,就是指定当前注解使用的作用目标。如果大家使用Eclipse等开发工具,将鼠标放到ElementType.TYPE处,会看到其注释内容,大致意思是说,这个注解要放到类、接口或者枚举类型声明的地方。也就是说,我们的@Controller注解只能放到类、接口、枚举定义前面,不能放到成员属性、方法、参数等地方。大家可以跟进ElementType,这里定义了“TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE”这么些枚举,根据注释(或者从枚举英文含义也不难猜测。这也从另一方面说明,合理的命名有助于提高代码可读性)很容易知道,注解可以实现注解到类文件的各个地方。
@Retention(RetentionPolicy.RUNTIME),Retention可能不好猜,但是看到后面的RUNTIME,精神一震,猜测应该是和“运行时”有关。再查看API帮助文档,Retention“指示注释类型的注释要保留多久”。这个保留多久,就要和RetentionPolicy(Retention的策略)配合使用了。Controller的Retention策略是运行时的,这样在代码运行时,可以通过反射获得这个注解。这中策略的好处,具体实现案例可以参考Spring的bean扫描以及AOP拦截的注解实现(Spring配置文件的component-scan base-package配置后,Spring bean工厂会逐个扫描包下所有类,根据其注解来生成相关bean。大家可以分析@Component、@Service、@Autowired等,其策略也是RUNTIME的)。
@Documented,如果需要通过javadoc工具文档化时,会判断这个注解,从而保留注释(具体没有实践过,不瞎诌了)。
@Component这个注解放在Controller上面,可以看做“Controller同样具有Component的作用”。实际上,目前的Spring扫描bean的时候,只认准了Component注解的。我们会看到,@Service、@Repository上面也有@Component注解。说道这里又不得不岔开下话题,来比照下@Service、@Controller、@Repository、@Component这几个注解的区别了。理论上讲,@Service是注解提供服务性质的bean上的,@Controller是注解MVC的C上的,@Repository是存储层bean使用的,而@Component是注解不区分服务还是控制的bean。实际上,这几类注解最终在Spring里都是以bean形式放到bean工厂里,没有什么区别对待。因此Spring扫描bean的时候,一律以@Component作为标记,@Service、@Controller、@Repository可以看做是一种功能预留:将来可能会对这三种注解的类做bean初始化时,做额外的增强型处理。
拆分了注解后,我们会发现注解也没那么神秘。接下来可以设计个属于自己的注解了:
自定义注解:
|
1
2
3
4
5
6
7
|
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String name() default "";// 名字 Class<!--?--> procClass() default Object.class;// 处理类的类型 String value() default "";// 比较特别 } |
注解使用类:
|
1
2
3
|
// 标注时,name、procClass和value当做属性直接设值@MyAnnotation(name="Lily",procClass=TestAnnotation.class,value="abc")public class SomeClass{} |
测试:
|
1
2
3
4
5
6
7
8
9
|
// 通过反射获得注解SomeClass some = new SomeClass();// 得到MyAnnotation的一个实例MyAnnotation annotationClass = some.getClass().getAnnotation(MyAnnotation.class);// 判断逻辑里,name和procClass当做方法用以调用String annotationName = annotationClass.name();System.out.println(annotationName);Class<!--?--> clazz = annotationClass.procClass();System.out.println(clazz); |
上面定义的value()在使用时,如果不设置其它属性,只设置value,可以这样简写:@MyAnnotation("abc"),此时,value的值为"abc",其它取默认值。(不局限String类型。当然,MyAnnotation的其它方法需要提供default值。)
以上是一个简单的样例,大家可以修改Target,增减方法,实现自己需要的注解。
最后,欢迎大家拍砖。
Java注解浅谈的更多相关文章
- 【推荐】JAVA基础◆浅谈3DES加密解密
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- JAVA随笔----浅谈lombok注解
在Java开发中,注解可谓是帮了大忙.注解的使用帮助我们简化了代码,让代码更加简洁.今天就来谈谈常用的Lombok注解. lombok注解文档 lombok官方下载地址 先看一下lombok支持的一些 ...
- Java注解一谈
阅读目录 1.元注解 2.自定义注解 3.注解处理器 android注解框架解析 我们经常会在java代码里面看到:“@Override”,“@Target”等等样子的东西,这些是什么? 在java里 ...
- java多线程浅谈
当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 分这几种情况: 1.其他方法前是否加了synchronized关键字,如果没加,则能. 2 ...
- Java:浅谈InputStream的close方法
原则:最好在任何时候使用InputStream或者OutputStream的时候,在finally中调用close()方法,显式关闭. 一个典型的示例 InputStream in = null; t ...
- 【JAVA】浅谈java内部类
一.什么是内部类? 到底什么是内部类呢?通俗的讲,就是在类内部定义的类,包括定义在一个类的方法外面.方法里面或者代码块中. 二.为什么要使用内部类? 为什么我们要不走寻常路,把一个类定义在另一个类的内 ...
- 【JAVA】浅谈java枚举类
一.什么情况下使用枚举类? 有的时候一个类的对象是有限且固定的,这种情况下我们使用枚举类就比较方便? 二.为什么不用静态常量来替代枚举类呢? public static final int SEASO ...
- java - 异常浅谈
java提供异常处理机制中,可以分为RuntimeException和checked Exception两种. RuntimeException 是运行时异常,是程序本身无法解决的.例如,对于一个用户 ...
- 通过Java代码浅谈HTTP协议
最近刚看了http协议,想写点东西加深一下理解,如果哪儿写错了,请指正. 1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(W ...
随机推荐
- 关闭AnyConnect登录安全警告窗口
一.问题描述:使用AnyConnect client连接时,如何关闭的安全警告窗口? 二.原因分析: AnyConnect Server(ASA)和AnyConect client(PC)上没有受 ...
- 实际中可能遇到的NAT问题(IPsec)
一.背景介绍:一般我们在实际网络中不是IPSec VPN的时候,都是边界设备连接Internet,然后两个边界设备通过Internet去实现互通,建立VPN,但是,有的运营商在分配IP地址的时候,给我 ...
- kaggle赛题Digit Recognizer:利用TensorFlow搭建神经网络(附上K邻近算法模型预测)
一.前言 kaggle上有传统的手写数字识别mnist的赛题,通过分类算法,将图片数据进行识别.mnist数据集里面,包含了42000张手写数字0到9的图片,每张图片为28*28=784的像素,所以整 ...
- Update(Stage4):spark_rdd算子:第2节 RDD_action算子_分区_缓存:缓存、Checkpoint
4. 缓存 概要 缓存的意义 缓存相关的 API 缓存级别以及最佳实践 4.1. 缓存的意义 使用缓存的原因 - 多次使用 RDD 需求: 在日志文件中找到访问次数最少的 IP 和访问次数最多的 IP ...
- php环境一键升级脚本
因为要解析PHP页面需要配置相应的PHP环境,而系统本身的php版本又大多不合适.网上那种一键lamp和lnmp的脚本很多,但是这样一来自己能够定制的空间则少了.所以我自己编写了个门用于安装php环境 ...
- 刚下载好的 vscode 不能运行,一片黑 以及终端不能输入 解决办法
1.鼠标右键vscode快捷方式点击属性,选择兼容性,勾选以兼容模式运行,下拉列表调整为windows vista (service pack 1)即可解决. 2.如果打开终端不能输入命令,首先点击属 ...
- vue.js ②
1.Vue实例的生命周期钩子 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听.编译模板.将实例挂载到 DOM 并在数据变化时更新 DOM 等.同时在这个过程中也会运行 ...
- Jmeter-maven-plugin github 版本插件变更历史
https://github.com/jmeter-maven-plugin/jmeter-maven-plugin/blob/master/CHANGELOG.md
- Python 基础之面向对象之装饰器@property
一.定义 装饰器@property可以把方法变成属性使用作用: 控制类内成员的获取 设置 删除获取 @property设置 @自定义名.setter删除 @自定义名.deleter 二.具体实现 1. ...
- 基于Goolgle最新NavigationDrawer实现全屏水平平移
常见实现App 上面侧边栏菜单之前使用SlidingMenu,现在发现Goolgle原生NavigationDrawer也挺好用.但是细心的开发者们发现NavigationDrawer没有类似Slid ...