自定义注解

Java 自定义注解 Java自定义注解Java注解简介Java元注解自定义注解代码演示 本章点知识总览: 1、Java 注解简介 2、Java 元注解(重点) 3、自定义注解 4、Aop 自定义注解的应用(重点) Java注解(Annotation) 分类 编程技术 Java注解(Annotation)又称Java标注,是JDK5.0约会的一种注释机制。 和Javadoc不同,Java标注可以通过反射获取标注内容。 ... 阅读详情

相信很多人对Java中的注解都很熟悉,比如我们经常会用到的一些如@Override、@Autowired、@Service等,这些都是JDK或者诸如Spring这类框架给我们提供的。

在以往的面试过程中,我发现,关于注解的知识很多程序员都仅仅停留在使用的层面上,很少有人知道注解是如何实现的,更别提使用自定义注解来解决实际问题了。

但是其实,我觉得一个好的程序员的标准就是懂得如何优化自己的代码,那在代码优化上面,如何精简代码,去掉重复代码就是一个至关重要的话题,在这个话题领域,自定义注解绝对可以算得上是一个大大的功臣。

所以,在我看来,会使用自定义注解 ≈ 好的程序员。

那么,本文,就来介绍几个,作者在开发中实际用到的几个例子,向你介绍下如何使用注解来提升你代码的逼格。

基本知识

在Java中,注解分为两种,元注解和自定义注解。

很多人误以为自定义注解就是开发者自己定义的,而其它框架提供的不算,但是其实上面我们提到的那几个注解其实都是自定义注解。

关于"元"这个描述,在编程世界里面有都很多,比如"元注解"、“元数据”、“元类”、"元表"等等,这里的"元"其实都是从meta翻译过来的。

一般我们把元注解理解为描述注解的注解,元数据理解为描述数据的数据,元类理解为描述类的类…

所以,在Java中,除了有限的几个固定的"描述注解的注解"以外,所有的注解都是自定义注解。

在JDK中提供了4个标准的用来对注解类型进行注解的注解类(元注解),他们分别是:

@Target

@Retention

@Documented

@Inherited

除了以上这四个,所有的其他注解全部都是自定义注解。

这里不准备深入介绍以上四个元注解的作用,大家可以自行学习。

本文即将提到的几个例子,都是作者在日常工作中真实使用到的场景,这例子有一个共同点,那就是都用到了Spring的AOP技术。

什么是AOP以及他的用法相信很多人都知道,这里也就不展开介绍了。

使用自定义注解做日志记录

不知道大家有没有遇到过类似的诉求,就是希望在一个方法的入口处或者出口处做统一的日志处理,比如记录一下入参、出参、记录下方法执行的时间等。

如果在每一个方法中自己写这样的代码的话,一方面会有很多代码重复,另外也容易被遗漏。

这种场景,就可以使用自定义注解+切面实现这个功能。

假设我们想要在一些web请求的方法上,记录下本次操作具体做了什么事情,比如新增了一条记录或者删除了一条记录等。

首先我们自定义一个注解:

/**

 * Operate Log 的自定义注解

 */

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface OpLog {

    /**

     * 业务类型,如新增、删除、修改

     * @return

     */

    public OpType opType();

    /**

     * 业务对象名称,如订单、库存、价格

     * @return

     */

    public String opItem();

    /**

     * 业务对象编号表达式,描述了如何获取订单号的表达式

     * @return

     */

    public String opItemIdExpression();

}

因为我们不仅要在日志中记录本次操作了什么,还需要知道被操作的对象的具体的唯一性标识,如订单号信息。

但是每一个接口方法的参数类型肯定是不一样的,很难有一个统一的标准,那么我们就可以借助Spel表达式,即在表达式中指明如何获取对应的对象的唯一性标识。

有了上面的注解,接下来就可以写切面了。主要代码如下:

/**

 * OpLog的切面处理类,用于通过注解获取日志信息,进行日志记录

 * @author Hollis

 */

@Aspect

@Component

public class OpLogAspect {

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

    @Autowired

    HttpServletRequest request;

    @Around("@annotation(com.hollis.annotation.OpLog)")

