任丘市奥力斯涂料厂

热线电话:18232851235
任丘市奥力斯涂料厂
热门搜索: AI 雄安 创新 服务 杭州

上海防火门专用胶厂 Java自定义注解指南: 从基础到实战落地

产品中心 点击次数:122 发布日期:2026-02-11 18:34
PVC管件胶

Java Java自定义注解指南:从基础到实战落地在 Java 开发中,注解(Annotation)是种元数据形式,它不直接影响代码的执行逻辑,却能为代码提供额外的描述信息,被编译器、框架或工具解析利用。从 JDK 内置的 @Override 、@Deprecated ,到 Spring 的 @Controller 、MyBatis 的 @Mapper ,注解已成为框架开发、代码简化、逻辑解耦的核心手段。而自定义注解,是让开发者能够根据业务需求封装属元数据,实现灵活的扩展。本文将从基础概念到实战场景上海防火门专用胶厂,拆解自定义注解的定义、解析与应用,助力开发者掌握这核心技能。

、注解核心认知:什么是注解?注解是 Java 5引入的特,本质是种特殊的接口(继承自 java.lang.annotation.Annotation ),用于在代码中嵌入元数据。其核心价值在于“ 解耦 ”——将非业务逻辑(如日志、权限、校验、配置)与业务代码分离,由门的处理器解析注解并执行对应逻辑,大幅提升代码的可维护和灵活。

#后端 #分布式1. 注解的分类按使用场景和作用范围,注解可分为三类: 内置注解 :JDK自带,用于标准开发场景,如 @Override (重写校验)、 @Deprecated (标记过时)、 @SuppressWarnings (压制警告);三框架注解 :框架封装的注解,如Spring的 @Autowired (依赖注入)、MyBatis的 @Select (SQL映射)、Lombok的 @Data (属生成);自定义注解 :开发者根据业务需求自定义的注解,用于封装属元数据,如接口权限校验注解、日志记录注解、参数校验注解等。2. 注解的核心特元数据属:注解可包含多个属,用于存储具体的配置信息(如注解参数、生范围);执行逻辑:注解本身仅提供元数据,需配“注解处理器”(解析工具)才能实现;可作用于多元素:注解可标注在类、法、字段、参数、包等Java元素上,具体范围由元注解指定。二、自定义注解基础:定义语法与元注解自定义注解的核心是“ 元注解 + 注解属 ”:元注解用于定义注解的自身行为(如生范围、生命周期),注解属用于存储自定义配置信息。

1. 元注解:注解的“注解”JDK 提供4个核心元注解,用于约束自定义注解的特,是自定义注解的备要素:

| @Target | 指定注解可作用的 Java 元素范围 | ElementType.TYPE(类/接口)、METHOD(法)、FIELD(字段)、PARAMETER(参数)、CONSTRUCTOR(构造器)等 | | @Retention | 指定注解的生命周期(保留阶段) | RetentionPolicy.SOURCE(仅源码,编译后丢弃)、CLASS(编译后保留在 class 文件,运行时丢弃,默认)、RUNTIME(运行时保留,可通过反射解析,常用) | | @Documented | 指定注解是否被 javadoc 工具生成文档 | 取值,仅作为标记 | | @Inherited | 指定注解是否可被子类继承(仅作用于类注解) | 取值,仅作为标记 |

核心提醒:@Retention(RetentionPolicy.RUNTIME) 是多数实战场景的备配置,只有设置为 RUNTIME,才能在程序运行时通过反射解析注解,实现动态。

2. 自定义注解定义语法自定义注解使用 @interface 关键字声明,语法结构为:元注解 + 注解名称 + 注解属。

// 元注解组

@Target({ElementType.METHOD, ElementType.TYPE}) // 作用于类和法

@Retention(RetentionPolicy.RUNTIME) // 运行时保留,支持反射解析

@Documented // 生成javadoc文档

@Inherited // 允许子类继承

public @interface MyAnnotation {

// 注解属:格式为“属类型 属名 [default 默认值];”

String value default ""; // 特殊属:value,使用时可省略属名直接赋值

int order default 0; // 普通属,带默认值

String[] tags; // 数组类型属,默认值,使用时须赋值

奥力斯    泡沫板橡塑板专用胶报价    联系人:王经理    手机:18232851235(微信同号)    地址:河北省任丘市北辛庄乡南代河工业区

}

3. 注解属的规则与注意事项注解属的声明有严格规则,不符规则会致编译失败: 属类型限制 :仅支持基本类型(int、boolean等)、String、Class、枚举、注解,及以上类型的数组;不支持对象、集等复杂类型。默认值规则 :属可通过 default 指定默认值,默认值的属,使用注解时须显式赋值。value属特殊 :若注解仅含value个属,或其他属都有默认值,使用时可省略“value=”,直接赋值;若有多个属默认值,须显式指定属名。数组属赋值 :单个值可直接赋值,多个值需用 {} 包裹,如 tags = {"log", "auth"} 。4. 注解的使用式定义完注解后,可在指定范围的 Java 元素上使用,根据属是否有默认值,赋值式不同:

