返回

解决Java模块化项目 Azure Identity 模块加载失败问题

java

解决Java模块化项目中使用 Azure Identity 模块的问题

使用 Java 模块化项目时,依赖项的管理方式可能导致一些初学者难以理解的错误。在使用 com.azure.identity 模块时,就可能会出现 Module not found 这样的异常。本文探讨这一问题的根源并提供几种解决方案,帮助开发者克服模块化 Java 项目中可能遇到的挑战。

问题分析

上述错误 java.lang.module.FindException: Module msal4j.persistence.extension not found 表明 JVM 在运行时无法找到 msal4j.persistence.extension 这个模块。从构建文件来看,该依赖已经被正确地添加到 build.gradle.kts 文件中。 进一步的错误, module not found: msal4j.persistence.extension 表明 module-info.java 也存在同样的问题。根本原因在于, msal4j.persistence.extension 是一个自动模块

自动模块 并不是传统意义上的模块,它们只是为了兼容那些不符合 Java 9 及以上版本模块化规范的 JAR 文件。自动模块不能直接通过模块名引入到你的模块中。 它们被放入一个名为未命名模块的模块图中,它们具有模块的所有可读性、并且不属于模块层级的任何其他层级。因此,显式在 module-info.javarequires 它将会导致错误。

解决方案

以下是一些可用于解决该问题的方法。

方案一:移除 module-info.java 中的依赖

最直接的办法,是避免尝试直接在模块符 module-info.java 中显式引用自动模块。修改 module-info.java 文件,删除对 msal4j.persistence.extensionrequires 语句。

修改后的 src/main/java/module-info.java:

module com.example {
    requires java.base;
    requires com.azure.identity;

    exports com.example;
}

步骤:

  1. 修改 src/main/java/module-info.java 文件,删除 requires msal4j.persistence.extension; 行。
  2. 运行构建任务: .\\gradlew run
    该方法简单快捷,适合对模块化细节不太关心,但仍然需要正常运行应用的开发者。 这样处理之后, 依赖可以正确找到。

方案二:使用 --add-modules 启动 JVM

这个方法可以显式指示 JVM 包含指定的模块。这种方案相对灵活,能控制启动时的模块加载。可以通过添加 --add-modules 参数来使自动模块“成为”一个常规模块,从而使你的应用程序在模块化环境中有意义地使用这些自动模块。

操作步骤:

  1. 修改 build.gradle.kts,配置 application 启动参数

    application {
         mainClass = "com.example.Main"
         mainModule = "com.example"
    
         applicationDefaultJvmArgs = listOf("--add-modules","msal4j.persistence.extension")
    
    }
    
    
  2. 确保module-info.java 包含所有必要的其他依赖。比如示例中的 com.azure.identity

  3. 执行 .\\gradlew run,启动程序。

通过添加启动参数, JVM 会把自动模块当作显式模块对待,问题就可以得到解决。 需要特别注意在运行时指定这些额外的模块名。

方案三:调整 msal4j-persistence-extension 依赖方式

另外一种方式是在build.gradle.kts 强制该依赖被添加到编译期的类路径,尽管它的运行不属于模块图本身。我们可以通过配置让它在模块路径中可用。这样做实际上在模块之外公开它,但却依然有效,尽管并非在纯粹的模块方式中执行。

build.gradle.kts 的修改 :

 dependencies {
     implementation(platform("com.azure:azure-sdk-bom:1.2.28"))
     implementation("com.azure:azure-identity")
     implementation("com.azure:azure-core")

      implementation ("com.microsoft.azure:msal4j-persistence-extension:1.3.0")  {
         isTransitive = true
      }

      configurations.implementation{
          resolutionStrategy.force("net.java.dev.jna:jna:5.13.0")
         resolutionStrategy.force("net.java.dev.jna:jna-platform:5.13.0")
          resolutionStrategy.force("org.slf4j:slf4j-api:1.7.36")
         resolutionStrategy.force("com.microsoft.azure:msal4j:1.17.1")
     }
 }

在此配置中,需要调整和固定内部传递的依赖以强制他们进入运行时模块路径中。这种方案本质上将自动模块放入依赖关系树中的适当位置, 解决了模块的依赖问题。这种做法并不推荐, 除非必须这样做, 并了解相关的风险。

操作步骤 :

  1. 按照上述示例修改 build.gradle.kts
  2. 运行 .\\gradlew run 检查问题是否被修复。
  3. 确保 module-info.java 文件中不存在 requires msal4j.persistence.extension;

该方案更为精细地控制了模块依赖和传递,适合对类加载有更高级要求的开发者。这种配置允许模块正确启动和运行,但是这需要对Gradle依赖关系图,传递性依赖等理解。

总结

在 Java 模块化项目中使用 com.azure.identity 模块时遇到的问题通常由 msal4j.persistence.extension 的自动模块特性引起。开发者可以通过移除 module-info.java 中的依赖,使用 --add-modules 启动参数, 或者在build.gradle.kts中强制设置该模块传递性依赖的路径等方式解决该问题。 选择合适的方案,取决于具体项目的需求和对模块化程度的要求。 如果仅需要正常运行,第一种方案更为推荐。 理解这些方案和它们背后的原理能帮助开发者更好的解决 Java 模块化问题。