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

能否将Elastic APM Java Agent插件嵌入应用JAR包部署?

将Elastic APM Agent插件嵌入Spring Boot可执行JAR的实现方案

为什么程序化自附加也无法读取JAR内的插件?

Elastic APM Agent的插件加载逻辑完全依赖本地文件系统路径——哪怕是用ElasticApmAttacher.attach()程序化附加,Agent内部依然会扫描config-plugins-dir指定路径下的物理JAR文件,不会从应用类路径中加载插件。这是因为Agent插件系统需要独立类加载器初始化,必须直接访问物理JAR文件,而非通过类路径读取已加载的类。

可行实现步骤

通过「Maven/Gradle资源打包+运行时临时提取」的方式,可以把插件嵌入应用JAR,同时让Agent正常加载:

1. 打包插件到应用JAR的资源目录

以Maven为例,在pom.xml中配置资源复制,把自定义APM插件JAR复制到应用的资源目录,打包后会被包含在Spring Boot可执行JAR的BOOT-INF/classes/apm-plugins路径下:

<build>
    <resources>
        <resource>
            <!-- 替换为你的插件JAR所在目录 -->
            <directory>${project.basedir}/lib/apm-plugins</directory>
            <targetPath>apm-plugins</targetPath>
            <includes>
                <include>*.jar</include>
            </includes>
        </resource>
    </resources>
</build>

2. 启动前提取插件到临时目录

在调用ElasticApmAttacher.attach()前,编写代码将JAR内的插件提取到系统临时目录,再把该目录设为Agent的插件目录:

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Objects;

public class ApmPluginInitializer {
    public static void init() throws IOException {
        // 创建专属临时目录
        Path tempPluginDir = Files.createTempDirectory("embedded-apm-plugins");
        
        // 从类路径读取插件并复制到临时目录
        try (var pluginStream = ApmPluginInitializer.class.getClassLoader()
                .getResourceAsStream("apm-plugins/your-custom-r2dbc-plugin.jar")) {
            Objects.requireNonNull(pluginStream, "APM自定义插件未找到");
            Path targetPath = tempPluginDir.resolve("your-custom-r2dbc-plugin.jar");
            Files.copy(pluginStream, targetPath, StandardCopyOption.REPLACE_EXISTING);
        }
        
        // 配置Agent插件目录
        System.setProperty("elastic.apm.config-plugins-dir", tempPluginDir.toString());
        
        // 附加APM Agent
        ElasticApmAttacher.attach();
    }
}

然后在Spring Boot启动类中调用:

public static void main(String[] args) throws IOException {
    ApmPluginInitializer.init();
    SpringApplication.run(YourApplication.class, args);
}

3. 可选:清理临时文件

为避免临时文件堆积,可在应用关闭时自动删除临时目录,通过@PreDestroy实现:

import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

@Component
public class TempDirCleaner {
    @Bean
    public DisposableBean pluginDirCleaner() {
        return () -> {
            String tempDirPath = System.getProperty("elastic.apm.config-plugins-dir");
            if (tempDirPath != null) {
                try {
                    Files.walk(Path.of(tempDirPath))
                         .sorted(java.util.Comparator.reverseOrder())
                         .map(Path::toFile)
                         .forEach(File::delete);
                } catch (IOException e) {
                    // 仅记录日志,不影响应用关闭
                    e.printStackTrace();
                }
            }
        };
    }
}

注意事项

  • 确保自定义插件版本与Elastic APM Agent版本完全兼容,避免类加载冲突
  • 应用进程需拥有临时目录的读写权限
  • Gradle用户可通过sourceSets配置实现类似的资源打包逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:57:36