我编写了一个 ArchUnitProcessor 处理程序,概要代码如下所示:

@SupportedAnnotationTypes("com.shanhy.processor.EnableMyProcessor") // 这是一个自定义注解
public class MyProcessor extends AbstractProcessor {

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
    // 更多代码(略)
}

想让该服务程序被自动发现,按照 java 的规则,需要在 resources/META-INF/services/ 中创建文件 javax.annotation.processing.Processor,然后内容为每行一条的类全称 com.shanhy.tools.archunit.processor.ArchUnitProcessor

问题来了,划重点:

如果我们创建并配置了这个服务发现文件,那么在我们编译时,它会自动被 maven-compiler-plugin 插件加载,在 compile 加载时我们的这个类还没有被编译为 class,它就会报错。

错误内容如下所示:

[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.902 s
[INFO] Finished at: 2024-12-20T15:30:11+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project shanhy-demo: Compilation failure
[ERROR] 服务配置文件不正确, 或构造处理程序对象javax.annotation.processing.Processor: Provider com.shanhy.processor.MyProcessor not found时抛出异常错误
[ERROR]
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

要想解决问题,所以我们只能先删除这个文件,在 maven 编译成功后再把文件放回去打包。但是你会发现,这样很难受,每次修改代码编译打包都要进行这样的操作。

还好,强大的 Java 生态总不缺乏解决问题的人。当我们想发明轮子时,可能解决问题的轮子已经被别人发明过了。

我们之间使用 google autoService 库来自动生成这个文件(AutoService 框架的作用是自动生成SPI清单文件),只需要给我们的目标类添加一个 @AutoService 注解即可。以 MyProcessor 为例添加注释后的代码如下:

@AutoService(Processor.class) // 注解里的这个class就是生成到META-INF/services目录中的文件名
@SupportedAnnotationTypes("com.shanhy.processor.EnableMyProcessor") // 这是一个自定义注解
public class MyProcessor extends AbstractProcessor {

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
    // 更多代码(略)
}

库对应的依赖为:

    <dependency>
        <groupId>com.google.auto.service</groupId>
        <artifactId>auto-service</artifactId>
        <version>1.1.1</version>
    </dependency>

只需要一个注解即可,这样在 maven 编译打包后就会自动生成services下面对应的文件和内容了。

弊端提醒:

不得不提醒你的是,让你使用了 google autoservice 库自动生成 SPI 配置文件时,确实带来了便利性。但是也正因为如此,所有依赖和使用你这个 processor 库 jar 包的服务,也必须要依赖 google autoservice,否则会出错的。因为我们的 Processor 类中使用了 @AutoService 注解,所以这个类被实例化时如果上下文缺少 google autoservice 就会报错的。

如果 Processor 工程本身没有使用 lombok、mapstruct 这些基于 Processor 方案的内容,你可以使用下面这种方法直接使用参数 -proc:none 禁用服务发现:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <compilerArgs>
                    <arg>-proc:none</arg>
                </compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

最后推荐

终极推荐方法是使用 maven-shade-plugin 插件的 IncludeResourceTransformer 来自动处理这个文件。

如下图所示:

在这里插入图片描述


(END)

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