SpringMVC之自定义注解

目录

一.什么是Java注解

1.简介

2.注解的分类 

3.JDK元注解

 二.自定义注解

1.自定义注解的分类

        1.1.标记Annotation:

        1.2.元数据Annotation:

2.如何使用自定义注解

3.案例演示

3.1 获取类、方法及属性上的注解值 

 3.2@Inherited 的使用

3.3获取类属性上的注解属性值

3.4获取参数修饰注解对应的属性值

三.aop自定义注解

1.导入aop自定义注解需要的Maven依赖

2.创建自定义注解


一.什么是Java注解

1.简介

Java注解是一种附加在代码中的元数据,它提供了关于代码的额外信息。注解可以在类、方法、字段、参数等各个层面上使用,用于描述代码的特性、行为、要求等。注解是在编译时被处理的,并且可以被编译器、工具或运行时框架解析和利用。

Java注解的语法形式以"@"符号开头,紧跟着注解的名称和可选的参数列表。注解可以包含元素,类似于接口的成员。这些元素可以具有默认值,也可以在使用注解时显式地指定值。

2.注解的分类 

  1. 提供信息给编译器:可以使用注解在源代码级别嵌入信息,这些信息可以被编译器解析和利用。例如,@Deprecated注解用于标记过时的代码,编译器会在编译时生成警告信息。

  2. 编译时进行额外的处理:某些注解可以触发编译时的额外操作。例如,@Entity注解用于标记实体类,编译器可以根据这个注解生成与数据库表的映射代码。

  3. 运行时的处理:某些注解在程序运行时可以被解析和处理。这些注解可以通过反射机制在运行时获取并执行相关操作。例如,Spring框架使用注解来配置依赖注入、AOP等特性。

3.JDK元注解

JDK提供了一些元注解(meta-annotation),它们是用于定义和配置自定义注解的注解。元注解可以应用于自定义注解上,用于指定注解的行为和特性。以下是JDK中常用的元注解:

  1. @Retention:指定注解的保留策略,即注解在何时生效。常用的保留策略有三种:

    • RetentionPolicy.SOURCE:注解仅在源代码中保留,编译器在编译时会忽略它们。
    • RetentionPolicy.CLASS:注解在编译时会被保留在字节码文件中,但在运行时不可获取。这是默认的保留策略。
    • RetentionPolicy.RUNTIME:注解在运行时保留,可以通过反射机制获取和解析注解信息。
  2. @Target:指定注解可以应用的目标元素类型,包括以下一些常见的目标类型(ElementType):

    • ElementType.TYPE:类、接口、枚举类型
    • ElementType.FIELD:字段、枚举常量
    • ElementType.METHOD:方法
    • ElementType.PARAMETER:方法参数
    • ElementType.CONSTRUCTOR:构造方法
    • ElementType.LOCAL_VARIABLE:局部变量
    • ElementType.ANNOTATION_TYPE:注解类型
    • ElementType.PACKAGE:包
  3. @Documented:指定注解是否包含在生成的Java文档中。如果一个注解被标记为@Documented,在生成文档时将包含该注解的信息。

  4. @Inherited:指定注解是否可以被继承。如果一个注解被标记为@Inherited,则表示子类会继承父类的注解。

除了以上元注解,JDK还提供了其他几个元注解,如@Repeatable(指定注解是否可重复应用于同一元素)和@Native(指定注解与本地代码关联)等。这些元注解为自定义注解的设计和行为提供了灵活性和可扩展性。

使用元注解可以通过注解注解(annotate the annotation)的方式来配置自定义注解的行为和特性,从而实现更加灵活和强大的注解功能。

 二.自定义注解

1.自定义注解的分类

        1.1.标记Annotation:

        没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息

        1.2.元数据Annotation:

        包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据;

2.如何使用自定义注解

使用@interface关键字, 其定义过程与定义接口非常类似, 需要注意的是:
 Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值类型定义了该成员变量的名字和类型,而且我们还可以使用default关键字为这个成员变量设定默认值;

3.案例演示

3.1 获取类、方法及属性上的注解值 

(1)自定义三个注解

