找回密码
 立即注册
首页 业界区 业界 JAVA自定义注解

JAVA自定义注解

少屠 2025-11-27 12:00:03
什么是注解?

注解是一种特殊的接口,用于为Java代码提供元数据。它们不会直接影响代码的执行,但可以被编译器、开发工具或运行时环境读取和使用。
Java内置了一些常用的注解,如:
@Override - 表示方法重写父类方法
@Deprecated - 表示代码已过时
@SuppressWarnings - 抑制编译器警告
注解的基本语法

定义注解

使用@interface关键字来定义注解:
 
  1. public @interface AutoFill {
  2. }
复制代码
 
元注解

元注解是用来注解其他注解的注解,Java提供了以下几种元注解:
@Target - 指定注解可以应用的目标元素类型
@Retention - 指定注解的保留策略
@Documented - 表示注解应该被包含在Javadoc中
@Inherited - 表示注解可以被继承
 
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface AutoFill {
  4.     /**
  5.      * 数据库操作类型:INSERT、UPDATE
  6.      */
  7.     OperationType value();
  8. }
复制代码
 
示例代码展示了一个用于公共字段自动填充的自定义注解,@Target明确注解可在方法上使用,@Retention明确在程序运行时可见。
 
注解元素

 
注解中可以定义元素,这些元素可以有默认值:
 
  1. public enum OperationType {
  2.     /**
  3.      * 更新操作
  4.      */
  5.     UPDATE,
  6.     /**
  7.      * 插入操作
  8.      */
  9.     INSERT
  10. }
复制代码
 
示例自定义注解中的value方法则用来返回上示枚举类型数据,明确 使用该注解的方法 的作用,使用方式如下:
 
  1. /**
  2.       * 更新员工信息
  3.       * @param employee
  4.       */
  5.      @AutoFill(OperationType.UPDATE)
  6.      void updateById(Employee employee);
复制代码
 
当注解只有一个方法且方法名为 value 时,使用时可以省略方法名,如果方法不叫 value,就必须明确指定方法名:
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface AutoFill {
  4.     /**
  5.      * 数据库操作类型:INSERT、UPDATE
  6.      */
  7.     OperationType type();
  8. }<br><br>
复制代码
  1. /**
  2.       * 更新员工信息
  3.       * @param employee
  4.       */
  5.      @AutoFill(type = OperationType.UPDATE)
  6.      void updateById(Employee employee);
复制代码
自定义注解的使用

通过反射处理注解

我们可以使用反射机制在运行时读取和处理注解:
 
  1. @Aspect
  2. @Component
  3. @Slf4j
  4. public class AutoFillAspect {
  5.     /**
  6.      * 公共字段自动填充切入点
  7.      */
  8.     @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
  9.     public void autoFillPointCut() {}
  10.     /**
  11.      * 公共字段自动填充
  12.      */
  13.     @Before("autoFillPointCut()")
  14.     public void autoFill(JoinPoint joinPoint) throws Throwable {
  15.         log.info("公共字段自动填充通知开始");
  16.         MethodSignature signature = (MethodSignature)joinPoint.getSignature();
  17.         AutoFill autoFill= signature.getMethod().getAnnotation(AutoFill.class);
  18.         // 获取数据库操作类型
  19.         Enum operationType = autoFill.value();
  20.         // 从ThreadLocal中获取当前登录用户的id
  21.         Long currentId = BaseContext.getCurrentId();
  22.         // 获取当前时间
  23.         LocalDateTime now = LocalDateTime.now();
  24.         // 从joinPoint中获取参数
  25.         Object[] args = joinPoint.getArgs();
  26.         if(args==null || args.length==0){
  27.             return;
  28.         }
  29.         // 从参数中获取实体对象
  30.         Object entity = args[0];
  31.         // 调用实体对象的方法,设置创建时间、创建人、更新时间、更新人
  32.         if(operationType==OperationType.INSERT){
  33.             try{
  34.                 Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
  35.                 Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
  36.                 Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
  37.                 Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
  38.                 setCreateTime.invoke(entity, now);
  39.                 setUpdateTime.invoke(entity, now);
  40.                 setCreateUser.invoke(entity, currentId);
  41.                 setUpdateUser.invoke(entity, currentId);
  42.             }catch (Exception e){
  43.                 log.error("公共字段自动填充通知异常", e);
  44.             }
  45.         }else if(operationType==OperationType.UPDATE){
  46.             try{
  47.                 Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
  48.                 Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
  49.                 setUpdateTime.invoke(entity, now);
  50.                 setUpdateUser.invoke(entity, currentId);
  51.             }catch (Exception e){
  52.                 log.error("公共字段自动填充通知异常", e);
  53.             }
  54.         }
  55.     }
  56. }
复制代码
 
上述示例展示的是@AutoFill注解进行公共字段自动填充必要的切面类。
  1. @Aspect
复制代码
该注解用于声明切面类。
  1. /**
  2.      * 公共字段自动填充切入点
  3.      */
  4.     @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
  5.     public void autoFillPointCut() {}
复制代码
这一部分用于声明哪些部分需要拦截。(在com.sky.mapper包下的所有类及其所有方法 被自定义注解(@AutoFill)所标注)
  1.     /**
  2.      * 公共字段自动填充
  3.      */
  4.     @Before("autoFillPointCut()")
  5.     public void autoFill(JoinPoint joinPoint) throws Throwable
复制代码
@Before: 表示这是一个前置通知,在目标方法执行之前运行。
autoFillPointCut(): 引用一个切点表达式,定义了哪些方法需要被拦截。
 
JoinPoint: AOP 连接点对象,可以获取被拦截方法的详细信息:方法名、参数、目标对象等。通过 joinPoint.getArgs() 获取方法参数。
 
  1. MethodSignature signature = (MethodSignature)joinPoint.getSignature();
  2. AutoFill autoFill= signature.getMethod().getAnnotation(AutoFill.class);
  3. // 获取数据库操作类型
  4. Enum operationType = autoFill.value();
复制代码
 
joinPoint.getSignature(): 获取连接点的签名信息。
(MethodSignature): 强制转换为 MethodSignature 类型,因为 Spring AOP 只拦截方法。
signature.getMethod(): 获取被拦截的 Method 对象。
.getAnnotation(AutoFill.class): 从方法上获取 @AutoFill 注解。
autoFill.value(): 调用注解的 value() 方法,获取注解中定义的枚举值。
 
  1. // 从joinPoint中获取参数
  2.         Object[] args = joinPoint.getArgs();
  3.         if(args==null || args.length==0){
  4.             return;
  5.         }
  6.         // 从参数中获取实体对象
  7.         Object entity = args[0];
复制代码
 
利用从joinPoint中获取的参数获得原本方法中传递的实体对象。
  1. Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
  2. Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
  3. setCreateTime.invoke(entity, now);
  4. setCreateUser.invoke(entity, currentId);
复制代码
利用反射为对象设置公共字段。
最终效果
 
1.png

2.png

3.png

4.png

5.png

@AutoFill注解能有效替代原本冗长且重复的公共字段设置代码。
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册