    public Object log(ProceedingJoinPoint pjp) throws Exception {

        Method method = ((MethodSignature)pjp.getSignature()).getMethod();

        OpLog opLog = method.getAnnotation(OpLog.class);

        Object response = null;

        try {

            // 目标方法执行

            response = pjp.proceed();

        } catch (Throwable throwable) {

            throw new Exception(throwable);

        } 

        if (StringUtils.isNotEmpty(opLog.opItemIdExpression())) {

            SpelExpressionParser parser = new SpelExpressionParser();

            Expression expression = parser.parseExpression(opLog.opItemIdExpression());

            EvaluationContext context = new StandardEvaluationContext();

            // 获取参数值

            Object[] args = pjp.getArgs();

            // 获取运行时参数的名称

            LocalVariableTableParameterNameDiscoverer discoverer

                = new LocalVariableTableParameterNameDiscoverer();

            String[] parameterNames = discoverer.getParameterNames(method);

            // 将参数绑定到context中

            if (parameterNames != null) {

                for (int i = 0; i < parameterNames.length; i++) {

                    context.setVariable(parameterNames[i], args[i]);

                }

            }

            // 将方法的resp当做变量放到context中,变量名称为该类名转化为小写字母开头的驼峰形式

            if (response != null) {

                context.setVariable(

                    CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, response.getClass().getSimpleName()),

                    response);

            }

            // 解析表达式,获取结果

            String itemId = String.valueOf(expression.getValue(context));

            // 执行日志记录

            handle(opLog.opType(), opLog.opItem(), itemId);

        }

        return response;

    }


    private void handle(OpType opType,  String opItem, String opItemId) {

      // 通过日志打印输出

      LOGGER.info("opType = " + opType.name() +",opItem = " +opItem + ",opItemId = " +opItemId);

    }

}

以上切面中,有几个点需要大家注意的:

  • 1、使用@Around注解来指定对标注了OpLog的方法设置切面。
  • 2、使用Spel的相关方法,通过指定的表示,从对应的参数中获取到目标对象的唯一性标识。
  • 3、再方法执行成功后,输出日志。

有了以上的切面及注解后,我们只需要在对应的方法上增加注解标注即可,如:

@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})

@OpLog(opType = OpType.QUERY, opItem = "order", opItemIdExpression = "#id")

public @ResponseBody

HashMap view(@RequestParam(name = "id") String id)

    throws Exception {

}

上面这种是入参的参数列表中已经有了被操作的对象的唯一性标识,直接使用#id指定即可。

如果被操作的对象的唯一性标识不在入参列表中,那么可能是入参的对象中的某一个属性,用法如下:

@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})

@OpLog(opType = OpType.QUERY, opItem = "order", opItemIdExpression = "#orderVo.id")

public @ResponseBody

HashMap update(OrderVO orderVo)

    throws Exception {

}

以上,即可从入参的OrderVO对象的id属性的值获取。

如果我们要记录的唯一性标识,在入参中没有的话,应该怎么办呢?最典型的就是插入方法,插入成功之前,根本不知道主键ID是什么,这种怎么办呢?

我们上面的切面中,做了一件事情,就是我们把方法的返回值也会使用表达式进行一次解析,如果可以解析得到具体的值,也是可以。如以下写法

@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})

@OpLog(opType = OpType.QUERY, opItem = "order", opItemIdExpression = "#insertResult.id")

public @ResponseBody

InsertResult insert(OrderVO orderVo)

    throws Exception {

    return orderDao.insert(orderVo);

}

以上,就是一个简单的使用自定义注解+切面进行日志记录的场景。下面我们再来看一个如何使用注解做方法参数的校验。

使用自定义注解做前置检查

当我们对外部提供接口的时候,会对其中的部分参数有一定的要求,比如某些参数值不能为空等。大多数情况下我们都需要自己主动进行校验,判断对方传入的值是否合理。

这里推荐一个使用HibernateValidator + 自定义注解 + AOP实现参数校验的方式。

首先我们会有一个具体的入参类,定义如下:

public class User {

    private String idempotentNo;

    @NotNull(

        message = "userName can't be null"

    )

    private String userName;

}

以上,对userName参数注明不能为null。

然后再使用Hibernate Validator定义一个工具类,用于做参数校验。

/**

 * 参数校验工具

 * @author Hollis

 */

public class BeanValidator {

    private static Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(true)

        .buildValidatorFactory().getValidator();

    /**

     * @param object object

     * @param groups groups

     */

    public static void validateObject(Object object, Class<?>... groups) throws ValidationException {

        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);

        if (constraintViolations.stream().findFirst().isPresent()) {

            throw new ValidationException(constraintViolations.stream().findFirst().get().getMessage());

        }

    }

}

以上代码,会对一个bean进行校验,一旦失败,就会抛出ValidationException。接下来定义一个注解:

/**

 * facade接口注解, 用于统一对facade进行参数校验及异常捕获

 * <pre>

 *      注意,使用该注解需要注意,该方法的返回值必须是BaseResponse的子类

 * </pre>

 */

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Facade {

}

这个注解里面没有任何参数,只用于标注那些方法要进行参数校验。

接下来定义切面:

/**

 * Facade的切面处理类,统一统计进行参数校验及异常捕获

 * @author Hollis

 */

@Aspect

@Component

public class FacadeAspect {

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

    @Autowired

    HttpServletRequest request;

    @Around("@annotation(com.hollis.annotation.Facade)")

    public Object facade(ProceedingJoinPoint pjp) throws Exception {

        Method method = ((MethodSignature)pjp.getSignature()).getMethod();

        Object[] args = pjp.getArgs();

        Class returnType = ((MethodSignature)pjp.getSignature()).getMethod().getReturnType();

        //循环遍历所有参数,进行参数校验

        for (Object parameter : args) {

            try {

                BeanValidator.validateObject(parameter);

            } catch (ValidationException e) {

                return getFailedResponse(returnType, e);

            }

        }

        try {

            // 目标方法执行

            Object response = pjp.proceed();

            return response;

        } catch (Throwable throwable) {

            return getFailedResponse(returnType, throwable);

        }

    }

    /**

     * 定义并返回一个通用的失败响应

     */

    private Object getFailedResponse(Class returnType, Throwable throwable)

        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        //如果返回值的类型为BaseResponse 的子类,则创建一个通用的失败响应

        if (returnType.getDeclaredConstructor().newInstance() instanceof BaseResponse) {

            BaseResponse response = (BaseResponse)returnType.getDeclaredConstructor().newInstance();

            response.setSuccess(false);

            response.setResponseMessage(throwable.toString());

            response.setResponseCode(GlobalConstant.BIZ_ERROR);

            return response;

        }

        LOGGER.error(

            "failed to getFailedResponse , returnType (" + returnType + ") is not instanceof BaseResponse");

        return null;

    }

}

以上代码,和前面的切面有点类似,主要是定义了一个切面,会对所有标注@Facade的方法进行统一处理,即在开始方法调用前进行参数校验,一旦校验失败,则返回一个固定的失败的Response。

特别需要注意的是,这里之所以可以返回一个固定的BaseResponse,是因为我们会要求我们的所有对外提供的接口的response必须继承BaseResponse类,这个类里面会定义一些默认的参数,如错误码等。

之后,只需要对需要参数校验的方法增加对应注解即可:

@Facade

public TestResponse query(User user) {

}

这样,有了以上注解和切面,我们就可以对所有的对外方法做统一的控制了。

其实,以上这个facadeAspect我省略了很多东西,我们真正使用的那个切面,不仅仅做了参数检查,还可以做很多其他事情。比如异常的统一处理、错误码的统一转换、记录方法执行时长、记录方法的入参出参等等。

总之,使用切面+自定义注解,我们可以统一做很多事情。除了以上的这几个场景,我们还有很多相似的用法,比如:

统一的缓存处理。如某些操作需要在操作前查缓存、操作后更新缓存。这种就可以通过自定义注解+切面的方式统一处理。

代码其实都差不多,思路也比较简单,就是通过自定义注解来标注需要被切面处理的累或者方法,然后在切面中对方法的执行过程进行干预,比如在执行前或者执行后做一些特殊的操作。