package com.YU.annotation.demo;import java.lang.annotation.*;/*** MyAnnotation1注解可以用在类、接口、属性、方法上* 注解运行期也保留* 不可继承*/
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation1 {String name();
}
package com.YU.annotation.demo;import java.lang.annotation.*;/***  MyAnnotation2注解可以用在方法上*  注解运行期也保留*  不可继承*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {TranscationModel model() default TranscationModel.ReadWrite;
}
package com.YU.annotation.demo;import java.lang.annotation.*;/*** @author YU* @time 2023/9/14 18:52:55** MyAnnotation3注解可以用在方法上* 注解运行期也保留* 可继承*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {TranscationModel[] models() default TranscationModel.ReadWrite;
}

其中的JDK元注解作用在前面都有介绍

这里我们编写测试方法,尝试获取类、方法及属性上的注解值 

@Testpublic void list() throws Exception {
//        获取类上的注解MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);System.out.println(annotation1.name());//abc//        获取方法上的注解MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);System.out.println(myAnnotation2.model());//Read//        获取属性上的注解MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);System.out.println(myAnnotation1.name());// xyz}

Demo1

package com.YU.annotation.demo1;/*** @author YU* 获取类与方法上的注解值*/
@MyAnnotation1(name = "abc")
public class Demo1 {@MyAnnotation1(name = "xyz")public Integer age;public Integer getAge() {return age;}@MyAnnotation2(model = TranscationModel.Read)public void list() {System.out.println("list");}@MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})public void edit() {System.out.println("edit");}
}

测试结果

 3.2@Inherited 的使用

还是根据上述提供的代码,新建一个demo2的类去继承demo1,当我们在使用demo2去获取注解值的时候,因为MyAnnotation1和MyAnnotation2并没有使用@Inherited,所以在测试时,获取不到MyAnnotation1和MyAnnotation2的的属性值

(1)当我们运行测试方法时,demo1中的MyAnnotation1没有使用@Inherited,测试时报出空指针异常

(2)但是在MyAnnotation1中加上@Inherited后,我们就可以通过demo2去获取属性中的注解值

所以回到我们最开始@Inherited的作用

@Inherited:指定注解是否可以被继承。如果一个注解被标记为@Inherited,则表示子类会继承父类的注解。

结论:类继承类时,只有被指定@Inherited的注解才能被继承使用

3.3获取类属性上的注解属性值

首先我们定义一个注解

package com.YU.annotation.demo2;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author YU*/
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {String value() default "默认value值";String what() default "这里是默认的what属性对应的值";
}

然后使用注解,获取注解上的属性值

package com.YU.annotation.demo2;/*** @author YU** 获取类属性上的注解属性值*/
public class Demo2 {@TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1")private static String msg1;@TestAnnotation("这就是value对应的值1")private static String msg2;@TestAnnotation(value = "这就是value对应的值2")private static String msg3;@TestAnnotation(what = "这就是what对应的值")private static String msg4;
}

测试结果得出的结论为

当我们同时为两个属性都设置值时,那么获取到的都为设置值,当我们没有去指定为哪个属性赋值时,但是又传了属性值,那么默认会给第一个设置属性值,当我们没有去设置属性值时,获取到的为注解中默认的属性值

3.4获取参数修饰注解对应的属性值

(1)定义一个注解

package com.YU.annotation.demo3;import java.lang.annotation.*;/*** @author YU** 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空*/
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {boolean value() default false;
}

(2)通过获取参数修饰注解对应的属性值

package com.YU.annotation.demo3;/*** @author YU** 获取参数修饰注解对应的属性值*/
public class Demo3 {public void hello1(@IsNotNull(true) String name) {System.out.println("hello:" + name);}public void hello2(@IsNotNull String name) {System.out.println("hello:" + name);}
}

 (3)编写测试方法

@Testpublic void hello3() throws Exception {
//        模拟浏览器传递到后台的参数 解读@requestParamString name = "zs";Demo3 demo3 = new Demo3();Method method = demo3.getClass().getMethod("hello1", String.class);for (Parameter parameter : method.getParameters()) {IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);if(annotation != null){System.out.println(annotation.value());//trueif (annotation.value() && !"".equals(name)){method.invoke(demo3,name);}}}}

测试方法解读:

当我们在进行测试时,先根据getMethod获取方法的返回值,将定义好的属性值传入(实际开发为前端返回的数据),通过判断传入的属性值来返回不同的结果,例如:

传入的值为“zs” 参数修饰注解的属性值为true,当两个条件同时满足时,将参数进行传递并调用业务方法

三.aop自定义注解

1.导入aop自定义注解需要的Maven依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.创建自定义注解

首先,在代码中创建一个用于 AOP 的自定义注解。自定义注解应使用 @interface 关键字进行定义,并可以包含一些元数据

@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {boolean value() default false;
}

在创建好注解后,我们要相应得去创建一个切面类,增加切入点和增强逻辑

@Component
@Aspect
public class MyLogAspect {private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);/*** 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类*/@Pointcut("@annotation(com.YU.annotation.aop.MyLog)")private void MyValid() {}@Before("MyValid()")public void before(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();logger.debug("[" + signature.getName() + " : start.....]");System.out.println("[" + signature.getName() + " : start.....]");MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc());}
}

