> 文章列表 > 关于Java注解的一些理解 小结

关于Java注解的一些理解 小结

关于Java注解的一些理解 小结

目录

1. 常用注解和理解

2. 自定义注解

2.1 案例背景

2.2 设计思路

3 总结


1. 常用注解和理解

注解在我的理解下,就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相对应的处理。

可能有些抽象,简单来说注解其实在开发中是非常常见的,比如我们在使用各种框架时(Spring)就会用到非常多的注解,@Controller/@Param / @Select 等。

除了框架实现的注解,Java原生也有@Overrided、@Deprecated、@FunctionalInterface等基本注解,不过Java原生注解大多数用于标记和检查。除了这些基本注解之外,还有一种叫做元Annotation,用来修饰注解的,常用的元注解有@Retention和@Target。

  • @Retention注解可以简单理解为设置注解的生命周期。
  • @Target可以理解为注解的修饰对象(方法、成员变量、包等)。

2. 自定义注解

2.1 案例背景

假设现在有个监控告警系统,我们需要将一些程序的审计日志,比如成功/失败日志,通过自定义注解的方式设置监控指标,如果这些逻辑在业务代码中混合就会显得不那么优雅。

2.2 设计思路

类似这种监控信息显然都可以通过AOP切面的方式去处理,而如果使用注解配置相关的信息,配合AOP解析就会比较优雅。

自定义注解首先考虑我们是在何时解析这个注解,需要用到@Retention注解,这个注解会修饰我们自定义注解的生命周期,@Retention注解传入的是RetentionPolicy枚举,包括SOURCE、CLASS和RUNTIME

理解这块就得了解从java文件到class文件再到class被jvm加载的过程了。

从上图可以发现有个注解抽象语法树,这里其实就回去解析注解,然后做逻辑处理。

重点是,如果想在编译期间处理注解相关的逻辑,需要集成AbstractProcessor并实现process方法,比如lombok就是通过AnnotationProcessor集成了AbstractProcessor。

一般只要自定义注解中@Retention注解设置为SOURCE和CLASS这两种级别就需要继承并实现,因为这两个级别加载到jvm的时候,注解就被抹除了。

比如lombok的@Data注解能有getter/setter等方法,就是在这个时候加上去的。

所以一般来说自定义注解都是什么级别?

一般来说我们自定义注解都是RUNTIME级别的,因为大多数情况我们是根据运行时环境去做处理,因为反射是Java获取运行时信息的重要手段,自定义注解需要配合反射来使用。

@Around("@annotation(com.sanwai.service.openapi.monitor.Monitor)")
public Object antispan(ProceedingJoinPoint pjp) throws Throwable {String functionName = pjp.getSignature().getName();Map<String, String> tags = new HashMap<>();logger.info(functionName);tags.put("functionName", functionName);tags.put("flag", "done");monitor.sum(functionName, "start", 1);//方法执行开始时间long startTime = System.currentTimeMillis();Object o = null;try {o = pjp.proceed();} catch (Exception e) {//方法执行结束时间long endTime = System.currentTimeMillis();tags.put("flag", "fail");monitor.avg("rt", tags, endTime - startTime);monitor.sum(functionName, "fail", 1);throw e;}//方法执行结束时间long endTime = System.currentTimeMillis();monitor.avg("rt", tags, endTime - startTime);if (null != o) {monitor.sum(functionName, "done", 1);}return o;
}

3 总结

注解是代码的特殊标记,可以在编译、类加载、运行时被读取,对应了RetentionPolicy的三种级别。

SOURCE和CLASS级别需要继承AbstractProcessor,实现process方法处理自定义注解的逻辑,而RUNTIME是我们日常开发用的最多的,配合反射机制可以在很多场景优化代码。