在 Spring 中,大家会经常用到各种注解。在加上这些注解后,我们的代码就有了很多神奇的功能。
比如,下面这个类只用了两个注解:@Controller
和@RequestMapping
,你就能在浏览器上访问 index() 方法。
@Controller
@RequestMapping("/")
public class IndexController {
@RequestMapping(value = "index")
public String index() {
return "index";
}
就这么简单的功能,你如果用 Java 自带的 Servlet,要写的代码最少也会翻倍。
这就是注解的威力。
什么是注解?
注解相当于给代码贴标签,你可以写代码来读取这些标签信息,做特殊的处理,从而实现更丰富的功能。
比如,下面这个例子,方法加上了@Override
注解,Java 就会做出处理,覆盖父类toString()
方法。
public class User {
// 覆盖父类的toString() 方法
@Override
public String toString() {
return "这是一个用户对象";
}
}
注解大致分成三类:JDK内置注解、第三方注解、自定义注解。
JDK内置注解,就是JDK自带的注解。比如,@Override
表示用子类的方法覆盖父类的方法。
public class UserOrderNoGen extends OrderNoGen {
// 这个注解表示:覆盖父类的 genOrderNo() 方法
@Override
public String genOrderNo() {
// 省略无数代码
}
}
第三方注解,就是第三方框架提供的注解。比如,Spring 框架提供的@Controller
和@RequestMapping
,我重新贴下文章开头的例子。
@Controller
@RequestMapping("/")
public class IndexController {
@RequestMapping(value = "index")
public String index() {
return "index";
}
}
自定义注解,就是我们自己写的注解。比如,我创建了一个注解@ExcelField
,可以放在类上,表示这个类是 Excel 导出模板。
// Excel导出模板
public @interface ExcelField {
// 省略无数代码
}
// 用户信息表
@ExcelField
public class UserInfoField {
// 省略无数代码
}
此外,注解的级别非常高,和类、接口、枚举是同一级别的,有自己的一套写法。我们先看看注解怎么写吧~
写注解-加上元注解
所谓元注解,就是加在注解上的注解。
如果你要自定义注解,有两个元注解非常重要,几乎是必须加上的,分别是:@Target
、@Retention
。
@Target
是限制注解的使用范围,表示这个注解能用在什么地方,它的取值范围在枚举 ElementType 里。 如果用@Target
来限制注解的使用范围,那么超出这个范围,代码就会报错。
当然,你也可以不加@Target
注解,这代表不限制注解的使用范围,你可以随便放,不会报错。
@Retention
是注解的保留策略,它的取值范围在枚举 RetentionPolicy 里。 注解的保留策略有 3 种,分别是:SOURCE、CLASS、RUNTIME。
SOURCE:注解只在源码中出现,在经过编译后,注解会被丢弃,不会出现在 class 文件中;
CLASS:经过编译后,注解会保留在 class 文件中,但在 JVM 加载时会忽略注解;
RUNTIME:在 JVM 加载时,注解会被加载到 JVM 内存,所以使用反射来读取注解;
但说实话,在这三种保留策略中,SOURCE 策略还不如多写两行注释;CLASS 策略就是让你看看,没太大作用;只有 RUNTIME 模式,才能真正发挥注解的作用。
注解的结构-成员变量
注解支持成员变量,成员变量可以用这些类型:
- 基本数据类型
- String
- 枚举类型
- 注解类型
- Class类型
- 以上类型的一维数组
这块我们没必要花太多时间,在用到的时候,再回来瞄一下就好。
最后,我们来看下注解是怎么起作用的。
注解是怎么起作用的?
注解想发挥作用,有三个要素:定义、使用、读取。
如果你用的是JDK内置注解,或者是第三方注解,那么只要使用就行,不用管定义和执行。
比如,Spring 框架会把注解类、读取注解的代码藏起来,我们只要会用就行,不用管太多。你可以看下面这个例子。
// 使用 Spring 的注解,把这个类交给 Spring 容器管理
@Service
public class UserService {
}
相比起来,自定义注解会更加复杂。自定义注解想发挥作用,我们需要自己定义注解,自己使用注解,最后再写代码读取。
有时候,我们要用自定义注解,才能实现一些功能。
比方说,这是一个 Excel 导出的功能,你得先创建注解@ExcelField
,然后把@ExcelField
加到模板类的成员变量上,最后用工具类ExcelExporter
来导出 excel 表格。
在注解的三要素中,定义注解是比较容易的,但使用、读取注解跟业务绑定很深,一两句话很难讲清楚,我们以后会结合实际案例来看。
写在最后
注解相当于给代码贴标签,你可以写代码来读取这些标签信息,做特殊的处理,从而实现更丰富的功能。
不过,注解想发挥作用,有三个要素:定义、使用、读取。但我们很少试过自定义注解,没有经历过定义—>使用—>读取的过程,就搞不清楚注解是怎么回事,更别提用好注解了。
换句话说,想要用好注解,你得看更多的实际案例,写更多的代码。