SpringMVC之自定义注解

news2024/10/6 0:14:10

目录

一.什么是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元注解作用在前面都有介绍

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

@Test
    public 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)编写测试方法

@Test
    public void hello3() throws Exception {
//        模拟浏览器传递到后台的参数 解读@requestParam
        String 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());//true
                if (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.coloradmin.cn/o/1012426.html

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

相关文章

模电课设:用Multisim设计和分析差分放大电路

1 课设内容 1&#xff09;设计一个差分放大器电路&#xff1b; 2&#xff09;用电流源替换发射极电阻&#xff0c;看看会发生什么&#xff1f; 3&#xff09;差分放大器电路特性之差模传输特性。 2 模型搭建 1&#xff09;设计一个差分放大器电路。 差分放大器电路是由对称…

day4_C++

day4_C 思维导图重载 思维导图 重载 #include <iostream> #include <cstring> using namespace std;class MyString { private:char *str;int size; public:MyString():size(10){str new char[size];strcpy(str,"");}MyString(const char *s){size st…

【案例】光电兼修的Alpha Cen,如何应对上升期的甜蜜烦恼?

Alpha Cen&#xff08;比邻星光&#xff09;是一家挺酷的公司&#xff0c;专注于超表面技术芯片研发。 所谓超表面芯片&#xff0c;就是通过控制类似下图的一个个独立纳米级别单元实现光操控。用微纳光学超表面技术能够平面化集成唯一还不在wafer上的光学器件&#xff0c;这意…

满载大模型技能干货的AI Day活动全新来袭

AI大模型时代&#xff0c;创造力才是第一生产力&#xff01; 满载大模型技能干货的AI Day主题活动全新来袭 丰富有趣的Workshop即将空降你的学校 帮助大家掌握前沿技能、拓展技术视野、迈进AIGC的大门 打造属于你的AI应用&#xff0c;满足不同阶段的学习实践需求 无论你是零基础…

面渣逆袭:微服务三十三问,两万字图文详解,速收藏

大家好&#xff0c;我是老三&#xff0c;面渣逆袭系列继续&#xff0c;这期给大家带来微服务相关的面试题。 概览 1.什么是微服务&#xff1f; 微服务&#xff08;Microservices&#xff09;是一种软件架构风格&#xff0c;将一个大型应用程序划分为一组小型、自治且松耦合的…

线程同步互斥锁

共用三个函数&#xff1a; mutex_lock() mutex_unlock() mutex_trylock() pthread_mutex_lock给安卓上层使用&#xff0c;mutex_lock给kernel使用&#xff0c;本质是一样的&#xff0c;都是IPC通信中的互斥锁&#xff0c;只不过安卓上层封装出pthread_mutex_lock。 pthr…

一篇文章带你了解立仪点激光位移传感器

激光位移传感器是利用激光技术进行测量的传感器。它由激光器、激光检测器和测量电路组成。激光传感器是新型测量仪表。能够精确非接触测量被测物体的位置、位移等变化。 可以测量位移、厚度、振动、距离、直径等精密的几何测量。激光有直线度好的优良特性&#xff0c;同样激光…

WOODWARD 5466-425 确保一致、无差错的配置和实施

WOODWARD 5466-425 确保一致、无差错的配置和实施 虽然许多大型制造公司已在其 IT 部门使用虚拟化多年&#xff0c;但 DeltaV Virtual Studio 专为过程控制系统而设计&#xff0c;具有自动化工程师直观且熟悉的工作流程和功能集。预构建的虚拟机模板可以轻松创建虚拟机&am…

ChatGPT充值,银行卡被拒绝,图文教程

目录 前言步骤1. 魔法地址选择2. 选择手机号码(归属地)3. 勾选,服从协议4. 填写信息5. 完善账单地址6. 订阅成功前言 大家好,今天我在订阅ChatGPT4时,遭遇了银行卡被拒绝的尴尬境地。这里有个技巧,助你开心畅享ChatGPT Plus的升级版。 可SiXin我,索取详细图文教程。 …

教学计划编制问题

教学计划编制问题 学生姓名&#xff1a;XX 指导老师&#xff1a;XXX 摘 要 本课程设计主要针对计算机系本科课程&#xff0c;根据课程之间的依赖关系&#xff0c;制定课程安排计划&#xff0c;并满足各学期课程数目大致相同。在课程设计中&#xff0c;系统开发平台为Windows…

中秋快乐! Happy Mid-autumn Festival!

中秋节代表着团圆。在我国&#xff0c;中秋节时&#xff0c;在外的游子都会赶回家&#xff0c;和家人一起赏月、吃月饼&#xff0c;所以&#xff0c;中秋节象征着家庭的圆满、人们的团聚&#xff0c;也寄托着人们对生活无限的热爱和对美好生活的向往。The Mid-Autumn Festival …

STM32外部复位IC与看门狗冲突,无法复位问题解决方案

使用STM32H743制作了一款飞控&#xff0c;外部复位IC采用MAX809STR,打板完后&#xff0c;烧录飞控固件后大量板子无法正常启动&#xff0c;怀疑是晶振没有起振或MCU未焊接好&#xff0c;检查后均焊接正常&#xff0c;编写裸机LED定时闪烁验证程序可正常运行。经网上查询资料锁定…

Linux学习记录——이십팔 网络基础(1)

文章目录 1、了解2、网络协议栈3、TCP/IP模型4、网络传输1、同一局域网&#xff08;子网&#xff09;2、局域网通信原理3、跨一个路由器的两个子网4、其它 详细的网络发展历史就不写了 1、了解 为什么会出现网络&#xff1f;一开始多个计算机之间想要共享文件&#xff0c;就得…

clickhouse union all之后数据量不一致

环境&#xff1a; clickhouse版本&#xff1a;22.8.16.32 问题&#xff1a;clickhouse使用union all查询结果与每一段sql查询结果只和不一致 原因&#xff1a;因为clickhouse版本问题&#xff0c;官方给出不同的解释 解决方案&#xff1a;将union all的每一段sql用括号括起来…

kafka知识点汇总

kafka是什么&#xff1f; Kafka是一个分布式的基于发布/订阅模式的消息队列&#xff08;Message Queue&#xff09;&#xff0c;主要应用于大数据实时处理领域。 Kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。Kafka是一种高吞吐量的分布…

Frp实现外网访问内网服务

一、需求背景 博主在本地电脑&#xff08;Windows&#xff09;上安装了一款BS架构的软件&#xff0c;现在想要其他人通过域名直接访问本地电脑的web服务。 二、准备事项 &#xff08;一&#xff09;前置条件 公网IP&#xff08;可以购买阿里云轻量服务器&#xff09;域名&a…

【藏经阁一起读】(68)__《ECS技术实战指南》

【藏经阁一起读】&#xff08;68&#xff09;__《ECS技术实战指南》 目录 一、知识收获 &#xff08;1&#xff09;、CIPU &#xff08;2&#xff09;、RDMA 二、个人建议 一、知识收获 &#xff08;1&#xff09;、CIPU 1、多模态、海量数据、超大模型成为发展方向&#…

基于Face++网络爬虫+人脸融合算法智能发型推荐程序——深度学习算法应用(含Python及打包exe工程源码)+爬虫数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境Pycharm 环境 模块实现1. Face.APl调用1&#xff09;Face.APl介绍2&#xff09;调用API 2. 数据爬取1&#xff09;网络数据爬取步骤2&#xff09;爬虫实现 3. 模型构建4. 用户界面设计1&#xff09;需要调用的库文…

肖sir__mysql之多表练习题__006

已知2张基本表&#xff1a;部门表&#xff1a;dept &#xff08;部门号&#xff0c;部门名称&#xff09;;员工表 emp&#xff08;员工号&#xff0c;员工姓名&#xff0c;年龄&#xff0c;入职时间&#xff0c;收入&#xff0c;部门号&#xff09; 1&#xff1a;dept表中有4条…

论文解读 | 基于视觉的水果采摘机器人识别与定位方法研究进展

原创 | 文 BFT机器人 01 背景 在复杂的农业环境中&#xff0c;利用机器视觉及其相关算法可以提高收割机器人的效率、功能性、智能化和远程互动性。对于水果采摘机器人系统来说&#xff0c;主要的挑战包括免提导航和水果定位&#xff0c;以及大多数果园中常见的崎岖地形和大型…