- 目录
1. 前言
- 注解为我们提供了形形色色的功能,依赖注入,记录日志,自动创建setter,getter方法等等。但究竟什么是注解?这些功能是怎么实现的?在开发中我们有没有需求需要用到自定义注解来实现自己的功能?如果有,我们要怎么创建我们自己的注解?
2. 注解的原理
- 注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java常量池。
3. 创建自定义注解
- 创建@Spongebob 自定义注解
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD,ElementType.FIELD})
@Inherited
public @interface Spongebob {
String value() default "假装说点什么...";
}
- 注解的类型为@interface,所有的Annotation 会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口。
- 我们看到我在Spongebob 注解上还加了4个注解,这四个注解比较特殊叫元注解
3.1 元注解
元注解就是可以加在注解上的注解,元注解不可以自定义。下面我来一一说明一下这四个元注解的作用。
@Documented
如果添加了@Documented,注解将能够在JavaDoc中展现。
@Retention
描述注解的生命周期,即什么时候注解是有效
类型 | 说明 |
RetentionPolicy.SOURCE | 在源文件中有效 |
RetentionPolicy.CLASS | 在 class 文件中有效 |
RetentionPolicy.RUNTIME | 在运行时有效 |
@Inherited
是否允许子类继承该注解。即@Spongebob 如果修饰了类A,那么类A的子类类B也会默认被@Spongebob 修饰。
@Target
表示该注解用于什么地方。默认值为任何元素,表示该注解可以用于任何地方。注解值可以多选,如果建注解用到了未定义的地方,编译会报错。
类型 | 说明 |
CONSTRUCTOR | 可用于描述构造器 |
FIELD | 用于描述域(属性) |
LOCAL_VARIABLE | 用于描述局部变量 |
METHOD | 用于描述方法 |
PACKAGE | 用于描述包 |
PARAMETER | 用于描述参数 |
TYPE | 用于描述类或接口(甚至 enum ) |
- 这四个元注解都是可选的,不一定需要添加
- 接着我们看到我给@Spongebob 添加了一个参数value,并设置了默认值。关于参数也有一些要求。
3.2 注解参数
- 参数成员只能用public 或默认(default) 这两个访问权修饰
- 参数成员只能用基本类型byte、short、char、int、long、float、double、boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这些类型的数组类型.
- 可以为参数设置默认值
- 如果注解只有一个参数,在使用时可以直接去掉参数名赋值
@Spongebob("你说我好看")
- 如果注解有多个参数,必须通过名称赋值,并以‘,’分割
@Spongebob(value="你说我好看",xx="xxx")
- 如果参数类型是数组类型,使用方法
@Spongebob({"你说我好看",“却是吃了吐”})
- 如果参数类型是数组类型,但是只有一个数据,可以去掉大括号赋值
@Spongebob("快乐都是他们的”)
- 如果想要获取到解信息,必须通过反射机制,通过反射获取被修饰的类或方法对象,便可以获取到修饰的注解对象信息。
4. 使用@Spongebob注解
@RestController
@RequestMapping("/index")
public class IndexController {
@Autowired
LoginService loginService;
@Spongebob
@RequestMapping("/testAnnotation")
public String testAnnotation(String name,String password){
String info= loginService.login(name,password);
System.out.println(info);
return info;
}
这里的@Spongebob没有任何实际的功能,我这里加个@Spongebob注解是为了表达这个testAnnotation方法是名为Spongebob的人开发的。
这里我们可以看出注解最原始的用处就是一个标签,为方法加一个标签,为类加一个标签,为字段属性加一个标签,表明这个方法或这个类有特殊含义。