// 作用于类,所有属显式赋值

@MyAnnotation(value = "user-service"上海防火门专用胶厂, order = 1, tags = {"service", "user"})

public class UserService {

// 作用于法,value 属省略名称,tags 赋值单个值 @MyAnnotation("get-user") public User getUserById(@MyAnnotation("user-id") Long id) { return new User; } }

三、自定义注解实战:解析与落地注解本身仅为元数据,需通过“注解处理器”解析并执行逻辑。根据注解的生命周期,解析式分为两类:SOURCE 阶段通过 APT(注解处理器工具)解析,RUNTIME 阶段通过反射解析。其中,反射解析是常用、灵活的式,保温护角专用胶适用于多数业务场景。

实战场景1:接口日志记录注解需求:自定义 @LogRecord 注解,标注在接口法上,记录法调用者、调用时间、执行耗时,实现侵入式日志记录。

1. 定义注解import java.lang.annotation.*;

@Target(ElementType.METHOD) // 仅作用于法 @Retention(RetentionPolicy.RUNTIME) // 运行时保留,支持反射 @Documented public @interface LogRecord { // 日志描述,默认取法名 String desc default ""; // 是否记录请求参数 boolean recordParam default true; // 是否记录返回结果 boolean recordResult default false; }

2. 实现注解处理器(反射解析)通过 Spring AOP 拦截标注了 @LogRecord 的法,反射解析注解属,执行日志记录逻辑(非 Spring 环境可通过动态代理实现)。

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

import java.time.LocalDateTime;

// 切面类,拦截注解标注的法 @Aspect @Component public class LogRecordAspect {

// 切入点:拦截所有标注@LogRecord 的法 @Around("@annotation(com.example.annotation.LogRecord)") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { // 1. 反射获取法及注解属 MethodSignature signature = (MethodSignature) joinPoint.getSignature; Method method = signature.getMethod; LogRecord logRecord = method.getAnnotation(LogRecord.class);

// 2. 解析注解属 String desc = logRecord.desc.isEmpty ? method.getName : logRecord.desc; boolean recordParam = logRecord.recordParam; boolean recordResult = logRecord.recordResult;

// 3. 日志前置记录 LocalDateTime startTime = LocalDateTime.now; String username = getCurrentUsername; // 模拟获取当前登录用户 System.out.printf("[日志记录] 时间:s,用户:s,操作:sn", startTime, username, desc); if (recordParam) { Object[] args = joinPoint.getArgs; System.out.printf("[日志记录] 请求参数:sn", args); }

// 4. 执行目标法 long start = System.currentTimeMillis; Object result = joinPoint.proceed; // 执行原法 long cost = System.currentTimeMillis - start;

// 5. 日志后置记录 if (recordResult) { System.out.printf("[日志记录] 返回结果:sn", result); } System.out.printf("[日志记录] 执行耗时:dmsn", cost);

return result; }上海防火门专用胶厂

// 模拟获取当前登录用户 private String getCurrentUsername { return "admin"; } }

3. 注解使用与果验证@RestController

@RequestMapping("/user")

