如何访问 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 BootAspectJ 的 Gradle 项目。

想要直接从 WEB-INF/libs(Spring Boot 定位所有依赖项)动态加载 aspectjweaverspring-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>

&lt;includeSystemScope&gt; 选项是必需的,因为否则 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?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 web 方法中访问会话?

如何使用 Web3 访问受访问权限保护的智能合约功能?

Struts2-- 如何在 Action 中访问 WEB 资源:

如何修改LNMP的web访问端口

如何从 Web 服务访问共享资源?

今晚九点|如何使用 Python 分析 web 访问日志?