在我们使用Spring开发JAVA的程序或多或少都有用到过注解(即@XXXXX),一般在类的定义、方法定义,属性定义上方。
JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型。该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的class文件和一个注解处理工具组成。
Annotation并不直接影响代码的语义,但是他可以被看做是程序的工具或者类库。它会反过来对正在运行的程序语义有所影响。
Annotation可以冲源文件、class文件或者在运行时通过反射机制多种方式被读取
为什么学习注解
- 能读懂别人写的代码,特别是底层框架相关的代码
- 让编程更加简介,代码更加清晰
- 装逼利器
注解分类
- 按照运行机制分
- 源码注解:注解只在源码中存在,编译成.class文件时丢失
- 编译时注解:在源码和.class文件中都存在,运行时丢失
- 运行时注解:源码、class文件、运行时都存在,甚至影响运行逻辑
- 按照来源划分
- JDK自带注解:(Java目前只内置了三种标准注解:@Override、@Deprecated、@SuppressWarnings,以及四种元注解:@Target、@Retention、@Documented、@Inherited)
- 第三方注解:接触最多,使用最多的注解Spring、Mybatis等
- 自定义注解:咱自己写的注解
- 按照功能划分
- 元注解:注解的注解(JAVA自带)
- 一般注解
JAVA自带注解
注解 | 用途 |
---|---|
@Override | 覆盖或重写父类的方法 |
@Deprecated | 表示该方法已经过时了。(当方法或是类上面有@Deprecated注解时,说明该方法或是类都已经过期不能再用,但不影响以前项目使用,提醒你新替代的方法或是类。如果程序员不小心使用了它的元素,那么编译器会发出警告信息。) |
@SuppressWarnings | 表示忽略指定警告,比如@Suppvisewarnings(“Deprecation”) |
常见第三方注解
包 | 注解 | 用途 |
---|---|---|
Spring | @Autowired | 自动注册成员变量 |
Spring | @Service | 业务层定义 |
Spring | @Repository | 持久层定义/数据访问组件(一般为自定义注解DAO层例如@MyBatisDao) |
Spring | @Controller | 控制层定义 |
Spring | @Component | 中立类进行注解/泛指组建 |
Mybatis | @Insert | 直接配置SQL语句 |
Mybatis | @Select | 直接配置SQL语句 |
Mybatis | @Update | 直接配置SQL语句 |
Mybatis | @Delete | 直接配置SQL语句 |
Mybatis | @InsertProvider | 通过SQL工厂类及对应的方法生产SQL语句(最常用) |
Mybatis | @UpdateProvider | 通过SQL工厂类及对应的方法生产SQL语句(最常用) |
Spring在启动时,自动扫描机制会自动扫描带有这些注解的类放到Spring容器中
自定义注解
自定义注解使用必须是@interface标记(明确这不是一个接口,它是使用@interface关键字定义的一个注解),事例代码如下:
/**
* @Project : ${PROJECt_NAME}
* @Package Name : com.codeyi.annotation.impl
* @Author Codeyi on 2018-02-07.
* @Creation Date: 2018年02月07日 14:31
* 自定义注解
*/
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.LOCAL_VARIABLE,ElementType.PACKAGE,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {
/*
①.成员类型是受限制的,合法的类型包括基本的数据类型以及String,Class,Annotation,Enumeration等。
②.如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=)。
③.注解类可以没有成员,没有成员的注解称为标识注解。
*/
int id() default 0;
String name();
}
- @Target是这个注解的作用域
参数 | 说明 |
---|---|
CONSTRUCTOR | (构造方法声明) |
FIELD | (字段声明) |
LOCAL VARIABLE | (局部变量声明) |
METHOD | (方法声明) |
PACKAGE | (包声明) |
PARAMETER | (参数声明) |
TYPE | (类接口) |
- @Retention是它的生命周期
参数 | 说明 |
---|---|
SOURCE | (只在源码显示,编译时丢弃) |
CLASS | (编译时记录到class中,运行时忽略) |
RUNTIME | (运行时存在,可以通过反射读取) |
- @Inherited是一个标识性的元注解,它允许子注解继承它。
- @Documented,生成javadoc时会包含注解。
参数
- 成员类型是受限制的,合法的类型包括基本的数据类型以及String,Class,Annotation,Enumeration等。
- 如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=)。
- 注解类可以没有成员,没有成员的注解称为标识注解。
注解的使用
@<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,…)
上面事例我们自定义了一个注解,下面我们就来尝试使用自定义注解完成一些我们想要的功能
**
* @Project : ${PROJECt_NAME}
* @Package Name : com.codeyi.annotation
* @Author Codeyi on 2018-02-07.
* @Creation Date: 2018年02月07日 14:38
*/
@MyAnnotation(id = 1, name = "MethodTest")
public class Test {
@MyAnnotation(id = 1, name = "A")
public void A() {
}
@MyAnnotation(id = 2, name = "B")
public void B() {
}
@MyAnnotation(id = 3, name = "C")
public void C() {
}
public static void main(String[] args) {
try {
// 使用类加载器加载类
Class myClasses = Class.forName("com.codeyi.annotation.Test");
//获取所有的方法
Method[] ms = myClasses.getMethods();
// 找到类上面的注解
boolean isExist = myClasses.isAnnotationPresent(MyAnnotation.class);
// 上面的这个方法是用这个类来判断这个类是否存在Description这样的一个注解
if (isExist) {
// 拿到注解实例,解析类上面的注解
MyAnnotation d = (MyAnnotation) myClasses.getAnnotation(MyAnnotation.class);
System.out.println(d.name());
}
// 遍历所有的方法
for (Method m : ms) {
// 找到类上面的注解
isExist = m.isAnnotationPresent(MyAnnotation.class);
// 上面的这个方法是用这个类来判断这个类是否存在MyAnnotation这样的一个注解
if (isExist) {
// 拿到注解实例,解析类上面的注解
MyAnnotation myAnnotation = m.getAnnotation(MyAnnotation.class);
System.out.print(myAnnotation.id() + "-" + myAnnotation.name());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
测试结果
MethodTest
2-B3-C1-A
Process finished with exit code 0
完美,那有这些了我们能做些什么呢?大家可以想想,很精彩的哦欢迎找本人讨论。