public class UserController {

// 使用日志注解,配置记录参数和结果 @LogRecord(desc = "根据 ID 查询用户", recordParam = true, recordResult = true) @GetMapping("/{id}") public User getUserById(@PathVariable Long id) { User user = new User; user.setId(id); user.setUsername("zhangsan"); return user; } }

调用接口后,控制台输出日志:

[日志记录] 时间:2026-01-29T15:30:00,用户:admin,操作:根据ID查询用户

[日志记录] 请求参数:[1]

[日志记录] 返回结果:User(id=1, username=zhangsan)

[日志记录] 执行耗时:12ms

实战场景2:接口权限校验注解需求:自定义 @RequiresPermission 注解,标注在接口法上,校验当前用户是否拥有指定权限,权限则抛出异常。

1. 定义注解@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface RequiresPermission {

// 所需权限标识(支持多个)

String[] value;

// 权限时的提示信息

String message default "权限访问该接口";

}

2. 实现权限校验切面@Aspect上海防火门专用胶厂

@Component

public class PermissionAspect {

@Around("@annotation(com.example.annotation.RequiresPermission)") public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable { // 1. 解析注解 MethodSignature signature = (MethodSignature) joinPoint.getSignature; RequiresPermission permission = signature.getMethod.getAnnotation(RequiresPermission.class); String[] requiredPermissions = permission.value; String message = permission.message;

// 2. 获取当前用户拥有的权限(模拟从登录上下文获取) List userPermissions = getCurrentUserPermissions;

// 3. 权限校验 boolean hasPermission = Arrays.stream(requiredPermissions) .anyMatch(userPermissions::contains); if (!hasPermission) { throw new RuntimeException(message); }

// 4. 校验通过,执行目标法 return joinPoint.proceed; }

// 模拟获取当前用户权限 private List getCurrentUserPermissions { return Arrays.asList("user:query", "user:add"); // admin 用户拥有的权限 } }

3. 注解使用与果验证@RestController

@RequestMapping("/user")

public class UserController {

// 要求拥有"user:query"权限 @RequiresPermission("user:query") @GetMapping("/{id}") public User getUserById(@PathVariable Long id) { return new User(id, "zhangsan"); }

// 要求拥有"user:delete"权限(当前用户此权限) @RequiresPermission(value = "user:delete", message = "删除用户权限") @DeleteMapping("/{id}") public String deleteUser(@PathVariable Long id) { return "删除成功"; } }

调用删除接口时,因权限抛出异常:java.lang.RuntimeException: 删除用户权限 ,实现权限校验。

四、自定义注解进阶技巧1. 注解组:复用注解逻辑可将多个注解组为个复注解,简化使用场景。例如,将日志记录与权限校验注解组为 @LogAndAuth ,标注次即可触发两个。

// 复注解:组@LogRecord和@RequiresPermission

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@LogRecord(desc = "需权限校验的操作", recordParam = true)

@RequiresPermission("admin:operate")

public @interface LogAndAuth {

// 可重写组注解的属(可选)

String logDesc default "";

}

使用时,标注复注解即可:

@LogAndAuth(logDesc = "管理员操作")

@PostMapping("/admin/operate")

public String adminOperate {

return "操作成功";

}

2. 注解与枚举结:规范属取值当注解属取值有限时,可结枚举类型,避硬编码,提升代码规范。

// 定义日志别枚举

public enum LogLevel {

INFO, WARN, ERROR

}

// 注解属使用枚举 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { LogLevel level default LogLevel.INFO; // 枚举类型属 String desc; }

// 使用注解 @Log(level = LogLevel.WARN, desc = "敏感操作日志") public void sensitiveOperate { // 业务逻辑 }

3. APT解析:编译期生成代码对于 @Retention(RetentionPolicy.SOURCE) 的注解,可通过 APT(Annotation Processing Tool)在编译期解析注解,自动生成代码(如 Lombok 的 @Data 生成 getter/setter)。核心是实现 javax.annotation.processing.AbstractProcessor ,重写 process 法解析注解并生成代码。

适用场景:需在编译期生成模板代码的场景(如 ORM 映射、DTO 转换),优点是运行时反射开销,能优异;缺点是开发复杂度于反射解析。

五、自定义注解频避坑指南1. 坑点1:注解法被解析,不生现象 :标注注解后,对应触发,控制台日志或校验逻辑未执行。规避案 :

检查元注解 @Retention 是否设置为 RUNTIME ,非RUNTIME法通过反射解析;Spring AOP场景:确保切面类添加 @Aspect 和 @Component ,且包路径被Spring扫描;确认注解作用范围( @Target )与使用位置致(如法注解不能标注在类上)。2. 坑点2:注解属赋值错误,编译失败现象 :使用注解时,编译提示“Attribute value must be constant”或“Missing required attribute”。规避案 :

注解属值须是常量(字面量、枚举、static final变量),不能是动态计的值;默认值的属须显式赋值,数组属多值用 {} 包裹,单值可直接赋值;避使用不支持的属类型(如List、Map、自定义对象)。3. 坑点3:切面拦截失,法未被增强现象 :Spring AOP 场景下,注解标注的法未被切面拦截,不生。规避案 :

避内部法调用:Spring AOP基于动态代理,类内部法调用法触发切面(需通过代理对象调用);切入点表达式正确:确保 @Around 等注解的切入点能匹配目标法(如注解全类名正确);非Spring Bean的类:切面仅对Spring容器管理的Bean生,未加 @Service / @Controller 的类法被拦截。4. 坑点4:注解继承失,子类父类注解现象 :父类标注注解,子类继承后,子类法对应。规避案 :

仅 @Inherited 元注解的类注解可被继承,法注解、字段注解不支持继承;子类需重写父类法并重新标注注解,或通过切面切入点调整为拦截父类注解。六、总结:自定义注解的核心价值与使用原则自定义注解的核心价值在于“ 用元数据驱动逻辑,实现代码解耦与复用 ”,它让非业务逻辑(日志、权限、校验)与业务代码分离,大幅提升代码的可维护和扩展。实际使用中需遵循以下原则:

按需设计:仅在需要封装元数据、解耦逻辑时使用注解,避过度设计致代码可读下降;明确范围:通过元注解严格约束注解的作用范围和生命周期,避滥用;能权衡:反射解析存在轻微能开销上海防火门专用胶厂,频调用场景可考虑APT编译期解析或缓存注解解析结果;规范命名:注解名称、属名需清晰易懂,结业务场景语义化(如 @RequiresPermission 、 @LogRecord )。从框架封装到业务开发,自定义注解已成为 Java 开发者的备技能。掌握本文所述的定义语法、解析式与实战场景,可灵活运用注解简化开发、封装通用逻辑,让代码优雅、具扩展。

相关词条:玻璃棉     塑料挤出机厂家     钢绞线    管道保温    PVC管道管件粘结胶

产品中心

18232851235