Spring注解之自定义注解入门

前言

  在业务开发过程中,Spring 框架自带的注解并非总能满足形形色色的业务需求,所以我们需要自定义注解来满足特定需求。在定义自己的注解之前,我们先探讨自定义注解的入门知识——Spring为我们提供的元注解和定义注解的基本语法。

注解是什么

  Spring 官方文档对 注解(annotation) 的定义如下:

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

中文意思就是:

注解是一种元数据,可以添加到Java源代码中。 类、方法、变量、参数和包都可以被注解。 注解对被注解代码的操作没有直接影响。

  通过官方描述,可以提炼出如下三条关键信息:

  1. 注解是一种元数据。即注解是属于java的一种数据类型,与类、接口和数组等类似;
  2. 注解用来修饰类、方法、变量、参数和包等;
  3. 注解不会对所修饰的代码产生直接的影响。

自定义注解

  使用关键字@interface定义自己的注解时,自动继承java.lang.annotation.Annotation接口,由编译程序完成其它细节。在定义注解时,不能继承其它的注解或接口,其内部只能定义注解类型元素(annotation type element),可以通过default来声明注解类型元素的默认值。

   注解定义基本语法:

public @interface 注解名

  通俗地讲,注解类型元素可以视作类的成员变量,故本文不作严格区分;其支持的数据类型包括:

  1. 所有基本数据类型(int,float,boolean,byte,double,char,long,short)
  2. String类型
  3. Class类型
  4. enum类型
  5. Annotation类型
  6. 以上所有类型的数组

  Annotation类型里面的成员变量该怎么设定?

  第一,只能设置public或默认(default)这两种访问权限修饰符。例如,String value(); 设为defaul默认类型。

  第二,参数类型只能用八种基本数据类型byte,short,char,int,long,float,double,boolean和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组。例如,String value();这里的参数类型就是String。

  第三,成员变量一般定义为名词。

  第四,如果只有一个成员变量,建议将其命名为Spring默认的 “value()”

  简单的自定义注解示例:

package com.eg.wiener.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义画图注解
 *
 * @author Wiener
 * @date 2021/1/30
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ShapeAn {

    String value();
    String beanName() default "circle";
}

  成员变量的定义与接口中定义抽象方法的语法高度类似,但是,这里可以设定默认值。因此注解类型元素的语法规范不走寻常路,即有属性的特征——可以赋值,又有方法的特征——打上了一对小括号。

  可以通过在注解中使用属性来配置一些参数,然后使用反射获取这些参数,这些注解没有其他特殊的功能,只是简单的代替xml配置的方式来配置一些参数。使用注解来配置参数这在Springboot中得到了热捧,如@Configuration。关于注解的详细使用,请移步《》。

元注解

  元注解的作用就是注解其它注解,即用来说明其它 annotation类型。Java5.0在包java.lang.annotation中定义了4个标准的meta-annotation,分别是 @Target、@Retention、@Documented和@Inherited,其中,前两个比较常见。下面我们看一下每个元注解的作用和相应参数的使用说明。

@Target

  @Target说明了Annotation所修饰的对象范围,默认可以在任何地方使用,也可以指定使用的范围。无规矩不成方圆,约定好规则,防止因乱用而出现稀奇古怪的问题。

  其属性通过ElemenetType类定义,可用的枚举值见下表:

枚举值 功能 示例
CONSTRUCTOR 用于描述构造器
FIELD 用于描述域/属性(包括 enum 实例) @Autowired
LOCAL_VARIABLE 用于描述局部变量
METHOD 用于描述方法 @RequestMapping
PACKAGE 用于描述包
PARAMETER 用于描述参数 @RequestParam
TYPE 用于描述类、接口(包括注解类型) 或enum声明 @Controller

 

@Retention

  @Retention定义了该Annotation的生命周期,表示需要在什么级别保存该注解信息,即:被描述的注解在什么范围内有效。

   元注解 Retention 有唯一的value作为成员变量,它的取值以枚举值的形式定义在java.lang.annotation.RetentionPolicy中,可选参数包括:

  1. SOURCE:源码级别,在源文件中有效。注解只存在于源码中,一般用于和编译器交互,在编译阶段检测代码。如@Override和@SuppressWarings等。

  2. CLASS:字节码级别,在class文件中有效。即注解存在于源码和字节码文件中,主要用于编译时生成额外的文件,如XML,Java文件等,但运行时无法获得。 如mybatis生成实体和映射文件,这个级别需要添加JVM加载时候的代理(javaagent),使用代理来动态修改字节码文件。

  3. RUNTIME:运行时级别,注解存在于源码、字节码和java虚拟机中。在运行时有效,注解处理器此时可以通过反射技术获取到此注解的属性值,从而去做一些运行时的业务逻辑处理。
      

   实际业务开发中,自定义注解生命周期几乎都是采用RUNTIME。

@Documented

  @Documented用于描述自定义的注解应该作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员变量。

@Inherited

   元注解@Inherited 是一个标记注解,她阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的注解类型被用于一个class,则这个annotation将同时被用于该class的子类。@Inherited注解只对那些@Target被定义为ElementType.TYPE的自定义注解起作用。

结束语

  老铁们,因楼兰胡杨能力有限,文中难免出现瑕疵,如果发现bug或者有更好的idea,请在文章下方留言!

Reference

posted @ 2021-01-30 18:38  楼兰胡杨  阅读(2917)  评论(0编辑  收藏  举报