在上述示例中,使用 @Pointcut 注解定义了一个切入点MyValid(),并使用 @Before 注解分别在切入点前后执行增强逻辑

 今天的学习到这里就结束了,感谢各位大大的观看,各位大大的三连是博主更新的动力,感谢谢谢谢谢谢谢谢谢各位的支持!!!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/79270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot整合mybatis

一、项目结构展示 二、开始整合 1、引入pom依赖 进入Maven中央仓库选择自己所需要的依赖&#xff0c;maven仓库地址&#xff1a;Maven Central 完整Maven依赖如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"h…

markdown工具Atom预览与插件安装

​atom是以命令行作为插件选项的入口 打开命令输入框 Windows: ctrl shift p Mac: command shift p 输入命令安装 输入 markdown preview toggle &#xff0c;可以偷懒只输入mdpt(模糊匹配) 按enter键即可看到预览&#xff0c;如图&#xff0c;左边编辑&#xff0c;右…

Vue中的过滤器 Filters

过滤器 Filters 过滤器一般用于格式化文本内容&#xff0c;通常可以在两个地方使用&#xff0c;主要是模板语法、以及 v-bind 表达式中。例如我想对展示的文本进行一些特殊处理&#xff0c;将金额进行四舍五入后再展示。选项 filters 内可以编写多个自定义过滤器。 用法&…

LightDB 23.3 通过GUC参数控制commit fetch

背景 commit游标提交之后&#xff0c;可以继续使用fetch进行结果集的操作。commit和fetch结合使用功能开发时不考虑分布式。后续&#xff0c;又对分布式进行了测试&#xff0c;发现持有portal后&#xff0c;代码中会对querydesc进行非空判断。当querydesc为空时&#xff0c;Li…

工业交换机常见的硬件故障有哪些?

工业交换机常见的硬件故障主要是由于受到供电电源、室内温度、室内湿度、电磁干扰、静电等机房环境的影响&#xff0c;造成工业交换机电源、背板、模块、端口等部件出现故障。具体可以分为以下几类。 1.电力供应故障&#xff1a; 由于外部供电不稳定、电源线路老化或雷击等原因…

LiveNVR监控流媒体Onvif/RTSP功能-支持海康摄像头海康NVR通过EHOME协议ISUP协议接入分发视频流或是转GB28181

LiveNVR支持海康NVR摄像头通EHOME接入ISUP接入LiveNVR分发视频流或是转GB28181 1、海康 ISUP 接入配置2、海康设备接入2.1、海康EHOME接入配置示例2.2、海康ISUP接入配置示例 3、通道配置3.1、直播流接入类型 海康ISUP3.2、海康 ISUP 设备ID3.3、启用保存3.4、接入成功 4、相关…

亚马逊封买家账号的原因有哪些

亚马逊可能封锁买家账号的原因有多种&#xff0c;主要是出于保护市场和维护平台秩序的考虑。以下是一些可能导致亚马逊封锁买家账号的常见原因&#xff1a; 1、涉及违规行为&#xff1a;如果买家违反了亚马逊的使用政策&#xff0c;如发表虚假评价、滥用退货政策、欺诈或盗窃等…

【视觉SLAM入门】7.3.后端优化 基于KF/EKF和基于BA图优化的后端,推导及举例分析

"时间倾诉我的故事" 1. 理论推导2. 主流解法3. 用EKF估计状态3.1. 基于EKF代表解法的感悟 4. 用BA法估计状态4.1 构建最小二乘问题4.2 求解BA推导4.3 H的稀疏结构4.4 根据H稀疏性求解4.5 鲁棒核函数4.6 编程注意 5.总结 引入&#xff1a; 前端里程计能给出一个短时间…

markdown学习笔记

markdown学习笔记 1.文字&#xff08;依靠HTML&#xff09; 1.1文字缩进-空格转义符 单字符空&#xff1a;&emsp; 半字符空&#xff1a;&ensp;1.2文字对齐 「居中&#xff1a;」<center> 居中 </center> or <p align"center"> 居中 …

吃瓜教程第一二章学习记录

