首页 > 基础资料 博客日记
JAVA自定义注解
2025-11-14 20:30:02基础资料围观5次
什么是注解?
注解是一种特殊的接口,用于为Java代码提供元数据。它们不会直接影响代码的执行,但可以被编译器、开发工具或运行时环境读取和使用。
Java内置了一些常用的注解,如:
@Override - 表示方法重写父类方法
@Deprecated - 表示代码已过时
@SuppressWarnings - 抑制编译器警告
注解的基本语法
定义注解
使用@interface关键字来定义注解:
public @interface AutoFill { }
元注解
元注解是用来注解其他注解的注解,Java提供了以下几种元注解:
@Target - 指定注解可以应用的目标元素类型
@Retention - 指定注解的保留策略
@Documented - 表示注解应该被包含在Javadoc中
@Inherited - 表示注解可以被继承
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { /** * 数据库操作类型:INSERT、UPDATE */ OperationType value(); }
示例代码展示了一个用于公共字段自动填充的自定义注解,@Target明确注解可在方法上使用,@Retention明确在程序运行时可见。
注解元素
注解中可以定义元素,这些元素可以有默认值:
public enum OperationType { /** * 更新操作 */ UPDATE, /** * 插入操作 */ INSERT }
示例自定义注解中的value方法则用来返回上示枚举类型数据,明确 使用该注解的方法 的作用,使用方式如下:
/** * 更新员工信息 * @param employee */ @AutoFill(OperationType.UPDATE) void updateById(Employee employee);
当注解只有一个方法且方法名为 value 时,使用时可以省略方法名,如果方法不叫 value,就必须明确指定方法名:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { /** * 数据库操作类型:INSERT、UPDATE */ OperationType type(); }
/**
* 更新员工信息
* @param employee
*/
@AutoFill(type = OperationType.UPDATE)
void updateById(Employee employee);
自定义注解的使用
通过反射处理注解
我们可以使用反射机制在运行时读取和处理注解:
@Aspect @Component @Slf4j public class AutoFillAspect { /** * 公共字段自动填充切入点 */ @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut() {} /** * 公共字段自动填充 */ @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint) throws Throwable { log.info("公共字段自动填充通知开始"); MethodSignature signature = (MethodSignature)joinPoint.getSignature(); AutoFill autoFill= signature.getMethod().getAnnotation(AutoFill.class); // 获取数据库操作类型 Enum operationType = autoFill.value(); // 从ThreadLocal中获取当前登录用户的id Long currentId = BaseContext.getCurrentId(); // 获取当前时间 LocalDateTime now = LocalDateTime.now(); // 从joinPoint中获取参数 Object[] args = joinPoint.getArgs(); if(args==null || args.length==0){ return; } // 从参数中获取实体对象 Object entity = args[0]; // 调用实体对象的方法,设置创建时间、创建人、更新时间、更新人 if(operationType==OperationType.INSERT){ try{ Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class); Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class); Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class); Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class); setCreateTime.invoke(entity, now); setUpdateTime.invoke(entity, now); setCreateUser.invoke(entity, currentId); setUpdateUser.invoke(entity, currentId); }catch (Exception e){ log.error("公共字段自动填充通知异常", e); } }else if(operationType==OperationType.UPDATE){ try{ Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class); Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class); setUpdateTime.invoke(entity, now); setUpdateUser.invoke(entity, currentId); }catch (Exception e){ log.error("公共字段自动填充通知异常", e); } } } }
上述示例展示的是@AutoFill注解进行公共字段自动填充必要的切面类。
@Aspect
该注解用于声明切面类。
/** * 公共字段自动填充切入点 */ @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut() {}
这一部分用于声明哪些部分需要拦截。(在com.sky.mapper包下的所有类及其所有方法 且 被自定义注解(@AutoFill)所标注)
/** * 公共字段自动填充 */ @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint) throws Throwable
@Before: 表示这是一个前置通知,在目标方法执行之前运行。
autoFillPointCut(): 引用一个切点表达式,定义了哪些方法需要被拦截。
JoinPoint: AOP 连接点对象,可以获取被拦截方法的详细信息:方法名、参数、目标对象等。通过 joinPoint.getArgs() 获取方法参数。
MethodSignature signature = (MethodSignature)joinPoint.getSignature(); AutoFill autoFill= signature.getMethod().getAnnotation(AutoFill.class); // 获取数据库操作类型 Enum operationType = autoFill.value();
joinPoint.getSignature(): 获取连接点的签名信息。
(MethodSignature): 强制转换为 MethodSignature 类型,因为 Spring AOP 只拦截方法。
signature.getMethod(): 获取被拦截的 Method 对象。
.getAnnotation(AutoFill.class): 从方法上获取 @AutoFill 注解。
autoFill.value(): 调用注解的 value() 方法,获取注解中定义的枚举值。
// 从joinPoint中获取参数 Object[] args = joinPoint.getArgs(); if(args==null || args.length==0){ return; } // 从参数中获取实体对象 Object entity = args[0];
利用从joinPoint中获取的参数获得原本方法中传递的实体对象。
Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
setCreateTime.invoke(entity, now);
setCreateUser.invoke(entity, currentId);
利用反射为对象设置公共字段。
最终效果





@AutoFill注解能有效替代原本冗长且重复的公共字段设置代码。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:

