千家信息网

Java中怎么自定义注解

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,这篇文章将为大家详细讲解有关Java中怎么自定义注解,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java基础,注解与自定义注解Java 注解Anno
千家信息网最后更新 2026年10月31日Java中怎么自定义注解

这篇文章将为大家详细讲解有关Java中怎么自定义注解,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

Java基础,注解与自定义注解

Java 注解Annotation,是 JDK5.0 引入的一种注释机制。

一、自带注解

在学习自定义注解前,先了解一下Java内部定义的一套注解:共有7个,3个在java.lang中,剩下的四个在java.lang.annotation中。

作用在类或者方法上:

@Override  检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。@Deprecated  标记已过时方法。不推荐使用@SuppressWarnings  指示编译器去忽略注解中声明的警告

作用在其他注解上

@Retention  标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。@Documented  标记这些注解是否包含在用户文档中@Target  标记这个注解应该是哪种 Java 成员@Inherited  标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

额外添加的3个注解:

@SafeVarargs  Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。@FunctionalInterface  Java 8 开始支持,标识一个匿名函数或函数式接口。@Repeatable  Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

二、注解结构

Annotation有三个重要的主干类,分别为:Annotation、ElememtType、RetentionPolicy

1、Annotation:

public interface Annotation {    boolean equals(Object obj);    int hashCode();    String toString();    Class annotationType();}

2、ElementType:

其指定Annotation的类型,如METHOD ,则该Annotation只能修饰方法

public enum ElementType {    TYPE,                                   //类、接口、枚举                    FIELD,                                  //字段、枚举常量    METHOD,                                 //方法    PARAMETER,                              //参数    CONSTRUCTOR,                    //构造方法    LOCAL_VARIABLE,                 //局部变量    ANNOTATION_TYPE,                //注释类型    PACKAGE,                                //包    TYPE_PARAMETER,    TYPE_USE}

3、RetentionPolicy:

public enum RetentionPolicy {        SOURCE,         //Annotation仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了    CLASS,          //编译器将Annotation存储于类对应的.class文件中。默认行为    RUNTIME         //编译器将Annotation存储于class文件中,并且可由JVM读入        }

RUNTIME:注释将由编译器记录在类文件中,并由VM在运行时保留,因此它们可以被反射读取。

CLASS:注释将由编译器记录在类文件中,但不需要在运行时由VM保留。

4、例子

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})@Documented@Repeatable(ComponentScans.class)public @interface ComponentScan{        }

@interface

@interface定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个Annotation。而不是声明了一个interface。(@interface和interface是不同的)。

定义 Annotation 时,@interface 是必须的。

注意:它和我们通常的 implemented 实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。

@Document

类和方法的 Annotation 在缺省情况下是不出现在 javadoc 中的。如果使用 @Documented 修饰该 Annotation,则表示它可以出现在 javadoc 中。

@Target

ElementType 是 Annotation 的类型属性。而 @Target 的作用,就是来指定 Annotation 的类型属性。

@Target(ElementType.TYPE) 的意思就是指定该 Annotation 的类型是 ElementType.TYPE。这就意味着,ComponentScan 是来修饰"类、接口(包括注释类型)或枚举声明"的注解。

@Retention

RetentionPolicy 是 Annotation 的策略属性,而 @Retention 的作用,就是指定 Annotation 的策略属性。

@Retention(RetentionPolicy.RUNTIME) 的意思就是指定该 Annotation 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将该 Annotation 信息保留在 .class 文件中,并且能被虚拟机读取。

注意:定义 Annotation 时,@Retention 可有可无。若没有 @Retention,则默认是 RetentionPolicy.CLASS。

三、自定义Annotation

我们下面自定义一个Log日志注解:一个 在 controller的method上的注解,该注解会将用户对这个方法的操作 记录到数据库中

3.1、操作类型

package com.lee.common.enums;/** * 业务操作类型 *  */public enum BusinessType{    /**     * 其它     */    OTHER,    /**     * 新增     */    INSERT,    /**     * 修改     */    UPDATE,    /**     * 删除     */    DELETE,    /**     * 授权     */    GRANT,    /**     * 导出     */    EXPORT,    /**     * 导入     */    IMPORT,    /**     * 强退     */    FORCE,    /**     * 生成代码     */    GENCODE,        /**     * 清空数据     */    CLEAN,}

