【发布时间】:2021-02-24 11:43:44
【问题描述】:
AWS SDK 可以通过类路径扫描定位 API 调用拦截器(查找 software/amazon/awssdk/global/handlers/execution.interceptors 并在此处实例化指定的类)。
我正在编写一个 Java 代理,目的是让 AWS 开发工具包可以定位我的拦截器。
- 我的拦截器与 Java 代理捆绑在一起。
- 我的拦截器实现了 AWS 的
ExecutionInterceptor。 - AWS 开发工具包没有与我的代理捆绑,因为我希望最终用户提供他们自己的 AWS 开发工具包版本。
对于常规的独立应用程序,这是不费吹灰之力的,因为 Java 代理会自动添加到应用程序的运行时类路径中。 AWS SDK 可以毫无问题地找到我的拦截器。
但是,这种方法与 Spring Boot 应用程序完全不同,其中 AWS 开发工具包作为依赖项捆绑在 BOOT-INF/lib 下。原因归结为 Spring Boot 的类加载层次结构。可以找到我的拦截器类,但由于无法找到 AWS 的 ExecutionInterceptor,它的加载失败,因为它是在层次结构中的“较低”类加载器中加载的。
所以我认为我的方法应该是以某种方式修改 Spring Boot 的类加载器搜索。但是,我面临这些问题:
- 在调用代理时,尚未创建 Spring Boot 的“较低”类加载器。
- 我不完全确定我需要检测什么。
我听说 Byte Buddy 能够在这种“有趣”的情况下提供帮助,但还没有找到实现这项工作的方法。有什么想法吗?
(编辑:我正在寻找一种不需要更改代码/打包的解决方案,因此采用 Java 代理方法)
(编辑:我尝试过的事情)
按照 Rafael 的回答:SDK 中解析所有拦截器的方法在 SdkDefaultClientBuilder 类中,称为 resolveExecutionInterceptors。
那么,以下内容适用于不是 SpringBoot 应用程序的独立 JAR:
public static void installAgent(Instrumentation inst) {
new AgentBuilder.Default()
.with(RedefinitionStrategy.DISABLED)
.type(ElementMatchers.nameEndsWith("SdkDefaultClientBuilder"))
.transform(
new Transformer() {
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
return builder.visit(Advice.to(MyAdvice.class).on(ElementMatchers.named("resolveExecutionInterceptors")));
}
}
).installOn(inst);
}
但是,对于 SpringBoot 应用程序,似乎根本没有应用该建议。我猜这是因为 SdkDefaultClientBuilder 类型在代理启动时甚至不可用。它在 SpringBoot 的运行时可用,在不同的类加载器中。
【问题讨论】:
-
您可以创建一个具有“正常”结构的 jar,而不是“BOOT-INF/lib 以供任何需要使用的东西。您可以查看 spring boot maven 插件docs.spring.io/spring-boot/docs/1.1.2.RELEASE/reference/html/…跨度>
-
对。我应该添加(并且很快会编辑问题)——我需要一个不需要更改代码或重新打包现有应用程序的解决方案
-
如果我理解正确,您的代理使用的类是通过不同的类加载器加载的?
-
@JohannesKuhn 是的
-
好吧,那么最简单的方法就是使用反射。
标签: instrumentation byte-buddy aws-java-sdk javaagents