使用这种方式可以大大减少重复代码,大大提升代码的优雅性,方便我们使用。

但是同时也不能过度使用,因为注解看似简单,但是其实内部有很多逻辑是容易被忽略的。就像我之前写过一篇《Spring官方都推荐使用的@Transactional事务,为啥我不建议使用!》中提到的观点一样,无脑的使用切面和注解,可能会引入一些不必要的问题。

不管怎么说,自定义注解却是是一个很好的发明,可以减少很多重复代码。快快在你的项目中用起来吧。

注解的实现原理及如何自定义注解 1.前言 在springmvc及springboot中,注解随处可见,我们几乎每天都在跟他打交道;那么如何自定义注解呢?自定义注解会不会更香呢 2.Java注解理解 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然 阅读详情

相关推荐

LIGGGHTS颗粒模拟入门:从DEM原理到工程实践

离散元法(DEM)是一种用于模拟颗粒物质行为的数值方法,其核心原理是通过计算每个颗粒的运动和相互作用来预测颗粒系统的宏观行为。该方法基于牛顿第二定律和接触力学模型,能够精确描述颗粒间的碰撞、摩擦和粘结等微观机制。在工程实践中,DEM技术为优化工业设备设计、预测材料流动和减少实验成本提供了重要价值。它广泛应用于制药造粒、矿石破碎、粉体输送和农业加工等领域,帮助工程师和研究人员深入理解颗粒系统的复杂动力学。LIGGGHTS作为一款基于LAMMPS的开源DEM软件,继承了其高效的并行计算架构,并针对颗粒模拟进行了

weixin_33979203的博客 417

【java学习-Spring】Spring-data-jpa(Java Persistence API)和Template

1,概念 JPA的存在意义是为了整合第三方ORM框架,建立一种标准的方式ORM 访问数据库的统一。但是现阶段JPA几乎都是接口,实现都是Hibernate在做。我们都知道,在使用持久化工具的时候,一般都有一个对象来操作数据库,在原生的Hibernate中叫做Session,在MyBatis中叫做SqlSession,而在JPA中叫做EntityManager通过这个对象来操作数据库。 对象关系映...

午后阳光 3517

微信小程序后台定位与实时位置更新的实战指南

本文提供了微信小程序实现后台定位与实时位置更新的完整实战指南。针对小程序退到后台后位置更新中断的痛点,详细解析了基于`startLocationUpdateBackground`API的后台定位解决方案。内容涵盖从隐私协议配置、项目权限声明,到授权、启动、监听、停止的核心代码流程,并分享了真机调试、性能优化及权限引导等关键避坑经验,帮助开发者构建稳定可靠的后台位置服务。

weixin_29008055的博客 466

关于自定义注解与注解之间存在的问题

项目场景: springboot+mybaits+oracle 项目当中创建了自定义注解,用来对用户的功能模块进行权限配置。 问题描述: 在项目进行启动时,对用户功能模块权限进行初始化,初始化需要对使用了自定义注解的方法进行扫描,问题就出现在扫描不到使用过自定义注解的方法。错误信息如下: [2021-04-01 11:49:44] [ ERROR] com.bi.sys.utils.listener.ApplicationStartedListener [51] - null java.lang.NullP

lierjun 的专栏 308

TMS320C6678开发笔记1-6---C6678单核烧写程序

第6节 单核烧写加载程序 6.1节 TI参考文档 参考文档:《KeystoneI Bootloader Resources and FAQ》讲的非常好,建议一定要看 https://processors.wiki.ti.com/index.php/KeystoneI_Bootloader_Resources_and_FAQ#Direct_Boot_Examples_.28without_IBL.29 里面有三个工程: C6678 EVM SPI boot example C6657 EVM ..

kunkliu的博客 5691

WVP+ZLM国标平台实战:从设备注册失败到视频播放黑屏,我遇到的5个典型问题与解法

部署WVP+ZLM国标视频平台时,设备注册失败、视频播放黑屏等问题常常让运维人员头疼不已。本文将基于真实运维场景,剖析五个最具代表性的故障案例,提供从网络配置到版本兼容性的全链路解决方案。

weixin_33178839的博客 360

