You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java注解类中添加自定义静态变量?(仿Log4j2实现)

实现自定义注解处理器为类添加静态变量

核心限制说明

Java标准注解处理器(继承AbstractProcessor的实现)无法修改已存在的源文件或类文件,只能生成新的源文件。如果要直接在标注@TestAnnotation的原类中添加静态变量并直接调用,必须结合字节码增强库(如ASM);如果接受生成新类后通过静态导入/继承使用,可以用纯注解处理器方案。


方案1:纯注解处理器(生成辅助类,静态导入使用)

1. 定义@TestAnnotation注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface TestAnnotation {
    // 可配置静态变量的默认值
    String value() default "Hello Generated";
}

2. 实现注解处理器TestProcessor

用JavaPoet简化代码生成(比原生API更直观),先添加Maven依赖:

<dependency>
    <groupId>com.squareup</groupId>
    <artifactId>javapoet</artifactId>
    <version>1.13.0</version>
    <scope>provided</scope>
</dependency>

处理器代码:

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import com.google.auto.service.AutoService;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.io.IOException;
import java.util.Set;

@AutoService(javax.annotation.processing.Processor.class)
@SupportedAnnotationTypes("com.yourpackage.TestAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class TestProcessor extends AbstractProcessor {
    private Filer filer;
    private Messager messager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(TestAnnotation.class)) {
            if (!(element instanceof TypeElement)) {
                messager.printMessage(Diagnostic.Kind.ERROR, "@TestAnnotation只能标注在类上");
                continue;
            }

            TypeElement typeElement = (TypeElement) element;
            String className = typeElement.getSimpleName().toString();
            String packageName = processingEnv.getElementUtils().getPackageOf(typeElement).getQualifiedName().toString();
            TestAnnotation annotation = typeElement.getAnnotation(TestAnnotation.class);
            String staticValue = annotation.value();

            // 生成public static final类型的静态变量
            FieldSpec testStringField = FieldSpec.builder(String.class, "testString", 
                    Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                    .initializer("$S", staticValue)
                    .build();

            // 生成与原类同包的辅助类,命名为原类名+Constants
            TypeSpec helperClass = TypeSpec.classBuilder(className + "Constants")
                    .addModifiers(Modifier.PUBLIC)
                    .addField(testStringField)
                    .build();

            try {
                JavaFile.builder(packageName, helperClass)
                        .build()
                        .writeTo(filer);
            } catch (IOException e) {
                messager.printMessage(Diagnostic.Kind.ERROR, "生成辅助类失败:" + e.getMessage());
            }
        }
        return true;
    }
}

3. 使用方式

在原类中静态导入辅助类的变量即可直接调用:

@TestAnnotation("我的自定义静态值")
public class DemoClass {
    import static com.yourpackage.DemoClassConstants.testString;

    public static void main(String[] args) {
        System.out.println(testString); // 输出:我的自定义静态值
    }
}

方案2:注解处理器+ASM字节码增强(直接修改原类)

如果要像Log4j2那样直接在原类中生成静态变量,需要用ASM修改编译后的字节码:

1. 添加ASM依赖

<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm</artifactId>
    <version>9.5</version>
    <scope>provided</scope>
</dependency>

2. 修改处理器实现

import com.google.auto.service.AutoService;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;

@AutoService(javax.annotation.processing.Processor.class)
@SupportedAnnotationTypes("com.yourpackage.TestAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class TestProcessor extends AbstractProcessor {
    private Filer filer;
    private Messager messager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(TestAnnotation.class)) {
            if (!(element instanceof TypeElement)) {
                messager.printMessage(Diagnostic.Kind.ERROR, "@TestAnnotation只能标注在类上");
                continue;
            }

            TypeElement typeElement = (TypeElement) element;
            String fullClassName = typeElement.getQualifiedName().toString();
            String internalClassName = fullClassName.replace('.', '/');
            TestAnnotation annotation = typeElement.getAnnotation(TestAnnotation.class);
            String staticValue = annotation.value();

            try {
                // 读取原类的字节码
                JavaFileObject classFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", internalClassName + ".class");
                InputStream inputStream = classFile.openInputStream();
                ClassReader classReader = new ClassReader(inputStream);

                // 用ClassWriter修改字节码
                ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
                ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9, classWriter) {
                    @Override
                    public void visitEnd() {
                        // 在类末尾添加public static final String testString字段
                        FieldVisitor fieldVisitor = visitField(
                                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL,
                                "testString",
                                "Ljava/lang/String;",
                                null,
                                staticValue
                        );
                        if (fieldVisitor != null) {
                            fieldVisitor.visitEnd();
                        }
                        super.visitEnd();
                    }
                };

                classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
                inputStream.close();

                // 写入修改后的字节码
                OutputStream outputStream = filer.createClassFile(fullClassName).openOutputStream();
                outputStream.write(classWriter.toByteArray());
                outputStream.close();
            } catch (IOException e) {
                messager.printMessage(Diagnostic.Kind.ERROR, "修改类字节码失败:" + e.getMessage());
            }
        }
        return true;
    }
}

3. 使用方式

直接在标注注解的类中调用静态变量:

@TestAnnotation("直接在原类调用的静态值")
public class DemoClass {
    public static void main(String[] args) {
        System.out.println(testString); // 输出:直接在原类调用的静态值
    }
}

处理器注册说明

如果不用@AutoService注解,需要手动在src/main/resources/META-INF/services/javax.annotation.processing.Processor文件中添加处理器的全类名:

com.yourpackage.TestProcessor

内容的提问来源于stack exchange,提问作者hteppl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 03:17:32