当大多数人听到 "机器学习 "时&#xff0c;他们会联想到机器人&#xff1a;一个可靠的管家或一个致命的终结者&#xff0c;这取决于你问谁。但是&#xff0c;机器学习并不只是未来主义的幻想&#xff0c;它已经存在了。事实上&#xff0c;在一些特殊的应用中&#xf…

upload-labs文件上传漏洞通关

一、环境搭建 upload-labs是一个使用php语言编写的&#xff0c;专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。 下载地址&#xff1a;https://github.com/c0ny1/upload-labs/releases 在 win 环境下 直接解压到phpstudy下即可 二、通关 &#xff08;一&#xff09;16关…

使用凌鲨进行聚合搜索

作为研发人员&#xff0c;我们经常需要在多个来源之间查找信息&#xff0c;以便进行研发工作。除了常用的搜索引擎如百度和必应之外&#xff0c;我们还需要查阅各种代码文档和依赖包等资源。这些资源通常分散在各个网站和文档库中&#xff0c;需要花费一定的时间和精力才能找到…

Redis缓存更新策略、详解并发条件下数据库与缓存的一致性问题以及消息队列解决方案

0、前言 我们知道&#xff0c;缓存由于在内存中&#xff0c;数据处理速度比直接操作数据库要快很多&#xff0c;因此常常将数据先读到缓存中&#xff0c;再进行查询、更新等操作。 但与之而来的问题就是&#xff0c;内存中的数据不仅没有持久化&#xff0c;而且需要保证…

如何在微软Edge浏览器上一键观看高清视频?

编者按&#xff1a;视频是当下最流行的媒体形式之一。但由于视频压缩、网络不稳定等原因&#xff0c;我们常常可以看到互联网上的很多视频其画面质量并不理想&#xff0c;尤其是在浏览器端&#xff0c;这极大地影响了观看体验。不过&#xff0c;近期微软 Edge 浏览器推出了一项…

linux命令查看谁在使用服务器的GPU

命令&#xff1a;查看GPU使用情况 nvidia-smi 可以知悉GPU占用情况和主要使用GPU的进程&#xff0c;如下图所示&#xff1a; 实时查看gpu使用&#xff1a; nvidia-smi -l 1 表示每隔1s刷新一下&#xff0c;数字可更改。 查看进程的归属者 方法一&#xff1a;ps -f -p pid…

发布文章到wordpress

给朋友新建的wp网站,没有内容怎么办,总不能一篇篇的挨个写入吧。用wp提供的录入模块就可以了 参考 wp说明文档 获取docx内容保存到wp 资料有个docx文件,但文件格式混乱,好在有目录,可以基于目录,对文章分割,用正则拆分存入wp 首先用pandoc把docx转为md文件,速度较慢,…

——二叉树

二叉树种类 二叉树有两种主要的形式&#xff1a;满二叉树和完全二叉树。 满二叉树 如果一棵二叉树只有度为0的结点和度为2的结点&#xff0c;并且度为0的结点在同一层上&#xff0c;则这棵二叉树为满二叉树。 完全二叉树 在完全二叉树中&#xff0c;除了最底层节点可能没…

开发者必看!NetMarvel 五大能力驱动【变现收益】增长飞轮

更多流量带来更多预算&#xff0c;再由更多预算驱动增长。这不仅是出海App增长变现的底层逻辑&#xff0c;也是程序化广告平台的运行法则。App出海之路走到今天&#xff0c;开发者已经意识到&#xff1a;应用内购是实现正向现金流的必要手段&#xff0c;接入广告平台获取广告收…

Spark on YARN 部署搭建详细图文教程

目录 一、引言 二、SparkOnYarn 本质 2.1 Spark On Yarn 的本质? 2.2 Spark On Yarn 需要啥? 三、配置 spark on yarn 环境 3.1 spark-env.sh 3.2 连接到 YARN 中 3.2.1 bin/pyspark 3.2.2 bin/spark-shell 3.2.3 bin/spark-submit (PI) 四、部署模式 DeployMod…

阿维塔30亿元融资背后:价格战再席卷,如何守住品牌底线?

造车新势力阿维塔近期消息不断。 8月31日&#xff0c;阿维塔宣布完成B轮融资&#xff0c;规模达到30亿元&#xff0c;投后估值近200亿元。随后的9月2日&#xff0c;阿维塔科技宣布8月共交付新车1975辆&#xff0c;略高于上月的1786辆&#xff0c;稳居30万以上纯电SUV头部阵营。…