Java Annotation Processor 注解处理器
大约 3 分钟
注解处理器
在Java世界里,注解(Annotation)是一种强大的元数据工具,它允许我们在不改变程序行为的情况下,为代码提供额外的信息。而注解处理器则将这种信息利用起来,它与Java编译器并行运行,能够在编译时自动生成代码,并且可以访问和修改正在编译的源代码文件,极大地提高了开发效率。
1、注解处理器的简单实现
1.1、定义注解
我们先来创建一个简单的注解。下面的代码定义了一个名为MyAnnotation的注解,保留策略设置为SOURCE,这意味着它只会存在于源代码中,不会出现在字节码中:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
String value();
}
1.2、创建注解处理器
接下来,我们需要创建一个处理这个注解的处理器。在Java中,这通常是一个实现了javax.annotation.processing.Processor接口的类:
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import java.io.IOException;
import java.util.Set;
public class MyAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
Set<Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
for (Element element : annotatedElements) {
if (element.getKind() == ElementKind.METHOD) {
// 创建新方法的代码块
MethodSpec methodSpec = MethodSpec.methodBuilder("printHello")
.addModifiers(Modifier.PUBLIC)
.addStatement("System.out.println(\"Hello, +$N\")", element.getSimpleName())
.build();
// 构建Java源文件
JavaFile javaFile = JavaFile.builder(element.getEnclosingElement().toString(), TypeSpec.classBuilder(element.getSimpleName().toString() + "Gen")
.addModifiers(Modifier.PUBLIC)
.addMethod(methodSpec)
.build())
.build();
try {
// 将生成的代码写入到生成代码目录
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return false; // 表示已经处理完所有相关的注解
}
@Override
public Set<String> getSupportedAnnotationTypes() {
HashSet<String> set = new HashSet<>();
set.add("com.example.demo.MyAnnotation");
return set;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
生成代码的地方使用了javapoet库来辅助,避免手动拼接字符串和import依赖,当然也可以使用模板来生成相应代码。
1.3、应用注解处理器
为了让我们的注解处理器在编译时生效,需要添加相应的设置。
手动处理
在maven项目 resource 目录创建 javax.annotation.processing.Processor文件,文件内写入 MyAnnotationProcessor 的类名 com.example.demo.MyAnnotationProcessor,这里有用到SPI的知识
修改maven编译插件配置如下,禁用注解处理
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
自动处理
使用google的auto-service来自动注册我们的注解处理器。
2、实战示例
现在我们可以编写一个使用MyAnnotation注解的类:
package com.example.demo;
public class TestClass {
@MyAnnotation
void myMethod() {
// ...
}
}
当你编译这个项目时,注解处理器将会自动生成TestClassGen类,里面包含printHello方法:
public class TestClass {
public void printHello(){
System.out.println("Hello, TestClass");
}
}
2.1、其他用法
注解处理器的其他用法
- 代码生成器
- 替代动态代理,将动态代理转换成静态代理。即将运行时的逻辑提前到编译期。
- 编译时修改代码,类似lombok,需要使用到Java Ast相关的类,Jdk8以后需要处理模块化带来的问题。