Java中的注解以及自定义注解

1、Annotation(注解) 概述 (1)、注解起到标识做用,比如Junit的@Test注解。 Junit会在运行时检查方法上是否存在此注解,如果存在,就通过反射来运行你的方法。注意标红的反射两个字,反射在注解里相当重要,写完你的自定义注解类后没啥用,必须要用反射才能让它动起来!所以需要对反射有了解,感兴趣的小可爱可以看下这篇:Java中的反射机制介绍 (2)、从 JDK 5.0 开...

曹举的个人博客 2万+

[Ethernet in CANoe]2--如何在CANoe中去仿真CP版本的SOME/IP通信

上篇文章()介绍了SOME/IP的两种类型的数据格式,根据作者目前的项目经验,目前在CANoe V18之前的版本,CP版本的arxml是最方便实现SOME/IP以太网仿真的。作者目前只有CANoe V17的license,所以本片文章是在CANoe 17上基于CP版本的arxml去做仿真模拟。

汽车ECU自动化测试 1764

Java自定义注解

Java-Java自定义注解 文章目录Java-Java自定义注解前言1、简介2、元注解3、自定义注解3.1 自定义注解3.2 数据模型使用注解3.3 定义一个“注解解析器”3.4 运行的代码3.5 结果 前言 Java 骚操作之一:自定义注解 1、简介 注解是一种能被添加到java源代码中的元数据,方法、类、参数和包都可以用注解来修饰。注解可以看作是一种特殊的标记,可以用在方法、类、参数和包上,程序在编译或者运行时可以检测到这些标记而进行一些特殊的处理。 2、元注解 元注解的作用就是负责注解其他注解

weixin_45020244的博客 1万+

CentOS7全隔离环境部署Nvidia Tesla A100 40G驱动与CUDA工具包实战

本文详细介绍了在CentOS7全隔离环境下部署Nvidia Tesla A100 40G显卡驱动与CUDA工具包的实战经验。通过构建本地YUM仓库、解决驱动依赖问题以及三重验证法,确保Tesla A100与CUDA 11.7的完美兼容。同时分享了Anaconda3离线部署技巧,帮助用户在隔离环境中高效搭建Python GPU开发环境。

weixin_27215337的博客 399

数据分片的三种方式:哈希、一致性哈希、按照数据范围分片

数据分片就是按照一定的规则,将数据集划分成相互独立、正交的数据子集,然后将数据子集分布到不同的节点上。通过设计合理的数据分片规则,可将系统中的数据分布在不同的物理数据库中,达到提升应用系统数据处理速度的目的。三种常用的数据分片方式:1. 哈希分片2. 一致性哈希分片(Consistent Hash)3. 按照数据范围分片(Range Based)数据分片的应用场景:1. 数据库扩展2. 分布式缓存对集群部署多个缓存节点,提高缓存的处理能力。

wjianwei666的专栏 1133

如何实现自定义注解

如何实现自定义注解   在我们实际开发过程中如果能合理的运用自定义注解,则会大大减少我们代码的开发量。那怎么才能实现自定义注解呢?废话不多说,直接上干货! 一、创建注解   这一步呢,我们可以理解成对应的实体类,我们要自定义注解,也需要这么一个东西,注解的名称,有哪些属性等等。 package org.disp.kingmouse.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retent

qq_22331931的博客 1万+

Qt入门教程【高级控件篇】QModelIndex索引

QModelIndex索引

小鱼酱的博客 4465

自定义注解 及 解析自定义注解

目录 自定义注解需要注意 元注解 使用自定义注解 解析注解 自定义注解需要注意 1-使用@interface来定义注解 2-成员变量使用的是无参数、无异常的方式进行声明 例如 想要声明变量,正常方式是String name,而注解中需要String name();来定义成员变量 3-使用default来给成员变量设置默认值 4-成员变量的类型。可以是基本数据类型。还可以是String ,class ,annotation ,enumerate 5-如果注解中只有一个成员变量,...

AmbroseLe 2530

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

自定义注解实现@NotNull注解

