【Java 注解】从入门到精通:上篇
概述
注解,对于一个从事 Java 开发行业的软件工程师而言,可以说是再熟悉不过了,在 SpringBoot 项目中,我们经常使用各种各样的注解:@Component
、@Bean
等。
注解一般在底层框架里使用居多,但你有了解过注解是如何工作的吗?注解对于我们的日常开发有什么特别之处呢?本文将带领你一探究竟,使你能够轻松使用注解进行实战开发。
重新认识一下注解
注解是 Java 提供的一种元数据机制,它们本质上是对代码的注释,能够在编译时或运行时被工具或框架解析和使用。注解本身不具备任何功能,但它们可以通过反射机制与代码中的其他部分交互。
注解的定义
注解通常以 @
符号开头,后跟注解名,如下示例定义了一个名为MyAnnotation
的注解。
public @interface MyAnnotation {
}
基于注解的常见用法
Java 中的注解本身并不具备任何功能,但我们可以基于注解实现一些常见的功能,注解常见的用法有以下两种:编译时检查、运行时处理。
编译时检查
如常见的使用 @Override
注解可以帮助编译器检查是否正确重写了父类方法,如果我们想自定义实现编译时检查,需要使用到注解处理器。
注解处理器
Java 提供了注解处理器(Annotation Processor),用于在编译期间处理注解。可以使用 javax.annotation.processing
包中的工具来创建自定义注解处理器。在后续的文章中,我们将实现这一功能。
运行时处理
可以通过反射在运行时访问注解,比如我定义了一个名为LogTag
的注解,结合 Aop 切面,当检测到方法上有这个注解时,可以在方法执行前后打印日志。
注解定义
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface LogTag {
}
Aop
切面
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
@Pointcut("@annotation(com.gumei.webapp.Annotations.LogTag)")
public void logPointcut() {
}
@Before("logPointcut()")
public void logPrint(JoinPoint joinPoint){
System.out.println("方法执行前打印日志:" + joinPoint.getSignature().getName());
}
}
在方法上使用注解
@Controller
@CrossOrigin
public class ControllerTest {
@LogTag
@ResponseBody
@RequestMapping("/test")
public Response test(Param param){
Response response = new Response();
response.setAge(param.age);
response.setName(param.name);
response.setDate(new Date());
response.setLocalDateTime(LocalDateTime.now());
return response;
}
}
当我们在访问test
接口时,切面检测到注解,便会执行对应的逻辑。
元注解
元注解是用于定义其他注解的注解。Java 提供了几个元注解:
-
@Retention: 指定注解的生命周期。可选值:
RetentionPolicy.SOURCE
: 注解仅在源代码中存在,编译时会被丢弃。RetentionPolicy.CLASS
: 注解在编译时被记录在 class 文件中,但 JVM 不会保留。RetentionPolicy.RUNTIME
: 注解在运行时保留,可以通过反射访问。
-
@Target: 指定注解可以应用的程序元素。常用的元素类型包括:
ElementType.TYPE
:类、接口(包括注解类型)、枚举ElementType.FIELD
:字段、枚举常量ElementType.METHOD
:方法ElementType.PARAMETER
:方法参数ElementType.CONSTRUCTOR
:构造方法ElementType.LOCAL_VARIABLE
:局部变量ElementType.ANNOTATION_TYPE
:注解ElementType.PACKAGE
:包
-
@Documented: 指定注解是否包含在 Javadoc 中。
-
@Inherited: 指定注解是否可以被子类继承。