3.2、自定义注解

package com.lee.common.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import com.lee.common.enums.BusinessType;import com.lee.common.enums.OperatorType;/** * 自定义操作日志记录注解 */@Target({ ElementType.PARAMETER, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Log{    /**     * 模块      */    public String title() default "";    /**     * 功能     */    public BusinessType businessType() default BusinessType.OTHER;    /**     * 操作人类别     */    public OperatorType operatorType() default OperatorType.MANAGE;    /**     * 是否保存请求的参数     */    public boolean isSaveRequestData() default true;}

3.3、日志处理Aspect

package com.lee.framework.aspectj;import java.lang.reflect.Method;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.servlet.HandlerMapping;import com.alibaba.fastjson.JSON;import com.lee.common.annotation.Log;import com.lee.common.core.domain.model.LoginUser;import com.lee.common.enums.BusinessStatus;import com.lee.common.enums.HttpMethod;import com.lee.common.utils.ServletUtils;import com.lee.common.utils.StringUtils;import com.lee.common.utils.ip.IpUtils;import com.lee.common.utils.spring.SpringUtils;import com.lee.framework.manager.AsyncManager;import com.lee.framework.manager.factory.AsyncFactory;import com.lee.framework.web.service.TokenService;import com.lee.system.domain.SysOperLog;/** * 操作日志记录处理 *  * @author lee */@Aspect@Componentpublic class LogAspect{    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);    // 配置织入点    @Pointcut("@annotation(com.lee.common.annotation.Log)")    public void logPointCut()    {    }    /**     * 处理完请求后执行     *     * @param joinPoint 切点     */    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)    {        handleLog(joinPoint, null, jsonResult);    }    /**     * 拦截异常操作     *      * @param joinPoint 切点     * @param e 异常     */    @AfterThrowing(value = "logPointCut()", throwing = "e")    public void doAfterThrowing(JoinPoint joinPoint, Exception e)    {        handleLog(joinPoint, e, null);    }    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)    {        try        {            // 获得注解            Log controllerLog = getAnnotationLog(joinPoint);            if (controllerLog == null)            {                return;            }            // 获取当前的用户            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());            // *========数据库日志=========*//            SysOperLog operLog = new SysOperLog();            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());            // 请求的地址            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());            operLog.setOperIp(ip);            // 返回参数            operLog.setJsonResult(JSON.toJSONString(jsonResult));            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());            if (loginUser != null)            {                operLog.setOperName(loginUser.getUsername());            }            if (e != null)            {                operLog.setStatus(BusinessStatus.FAIL.ordinal());                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));            }            // 设置方法名称            String className = joinPoint.getTarget().getClass().getName();            String methodName = joinPoint.getSignature().getName();            operLog.setMethod(className + "." + methodName + "()");            // 设置请求方式            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());            // 处理设置注解上的参数            getControllerMethodDescription(joinPoint, controllerLog, operLog);            // 保存数据库            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));        }        catch (Exception exp)        {            // 记录本地异常日志            log.error("==前置通知异常==");            log.error("异常信息:{}", exp.getMessage());            exp.printStackTrace();        }    }    /**     * 获取注解中对方法的描述信息 用于Controller层注解     *      * @param log 日志     * @param operLog 操作日志     * @throws Exception     */    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception    {        // 设置action动作        operLog.setBusinessType(log.businessType().ordinal());        // 设置标题        operLog.setTitle(log.title());        // 设置操作人类别        operLog.setOperatorType(log.operatorType().ordinal());        // 是否需要保存request,参数和值        if (log.isSaveRequestData())        {            // 获取参数的信息,传入到数据库中。            setRequestValue(joinPoint, operLog);        }    }    /**     * 获取请求的参数,放到log中     *      * @param operLog 操作日志     * @throws Exception 异常     */    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception    {        String requestMethod = operLog.getRequestMethod();        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))        {            String params = argsArrayToString(joinPoint.getArgs());            operLog.setOperParam(StringUtils.substring(params, 0, 2000));        }        else        {            Map paramsMap = (Map) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));        }    }    /**     * 是否存在注解,如果存在就获取     */    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception    {        Signature signature = joinPoint.getSignature();        MethodSignature methodSignature = (MethodSignature) signature;        Method method = methodSignature.getMethod();        if (method != null)        {            return method.getAnnotation(Log.class);        }        return null;    }    /**     * 参数拼装     */    private String argsArrayToString(Object[] paramsArray)    {        String params = "";        if (paramsArray != null && paramsArray.length > 0)        {            for (int i = 0; i < paramsArray.length; i++)            {                if (!isFilterObject(paramsArray[i]))                {                    Object jsonObj = JSON.toJSON(paramsArray[i]);                    params += jsonObj.toString() + " ";                }            }        }        return params.trim();    }    /**     * 判断是否需要过滤的对象。     *      * @param o 对象信息。     * @return 如果是需要过滤的对象,则返回true;否则返回false。     */    public boolean isFilterObject(final Object o)    {        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;    }}

3.4、注解的使用

/** * 修改推荐位 */@Log(title = "推荐位", businessType = BusinessType.UPDATE)@PutMapping("/edit")public AjaxResult edit(@RequestBody GsRecommPosition gsRecommPosition){    Long gsRecommPositionId = gsRecommPosition.getGsRecommPositionId();    boolean condition = recommPositionHasCategory(gsRecommPositionId);    return toAjax(gsRecommPositionService.updateGsRecommPosition(gsRecommPosition));}/**  * 删除推荐位  */@Log(title = "推荐位", businessType = BusinessType.DELETE)@DeleteMapping("delete/{gsRecommPositionId}")public AjaxResult remove(@PathVariable Long gsRecommPositionId){    boolean condition = recommPositionHasCategory(gsRecommPositionId);    return toAjax(gsRecommPositionService.deleteGsRecommPositionById(gsRecommPositionId));}

四、JoinPoint解析

1、JoinPoint

对象封装了SpringAop切面方法中的信息

方法名功能
Signature getSignature();获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs();获取传入目标方法的参数对象
Object getTarget();获取被代理的对象
Object getThis();获取代理对象
joinPoint.getSignature().getName(); // 获取目标方法名joinPoint.getSignature().getDeclaringType().getSimpleName(); // 获取目标方法所属类的简单类名joinPoint.getSignature().getDeclaringTypeName(); // 获取目标方法所属类的类名joinPoint.getSignature().getModifiers(); // 获取目标方法声明类型(public、private、protected)Object[] args = joinPoint.getArgs(); // 获取传入目标方法的参数,返回一个数组joinPoint.getTarget(); // 获取被代理的对象joinPoint.getThis(); // 获取代理对象自己//获取自定义注解的信息MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();Method method = methodSignature.getMethod();CustomLog customLog = methodSignature.getMethod().getAnnotation(CustomLog.class);

2、ProceedingJoinPoint

ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中

Object proceed() throws Throwable //执行目标方法 Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法

关于Java中怎么自定义注解就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

注解 方法 对象 参数 信息 编译 接口 日志 目标 类型 编译器 文件 处理 就是 数据 注释 推荐 作用 属性 数据库 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 广东猪兼强互联网科技有限公司 嘟嘟瓜互联网科技 互联网科技革命 互联网科技论文 云电互联网科技 善班互联网科技有限公司 互联网金融 科技创新 盛创互联网科技有限公司 深圳卡尔迅互联网科技有限公司怎么样 卫星互联网科技股票 科技赋能互联网健康 宁夏众和广鑫互联网科技有限公司 宜昌元轩互联网科技有限公司 互联网科技大奖都有哪些公司 世界互联网领先科技成果获奖 互联网科技公司营业执照怎么办理 工业互联网展湾科技股份有限公司 有人说阿里系是互联网科技企业 互联网科技机房 科技和互联网行业的特点 北京路客互联网科技有限公司 金融科技创新监管互联网金融 上海喔噻互联网科技 衡水科技产业互联网平台 昭通云南众福互联网科技有限公司 洛阳共同富裕互联网科技有限公司 互联网金融科技公司的优势 科技互联网行业投资研究 中国科技和美国互联网 科技信息时代互联网发展
0