先了解一下基本的自定义注解的时候,常用的注解含义 @Documented // 代表这个注解,可以被javadoc 处理的(加不加都行) @Retention(RetentionPolicy.RUNTIME) // RetentionPolicy 生命周期,一共有三个 // SOURCE 只留在源码,编译好后的代码是不有该注解的,该注解一旦编译就不存在了 ; // class 只停留在字节码,...

树欲静而风不止 1万+

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

注解,自定义注解和元注解

自定义注解就是自己做一个注解来使用value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!!但是如果有多个属性, 且多个属性没有默认值,那么value名称是不能省略的。

CX的博客 1172

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java注解以及自定义注解

Java注解以及自定义注解

YIYIYI 1968

springboot 自定义注解

Annotation表示注解。是JDK1.5的新特性。注解的主要作用:对我们的程序进行标注。通过注解可以给类增加额外的信息。注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。public @interface 注解名称 {public 属性类型 属性名();注解中的属性可以有默认值,格式为:数据类型 属性名() default 默认值;​属性类型可以是基本数据类型,String,Class,注解,枚举,以及上述类型的数组​。

weixin_68537303的博客 2370

条件注解及自定义注解

目录结构:如何自定义注解?注解其实就是一种标记,可以在程序代码中的关键节点(类、方法、变量、参数、包)上打上这些标记,然后程序在编译时或运行时可以检测到这些标记从而执行一些特殊操作。因此可以得出自定义注解使用的基本流程:第一步,定义注解——相当于定义标记;第二步,配置注解——把标记打在需要用到的程序代码中;第三步,解析注解——在编译期或运行时检测到标记,并进行特殊操作。在底层实现上,所有定义的注解都会自动继承接口。

cxbtdd的博客 440

注解之自定义注解实现

Java自定义注解一般使用场景为自定义注解+拦截器或者AOP,使用自定义注解来自己设计框架,使得代码看起来非常优雅。本文主要介绍使用自定义注解+AOP来实现。

Java__EE小白成长之路 3058

用自定义注解做点什么——自定义注解有什么用

用自定义注解做点什么 前言 你不一定听过注解,但你一定对@Override不陌生。 当我们重写父类方法的时候我们就看到了@Override。我们知道它表示父类方法被子类重写了。 现在告诉你,@Override就是一个注解。 也许你会疑惑注解是什么? 注解(annotation)是JDK5之后引进的新特性,是一种特殊的注释,之所以说它特殊是因为不同于普通注释(comment)能存在于源码,而且还能存在编译期跟运行期,会最终编译成一个.class文件,所以注解能有比普通注释更多的功能。 接下来,先入个门,然后

qq_43842093的博客 2523

Java自定义注解开发

一、JAVA注解 1、java注解的定义 Java注解是附加在代码中的一些元信息,用于一些工具在编译、 运行时进行解析和使用,起到说明、配置的功能。 注解相关类都包含在java.lang.annotation包中。 2、java注解的分类 2.1 JDK基本注解 2.1.1 @Override 重写 2.1.2 @Deprecated 已过时 2.1.3 @SuppressWarnings(value = ...

zxy15974062965的博客 7173

自定义注解的使用

自定义注解的使用 文章目录自定义注解的使用前言一、注解是什么?二、四个元注解三、自定义注解示例1.原生方式2.读入数据总结 前言 一、注解是什么? 注解也叫元数据,例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解 一般常用的注解可以分为三类: 一类是Java自带的标准注解,包括@Override(标明重写某个方法)、@Deprecated(标明某个类或方法过时)和@Suppres

weixin_41979002的博客 4506

Java注解,元注解,自定义注解的使用

自定义注解,需要使用@interface来定义,使用@interface自定义注解时,自动继承java.lang.annotation.Annotation接口。权限修饰符 @interface 注解名 {// 定义内容 String value() default "";// 参数类型 参数名 默认值;@interface 用来声明一个注解其中上面的表示这个注解需要提供一个String类型的参数,且其默认值为空字符串default ""value() 就是参数的名称。

m0_63622279的博客 1909
上一篇: Spring AOP配置 之 @Aspect
下一篇: k8s资源清单与存活检测和就绪检测
Persistence___
博客等级 码龄8年 47粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值