01 什么是注解?
Java 注解(Annotation),相信大家没用过也见过。个人理解,注解就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,从而做相对应的处理。
注解跟注释很像,区别是注释是给人看的(想想自己遇到那些半句注释没有的业务代码,还是不是很难受?);而注解是给程序看的,它可以被编译器读取。
1.1 注解的作用
注解大多时候与反射或者 AOP 切面结合使用,它的作用有很多,比如标记和检查,最重要的一点就是简化代码,降低耦合性,提高执行效率。比如我司就是通过自定义注解 + AOP 切面结合,解决了写接口重复提交的问题。
简单描述下我司防止重复提交注解的逻辑:请求写接口提交参数 —— 参数拼接字符串生成 MD5 编码 —— 以 MD5 编码加用户信息拼接成 key,set Redis 分布式锁,能获取到就顺利提交(分布式锁默认 3 秒过期),不能获取就是重复提交了,报错。
如果每加一个写接口,就要写一次以上逻辑的话,那程序员会疯的。所以,有大佬就使用注解 + AOP 切面的方式解决了这个问题。只要在写接口 Controller 方法上加这个注解即可解决,也方便维护。
1.2 注解的语法
以我司防止重复提交的自定义注解,介绍下注解的语法。它的定义如下:
// 声明 NoRepeatSubmit 注解 @Target(ElementType.METHOD) // 元注解 @Retention(RetentionPolicy.RUNTIME) // 元注解 public @interface NoRepeatSubmit { /** * 锁定时间,默认单位(秒) */ long lockTime() default 3L; }
Java 注解使用 @interface
修饰,我司的 NoRepeatSubmit
注解也不例外。此外,还使用两个元注解。其中 @Target
注解传入 ElementType.METHOD
参数来标明 @NoRepeatSubmit
只能用于方法上,@Retention(RetentionPolicy.RUNTIME)
则用来表示该注解生存期是运行时,从代码上看注解的定义很像接口的定义,在编译后也会生成 NoRepeatSubmit.class
文件。
1.3 注解的元素
定义在注解内部的变量,称之为元素。注解可以有元素,也可以没有元素。像 @Override
就是无元素的注解,@SuppressWarnings
就属于有元素的注解。
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
带元素的自定义注解:
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface NoRepeatSubmit { /** * 锁定时间,默认单位(秒) */ long lockTime() default 2L; }
1.3.1 注解元素的格式
注解的元素格式如下:
// 基本格式 数据类型 元素名称(); // 带默认值 数据类型 元素名称() default 默认值;
1.3.2 注解元素的数据类型
注解元素支持如下数据类型:
所有基本类型(int,float,boolean,byte,double,char,long,short) String Class enum Annotation 上述类型的数组
声明注解元素时可以使用基本类型但不允许使用任何包装类型,同时注解也可以作为元素的类型,也就是嵌套注解。
1.3.3 编译器对元素默认值的限制
遵循规则:
- 元素要么具有默认值,要么在使用注解时提供元素的值。
- 对于非基本类型的元素,无论是在源代码中声明,还是在注解接口中定义默认值,都不能以 null 作为值。
1.4 注解的使用
注解是以 @注释名 的格式在代码中使用,比如:以下常见的用法。
public class TestController { // NoRepeatSubmit 注解修饰 save 方法,防止重复提交 @NoRepeatSubmit public static void save(Object o){ // 保存逻辑 } // 一个方法上可以有多个不同的注解 @Deprecated @SuppressWarnings("uncheck") public static void getDate(){ } }
在 save 方法上使用 @NoRepeatSubmit
(我司自定义注解),加上之后,编译期会自动识别该注解并执行注解处理器的方法,防止重复提交;
而对于 @Deprecated
和 @SuppressWarnings (“uncheck”)
,则是 Java 的内置注解,前者意味着该方法是过时的,后者则是忽略指定的异常检查。