自定义注解

news2024/11/20 16:46:08

如何实现自定义注解

  在我们实际开发过程中如果能合理的运用自定义注解,则会大大减少我们代码的开发量。那怎么才能实现自定义注解呢?废话不多说,直接上干货!

一、创建注解

  这一步呢,我们可以理解成对应的实体类,我们要自定义注解,也需要这么一个东西,注解的名称,有哪些属性等等。

package org.disp.kingmouse.annotations;

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

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER, ElementType.METHOD})
public @interface KingMouse {
    String value() default "";
}

  1. @Retention: 表示该注解的生命周期,是RetentionPolicy类型的,该类型是一个枚举类型,可提供三个值选择,分别是:CLASS、RUNTIME、SOURCE

  1. RetentionPolicy.CLASS: 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;

  1. RetentionPolicy.RUNTIME: 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;

  1. RetentionPolicy.SOURCE: 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;

  1. 由此可见生命周期关系:SOURCE < CLASS < RUNTIME,我们一般用RUNTIME

  1. @Target: 表示该注解的作用范围,是ElementType类型的,该类型是一个枚举类型,一共提供了10个值选择,我们最常用的几个:FIELD、TYPE、PARAMETER、METHOD

  1. ElementType.FIELD:用于字段、枚举的常量

  1. ElementType.TYPE:用于接口、类、枚举、注解

  1. ElementType.PARAMETER:用于方法参数

  1. ElementType.METHOD:用于方法

在KingMouse这个类里面可以根据实际需求写上所需要的属性,到这里,我们的第一步就完成!

二、定义注解行为

  这一步就是我们需要如何去处理我们的注解,这里面有四个方法,分别是@Before@after@AroundAfterReturningAfterThrowing,我们常用的一般是前三个,看具体需求选择适合自己的就行

  1. @Before: 前置通知, 在方法执行之前执行,这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

  1. @After: 后置通知, 在方法执行之后执行(不论是正常返回还是异常退出)。

  1. @Around: 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

  1. @AfterRunning:返回通知, 在方法正常返回结果之后执行 。

  1. @AfterThrowing: 异常通知, 在方法抛出异常之后。

我们这里演示@Before@after,老规矩,直接上代码!

package org.disp.kingmouse.annotations;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class KingmouseAspect {

    private final static Logger LOGGER = LoggerFactory.getLogger(KingmouseAspect.class);

    @Before("@annotation(kingMouse)")
    public void doBefore(KingMouse kingMouse) {
        String value = kingMouse.value();
        LOGGER.info("@KingMouse before msg: [{}]", value);
        //do something
    }


    @After(value = "@annotation(kingMouse)")
    public void testAround(KingMouse kingMouse) {
        String value = kingMouse.value();
        LOGGER.info("@KingMouse around msg: [{}]", value);
        //do something
    }
}

  这个类里面我们就可以做我们想做的事情,我这里就直接打印KingMouse中的值代替了,上面这两步做完,我们的自定义注解就完成了,剩下的就是我们如何去使用了

三、验证测试

我们直接将KingMouse这个注解写到方法上,上代码

package org.disp.kingmouse.controller;


import lombok.extern.java.Log;
import org.disp.kingmouse.annotations.KingMouse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created with IntelliJ IDEA
 *
 * @auther KingMouse
 * @date 2020/6/02 11:26
 * Description:
 */
@Log
@Controller
@RequestMapping("/e")
public class TestController {
    @RequestMapping("/test")
    @KingMouse(value = "自定义注解-controller")
    public void test(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        log.info("KingMouse - test");
        test2();
    }

    @KingMouse(value = "自定义注解-method")
    public void test2(){
        log.info("KingMouse - test2");
    }
}

  这里面我们可以清楚的看到@KingMouse before msg: [自定义注解-controller]和@KingMouse around msg: [自定义注解-controller]分别对应@Before、@After两个方法,看到这里,有不少小伙伴应该会发现,为什么自定义注解-method这个内容没有打印,但是看日志,test2方法命名是执行了的,这是为什么?其实,注解的本质还是aop,所有当我们发起调用的时候,是可以拦截的,但是我们通过类直接调用方法是不行的,如果需要调用方法也可以被拦截,有两种方法:

  • 添加切面,上代码!

package org.disp.kingmouse.annotations;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class KingmouseAspect {

   private final static Logger LOGGER = LoggerFactory.getLogger(KingmouseAspect.class);

   @Pointcut("@annotation(org.disp.kingmouse.annotations.KingMouse)")
   public void kingmouse() {
   }

   @Before("kingmouse() && @annotation(kingMouse)")
   public void doBefore(KingMouse kingMouse) {
       String value = kingMouse.value();
       LOGGER.info("@KingMouse before msg: [{}]", value);
       //do something
   }


   @After(value = "kingmouse() && @annotation(kingMouse)")
   public void testAround(KingMouse kingMouse) {
       String value = kingMouse.value();
       LOGGER.info("@KingMouse around msg: [{}]", value);
       //do something
   }
}
  • 改变方法引用,上代码!


