【SpringMVC】自定义注解(一)

简介: 【SpringMVC】自定义注解

449cbaaf1a4648b3b858e961b0f1006c.jpg

🎉🎉欢迎来到我的CSDN主页!🎉🎉

🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚

🌟在这里,我要推荐给大家我的专栏《Spring MVC》。🎯🎯

🚀无论你是编程小白,还是有一定基础的程序员,这个专栏都能满足你的需求。我会用最简单易懂的语言,带你走进Spring MVC的世界,让你从零开始,一步步成为JAVA大师。🚀🏆

🌈让我们一起在SpringMVC的世界里畅游吧!🌈🌈

👉点击这里,就可以查看我的主页啦!👇👇

Java方文山的个人主页

🎁如果感觉还不错的话请记得给我点赞哦!🎁🎁

💖期待你的加入,一起学习,一起进步!💖💖

一、前言

1.1.什么是注解

Annontation是Java5开始引入的新特征,中文名称叫注解。

它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观、更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。

 

1.2.注解的用处

  • 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等
  • 跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2 依赖注入,未来java 开发,将大量注解配置,具有很大用处;
  • 在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

1.3.注解的原理

注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。

 

二、注解的分类

2.1.JDK基本注解

2.1.1.@Override

     java.lang.Override 是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重写了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java 编译器将以一个编译错误来警示。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@Override是给javac(java编译器)看的,编译完以后就@Override注解就没有价值了,@Override注解在源代码中有用,编译成.class文件后@Override注解就没有用了,因此@Override的Retention的属性值是RetentionPolicy.SOURCE。

 

2.1.2.@SuppressWarnings

@SuppressWarnings是给javac(java编译器)看的,编译器编译完java文件后,@SuppressWarnings注解就没有用了,所以@SuppressWarnings的Retention的属性值是RetentionPolicy.SOURCE。

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

2.2.JDK元注解

看完以上的JDK基本注解你是否更蒙了!?为什么注解类里面还有注解,那其实是JDK的元注解。

所有元注解定义在java.lang.annotation包下面,其中Annotation是注解的基本接口,所有的注解都继承这个接口

java.lang.annotation 提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要使用到元注解)

2.2.1.@Retention

指定注解的生命周期(源码、class文件、运行时)或是称作定义注解的保留策略。

该元注解中有三个属性值

@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含

@Retention(RetentionPolicy.CLASS) //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得

@Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时可以通过反射获取到

下面我用别人写好的注解来给大家演示:

@Retention(RetentionPolicy.SOURCE)

@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
public @interface Slf4j {
    java.lang.String topic() default "";
}

这是Slf4j的注解,用了元注解@Retention(RetentionPolicy.SOURCE) ,说明该注解仅存在于源码中,class文件中不包括我们来看看。

确实如此我们的源码中有@Slf4j但是字节码文件中却没有,这就是该元注解以及属性的作用。

用到最多的还是@Retention(RetentionPolicy.RUNTIME),下面我们来看一下该元注解的使用。

@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Documented
@org.springframework.web.bind.annotation.Mapping
public @interface RequestMapping {
    java.lang.String name() default "";
    @org.springframework.core.annotation.AliasFor("path")
    java.lang.String[] value() default {};
    @org.springframework.core.annotation.AliasFor("value")
    java.lang.String[] path() default {};
    org.springframework.web.bind.annotation.RequestMethod[] method() default {};
    java.lang.String[] params() default {};
    java.lang.String[] headers() default {};
    java.lang.String[] consumes() default {};
    java.lang.String[] produces() default {};
}

这是注解RequestMapping,因为@Retention中所填写的是RetentionPolicy.RUNTIME,所以被该注解所修饰的类/方法/属性就可以在运行时可以通过反射获取到。

2.2.2.@Target

指定被修饰的Annotation指定注解使用的目标范围(类、方法、字段等)。

刚刚在上面我们提到了一个关键信息,被@RequestMapping注解所修饰的类/方法/属性,那我们怎么知道又怎么决定那些注解可以用于类/方法/属性呢?就是通过元注解@Target来决定。

元注解 作用目标范围
@Target(ElementType.TYPE)    接口、类
@Target(ElementType.FIELD)    属性
@Target(ElementType.METHOD)     方法
@Target(ElementType.PARAMETER)  方法参数
@Target(ElementType.CONSTRUCTOR) 构造函数
@Target(ElementType.LOCAL_VARIABLE)  局部变量
@Target(ElementType.ANNOTATION_TYPE)  注解
@Target(ElementType.PACKAGE) 

注意:可以指定多个位置,例如:

@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上面使用

不相信的同学可以回过头看看上面的代码中有没有Target哦!

2.2.3.@Inherited

指定子类可以继承父类的注解,只能是类上的注解,方法和字段的注解不能继承。即如果父类上的注解是@Inherited修饰的就能被子类继承。

当父类上的注解被@Inherited修饰时,子类可以继承该注解。下面是一个示例代码来演示这个概念:

import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface MyAnnotation {
    String value();
}
@MyAnnotation("我是父类的注解")
class ParentClass {
}
class ChildClass extends ParentClass {
}
 class Main {
    public static void main(String[] args) {
        // 获取父类上的注解
        MyAnnotation parentAnnotation = ParentClass.class.getAnnotation(MyAnnotation.class);
        System.out.println("获取父类上的注解: " + parentAnnotation.value());
        // 获取子类上的注解
        MyAnnotation childAnnotation = ChildClass.class.getAnnotation(MyAnnotation.class);
        System.out.println("获取子类上的注解: " + childAnnotation.value());
    }
}

如果我们没有用@Inherited会怎么样呢?

会抛出java.lang.NullPointerException异常,因为子类无法继承父类的注解。

相关文章
|
6月前
|
前端开发 Java 编译器
SpringMVC自定义注解---[详细介绍]
SpringMVC自定义注解---[详细介绍]
27 0
|
6月前
|
监控 Java 编译器
SpringMVC之自定义注解
SpringMVC之自定义注解
33 0
|
7月前
|
前端开发 Java
48SpringMVC - 参数绑定(自定义)
48SpringMVC - 参数绑定(自定义)
28 0
|
6月前
|
安全 Java 数据库连接
【springMvc】自定义注解的使用方式
【springMvc】自定义注解的使用方式
64 0
|
6天前
|
前端开发 安全 Java
解锁高级技巧:玩转 Spring MVC 自定义拦截器的神奇世界
解锁高级技巧:玩转 Spring MVC 自定义拦截器的神奇世界
80 0
|
6天前
|
缓存 安全 Java
SpringMVC自定义注解和使用
SpringMVC自定义注解和使用
97 0
|
5月前
|
Java
springmvc之自定义注解-->自定义注解简介,基本案例和aop自定义注解
springmvc之自定义注解-->自定义注解简介,基本案例和aop自定义注解
34 0
|
5月前
|
Java 开发者
SpringMVC----自定义注解
SpringMVC----自定义注解
33 0
|
5月前
|
Java
【SpringMVC】之自定义注解
【SpringMVC】之自定义注解
36 0
|
6月前
|
JSON 安全 Java
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)
47 0
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)