如何访问 WEB-INF/lib/jars?
Posted
技术标签:
【中文标题】如何访问 WEB-INF/lib/jars?【英文标题】:How to get access to WEB-INF/lib/ jars? 【发布时间】:2021-06-30 00:42:12 【问题描述】:我有带有 Spring Boot 和 AspectJ 的 Gradle 项目。
想要直接从 WEB-INF/libs(Spring Boot 定位所有依赖项)动态加载 aspectjweaver
和 spring-instrument
javaagents
Gradle 依赖项:
代理加载器:
public class AgentLoader
private static final Logger LOGGER = LoggerFactory.getLogger(AgentLoader.class);
public static void loadJavaAgent()
if (!isAspectJAgentLoaded())
LOGGER.warn("Aspect agent was not loaded!");
public static boolean isAspectJAgentLoaded()
try
Agent.getInstrumentation();
catch (NoClassDefFoundError e)
return false;
catch (UnsupportedOperationException e)
LOGGER.info("Dynamically load AspectJAgent");
return dynamicallyLoadAspectJAgent();
return true;
public static boolean dynamicallyLoadAspectJAgent()
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
int p = nameOfRunningVM.indexOf('@');
String pid = nameOfRunningVM.substring(0, p);
try
VirtualMachine vm = VirtualMachine.attach(pid);
String jarFilePath = AgentLoader.class.getClassLoader().getResource("WEB-INF/libs/aspectjweaver-1.9.6.jar").toString();
vm.loadAgent(jarFilePath);
jarFilePath = AgentLoader.class.getClassLoader().getResource("WEB-INF/libs/spring-instrument-5.3.2.jar").toString();
vm.loadAgent(jarFilePath);
vm.detach();
catch (Exception e)
LOGGER.error("Exception while attaching agent", e);
return false;
return true;
但是在null
中发现getResource()
的返回值
处理此问题的最佳解决方案是什么?
【问题讨论】:
欢迎来到 SO。有趣的问题。请帮助我一点,这样我就可以帮助你。只需在 GitHub 上发布一点MCVE,这样我就可以重现该问题。我不是 Spring Boot 或 Gradle 用户,我是 Maven 人。但是,如果我有一个工作项目设置,我可以使用 AspectJ 查看您的类加载器问题。我需要查看 uber JAR 是如何打包的,在执行代理加载器类时使用了哪个类加载器,以及该类加载器是如何/何时启动的。 【参考方案1】:尼基塔,今天是你的幸运日。我只是有一点时间,很好奇如何让我的代码从 https://www.eclipse.org/aspectj/doc/released/README-187.html 开始运行,显然你之前发现了,它在 Spring Boot 的上下文中工作。我刚刚使用了我的 Maven Spring Boot 游乐场项目。根据您使用的 Java 版本,您需要确保 JDK 8 中的 tools.jar 被定义为系统范围的依赖项并复制到可执行的 Spring uber JAR 中,或者您需要确保 Java 附加API 在 Java 9+ 中激活。这是我为 Java 8 所做的:
Maven:
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>$java.home/../lib/tools.jar</systemPath>
</dependency>
<!-- (...) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>spring.aop.DemoApplication</mainClass>
<!-- Important for tools.jar on Java 8 -->
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<includeSystemScope>
选项是必需的,因为否则 Boot 不知道如何找到附加 API 类。只需在 Gradle 中做一些等效的事情就可以了。
Java:
您需要知道,为了附加代理,它必须是文件系统上的一个文件,而不仅仅是任何资源或输入流。这就是附加 API 的工作方式。所以不幸的是,您必须先将其从 uber JAR 复制到文件系统。以下是你的做法:
public static boolean dynamicallyLoadAspectJAgent()
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
int p = nameOfRunningVM.indexOf('@');
String pid = nameOfRunningVM.substring(0, p);
try
VirtualMachine vm = VirtualMachine.attach(pid);
ClassLoader classLoader = AgentLoader.class.getClassLoader();
try (InputStream nestedJar = Objects.requireNonNull(classLoader.getResourceAsStream("BOOT-INF/lib/aspectjweaver-1.9.4.jar")))
File targetFile = new File("aspectjweaver.jar");
java.nio.file.Files.copy(nestedJar, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
vm.loadAgent(targetFile.getAbsolutePath());
try (InputStream nestedJar = Objects.requireNonNull(classLoader.getResourceAsStream("BOOT-INF/lib/spring-instrument-5.1.9.RELEASE.jar")))
File targetFile = new File("spring-instrument.jar");
java.nio.file.Files.copy(nestedJar, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
vm.loadAgent(targetFile.getAbsolutePath());
vm.detach();
catch (Exception e)
LOGGER.error("Exception while attaching agent", e);
return false;
return true;
此外,在我的情况下,文件在BOOT-INF/lib
下,而不是WEB-INF/lib
。
更新:你说你在某个地方遇到了这个后续问题(重新格式化以提高可读性):
failed to access class
org.aspectj.weaver.loadtime.Aj$WeaverContainer
from class
org.aspectj.weaver.loadtime.Aj
(
org.aspectj.weaver.loadtime.Aj$WeaverContainer is in
unnamed module of
loader 'app';
org.aspectj.weaver.loadtime.Aj is in
unnamed module of
loader org.springframework.boot.loader.LaunchedURLClassLoader @3e9b1010
)
at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:108)
这意味着Aj
无法找到自己的内部类Aj.WeaverContainer
。这表明它们是在不同的时间点和不同的类加载器中加载的。当从可执行 JAR 开始远程调试到我的示例引导应用程序时,我看到应用程序类加载器实际上是 LaunchedURLClassLoader
的父类,即在父类中加载的类正试图访问另一个仅对其子类加载器可用的类,这在 Java 中是不可能的。它只能反过来工作。
也许不从代理加载器内部导入和引用 AspectJ 编织器类会有所帮助。尝试注释掉 loadJavaAgent()
和 isAspectJAgentLoaded()
方法并删除 import org.aspectj.weaver.loadtime.Agent;
。然后在您的应用程序中直接调用AgentLoader.dynamicallyLoadAspectJAgent()
看看这是否有帮助。关于代理加载,我还有一些优势,但让我们先让它尽可能简单。
【讨论】:
非常感谢 kriegaex。很高兴我以与您提出的相同方式解决了我的问题。我们认为孤独:) 它现在可以工作,但我开始收到奇怪的错误:failed to access class org.aspectj.weaver.loadtime.Aj$WeaverContainer from class org.aspectj.weaver.loadtime.Aj (org.aspectj.weaver.loadtime.Aj$WeaverContainer is in unnamed module of loader 'app'; org.aspectj.weaver.loadtime.Aj is in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @3e9b1010) at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:108)
这是一个典型的类加载器问题。 AspectJ 编织器在类加载器 A 中加载,但由加载器 B 中的类引用。我也许可以帮助您,但不能没有 MCVE。所以现在轮到你了。提取一个最小的reprerer项目,发布到GitHub上,我可以看看。我不想推测或猜测。谢谢。
碰巧又点了这个问题,才发现Aj
找不到自己的内部类Aj.WeaverContainer
。这表明它们是在不同的时间点和不同的类加载器中加载的。请参阅我将在几分钟后写的答案更新。
删除 import org.aspectj.weaver.loadtime.Agent
确实有效,感谢您的帮助。但你指的是哪个 A? :)以上是关于如何访问 WEB-INF/lib/jars?的主要内容,如果未能解决你的问题,请参考以下文章