package org.disp.kingmouse.controller;
import lombok.extern.java.Log;
import org.disp.kingmouse.annotations.KingMouse;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created with IntelliJ IDEA
 *
 * @auther KingMouse
 * @date 2020/6/02 11:26
 * Description:
 */
@Log
@Controller
@RequestMapping("/e")
public class TestController {
    @RequestMapping("/test")
    @KingMouse(value = "自定义注解-controller")
    public void test(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        log.info("KingMouse - test");
        ((TestController) AopContext.currentProxy()).test2();
    }

    @KingMouse(value = "自定义注解-method")
    public void test2() {
        log.info("KingMouse - test2");
    }
}

这步改完,我们重启服务,测试,结果!!!!报错了!!

报错信息:

ERROR o.a.c.c.C.[.[.[.[dispatcherServlet][175] [TxId :  , SpanId : ]- Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.] with root cause
java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.
    at org.springframework.aop.framework.AopContext.currentProxy(AopContext.java:69)
    at org.disp.kingmouse.controller.TestController.test(TestController.java:28)

通过代码我们不难看出,被禁用了,其实springboot默认是关闭的,不允许我们这么用,打开就好了,我们只需要在我们的启动类上增加@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true),上代码!

package org.disp.kingmouse;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
public class KingmouseApplication {

    public static void main(String[] args) {
        SpringApplication.run(KingmouseApplication.class, args);
    }

}

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

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

相关文章

BetaFlight统一硬件资源抽象设计

BetaFlight统一硬件资源抽象设计1. 源由2. 资源配置注意事项3. 资源配置文件修改验证步骤Step 1&#xff1a;确认硬件修改内容Step 2&#xff1a;资源配置文件修改Step 3&#xff1a;验证配置文件Step 4&#xff1a;提交资源配置文件PR4. 参考资料就笔者接触嵌入式设计以来&…

ESP32设备驱动-MAX44009环境光传感器驱动

MAX44009环境光传感器驱动 文章目录 MAX44009环境光传感器驱动1、MAX44009介绍2、硬件准备3、软件准备4、驱动实现1、MAX44009介绍 MAX44009 环境光传感器具有 IC 数字输出,非常适合智能手机、笔记本电脑和工业传感器等多种便携式应用。 它的工作电流小于 1A,是业内功耗最低…

Springboot——Swagger

Swagger2 的 maven 依赖使用 Swagger2 工具&#xff0c;必须要导入 maven 依赖&#xff0c;当前官方最高版本是 2.8.0&#xff0c;我尝试了一下&#xff0c;个人感觉页面展示的效果不太好&#xff0c;而且不够紧凑&#xff0c;不利于操作。另外&#xff0c;最新版本并不一定是最…

Redux toolkit

Redux 是 JavaScript 应用的状态容器&#xff0c;提供可预测的状态管理。 Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法 入门 Redux | Redux 中文官网 本案例是一个加&#xff0c;减的计算器&#xff0c;从零到壹 1、创建一个react的项目 Create-react-app react-too…

MybatisX快速生成增删改查

MybatisX快速生成增删改查 MybatisX 是一款基于 IDEA 的快速开发插件&#xff0c;方便在使用mybatis以及mybatis-plus开始时简化繁琐的重复操作&#xff0c;提高开发速率。 注意&#xff1a;idea得用最新的版本才能生效一些功能&#xff0c;我用的是2021.3版本的 1 安装 file …

【Unity VR开发】结合VRTK4.0:直线

桃花坞里桃花庵&#xff0c;桃花庵里桃花仙。桃花仙人种桃树&#xff0c;又折桃花当酒钱。 酒醒只在花前坐&#xff0c;酒醉还来花下眠。半醉半醒日复日&#xff0c;花落花开年复年。 但愿老死花酒间&#xff0c;不愿鞠躬车马前。车尘马足富者趣&#xff0c;酒盏花枝贫者缘。…

新C++(7):多态那些事儿_上

"也应该歌颂赞美那株鲜红的玫瑰。"一、回顾多态(1)什么是多态呢在编程语言和类型轮中&#xff0c;多态&#xff08;英语&#xff1a;polymorphism&#xff09;指为不同数据类型的实体提供统一的接口。多态类型(英语:polymorphic type&#xff09;可以将自身所支持的操…

FreeRTOS任务通知实验

从 V8.2.0 版本开始&#xff0c;FreeRTOS 新增了任务通知这个功能&#xff0c;可以使用任务通 知来代替信号量、消息队列、事件组等这些东西。使用任务通知的话效率会更高。 本章要实现的功能是&#xff1a;使用任务通知方式实现消息队列、二值信号量、计数信号 量、事件标记功…

极狐场景化造车理念受热捧,北汽蓝谷构建未来5年核心竞争力

近日&#xff0c;极狐汽车以“一米视角”为设计思考的原点&#xff0c;围绕亲子出行的全场景&#xff0c;推出全球首款智能亲子车——考拉。作为北汽蓝谷场景化造车的首款产品&#xff0c;极狐汽车考拉无疑是继高阶智能驾驶标杆产品HI之后的又一次先行探索&#xff0c;致力于卡…

1月VR大数据:Quest 2增长2.91%,HTC份额跌至10%以下

Hello大家好&#xff0c;每月一期的VR内容/硬件大数据统计又和大家见面了。 想了解VR软硬件行情么&#xff1f;关注这里就对了。我们会统计Steam平台的用户及内容等数据&#xff0c;每月初准时为你推送&#xff0c;不要错过喔&#xff01;本数据报告包含&#xff1a;Steam VR硬…

初识C语言(对c语言的简单介绍)

初识C语言什么是C语言&#xff1f;第一个C语言程序数据类型类型的使用&#xff1a;变量、常量定义变量的方法变量的分类变量的使用变量的作用域和生命周期常量字符串转义字符注释字符串转义字符注释选择语句循环语句函数数组数组定义数组的使用操作符常见关键字关键字 typedef关…

MySQL进阶篇之SQL优化

03、SQL优化 3.1、插入数据 1、insert优化 批量插入 INSERT INTO 表名 (字段1,字段2,...) VALUES (值1,值2,...),(值1,值2,...),(值1,值2,...);INSERT INTO 表名 VALUES (值1,值2,...),(值1,值2,...),(值1,值2,...);手动提交事务 start transaction; INSERT INTO 表名 (字段1…

【SQL 审核查询平台】Archery使用介绍

Archery 读作&#xff1a;[ˈɑːrtʃəri] Archery目录界面截图功能清单依赖清单框架前端组件服务端部署准备运行配置启动访问修改配置项基础设置添加实例添加资源组资源组关联用户/实例添加权限组用户关联权限组/权限设置工单上线和查询的审批流程设置默认资源组和默认权限组…

数组的几种常见方法及其返回值

push()&#xff1a;向数组的末尾添加一个或多个元素&#xff1b;返回的是数组的新长度。unshift()&#xff1a;向数组的开头添加一个或多个元素&#xff1b;返回的是数组的新长度。shift()&#xff1a;删除数组的第一个元素&#xff0c;并返回被删除的&#xff08;即第一个元素…

品牌社交营销链路 | 小红书数据分析网站

【导语】 2022年&#xff0c;小红书品牌推广竞争愈演愈烈&#xff0c;从小红书用户画像分析&#xff0c;到抢占小红书关键词排名&#xff0c;营销动作内卷升级&#xff0c;那么在2023的新篇章&#xff0c;如何打通社交种草的链路呢&#xff1f; 1、运营企业账号&#xff0c;建立…

MQTT 代理助力ECARX实现汽车智能互联

一、应用背景 ECARX是中国汽车制造商吉利旗下的一家科技创新企业&#xff0c;致力于持续打造行业领先的智能网联生态开放平台&#xff0c;全面为车企赋能&#xff0c;创造更智能、更安全的出行体验&#xff0c;为智能互联汽车提供智能解决方案。 ECARX主要业务包括吉利汽车的…

让Apache Beam在GCP Cloud Dataflow上跑起来

简介 在文章《Apache Beam入门及Java SDK开发初体验》中大概讲了Apapche Beam的简单概念和本地运行&#xff0c;本文将讲解如何把代码运行在GCP Cloud Dataflow上。 本地运行 通过maven命令来创建项目&#xff1a; mvn archetype:generate \-DarchetypeGroupIdorg.apache.b…

Swift 新 async/await 同步机制小技巧:消除“多余”的 await 关键字

概览 在使用多个Actor 共同实现同步功能的时候&#xff0c;我们往往会看到如下使用场景&#xff1a; Actor A 必须在主线程上运行&#xff0c;Actor B可以在任意线程上运行&#xff0c;但需要适时的调用 Actor A 中的方法。 在这种情况下&#xff0c;我们会遇到如下代码&#…

从移动激光扫描数据中自动提取单棵树的双重生长方法

论文题目&#xff1a;A dual growing method for the automatic extraction of individual trees from mobile laser scanning data Abstract 在城市场景的杂乱点云中&#xff0c;街道树木与其他物体交织在一起&#xff0c;阻碍了对单个树木的自动提取。根据树木的一般构成&a…

React:安装配置使用scss

目录 前言&#xff1a; 1.暴露隐藏的webpack配置&#xff1b; 2.安装sass的相关包&#xff1b; 3.项目中新建一些scss文件&#xff1b; 4.在config文件夹中找到webpack.config.js文件&#xff0c;进行配置&#xff1b; 5.测试使用&#xff1b; 前言&#xff1a; 项目采用…