java - 使用库时出现 ClassNotFoundException 异常

标签 java gradle kotlin shared-libraries gradle-kotlin-dsl

我创建了一个公共(public)库来在我的 Spring 微服务中使用它。 在这个库中,我使用了一些其他库(例如:libphonenumber)。 我创建了jar文件并将其导入到另一个项目中,并且我使用它没有任何问题。 但是在构建项目时,抛出了这个异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'phoneUtils': Lookup method resolution failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [com.weryou.backend.commons.utils.PhoneUtils] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@368239c8]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:265) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1269) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1184) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:743) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:390) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1214) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1203) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at com.weryou.backend.mission.MissionAppKt.main(MissionApp.kt:13) ~[main/:na]
Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.weryou.backend.commons.utils.PhoneUtils] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@368239c8]
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:507) ~[spring-core-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:404) ~[spring-core-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:389) ~[spring-core-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:248) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
... 18 common frames omitted
Caused by: java.lang.NoClassDefFoundError: com/google/i18n/phonenumbers/Phonenumber$PhoneNumber
at java.base/java.lang.Class.getDeclaredMethods0(Native Method) ~[na:na]
at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3167) ~[na:na]
at java.base/java.lang.Class.getDeclaredMethods(Class.java:2310) ~[na:na]
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:489) ~[spring-core-5.1.9.RELEASE.jar:5.1.9.RELEASE]
... 21 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.google.i18n.phonenumbers.Phonenumber$PhoneNumber
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583) ~[na:na]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
... 25 common frames omitted

我不知道为什么这个异常是从我导入库的项目中抛出的。通常,如果库的依赖项存在问题,库将无法工作,但它可以工作。 但是当我将库中使用的相同依赖项放入项目 gradle 时,一切正常。 通常,如果我在库中使用依赖项,我不需要在该库使用的项目中实现它们。 我尝试使库的依赖项具有传递性,但这不起作用!

这是库的 gradle 文件:

plugins {
kotlin("jvm") version "1.3.50"
}

group = "com.weryou.backend"
version = "1.0.0"
java.sourceCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation("io.jsonwebtoken:jjwt:0.9.1") {
        isTransitive = true
    }
    implementation("com.googlecode.libphonenumber:libphonenumber:8.10.14") {
        isTransitive = true
    }
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.9") {
        isTransitive = true
    }
}

这是使用该库的项目的gradle文件

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "2.1.7.RELEASE"
    id("io.spring.dependency-management") version "1.0.8.RELEASE"
    kotlin("jvm") version "1.2.71"
    kotlin("plugin.spring") version "1.2.71"
}

group = "com.project.test"
version = "0.0.1"
java.sourceCompatibility = JavaVersion.VERSION_1_8

repositories {
   mavenCentral()
}

dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))

    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

    implementation("org.springframework.boot:spring-boot-starter-web")
}

dependencyManagement {
    imports {
        mavenBom("org.springframework.cloud:spring-cloud-dependencies:Greenwich.SR2")
    }
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "1.8"
    }
}

最佳答案

如果你查看你的消费项目,你会像这样声明对公共(public)库的依赖

dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    // ...
}

jar 文件本身不包含有关其所需的所有传递依赖项的任何信息*。因此,您的消费项目不可能仅通过查看 jar 文件就知道这一点。

有多种方法可以做到这一点,这完全取决于您的布局以及您希望项目的紧密耦合程度。以下是其中的一些:

  1. 在使用项目中,(再次)声明库所需的所有依赖项。这是您已经尝试过并说效果很好的方法。希望现在您知道原因了。缺点是您必须手动保持它们同步。

  2. 创建您的库的 Maven 发行版,并让您的消费项目依赖它,就像您对所有其他依赖项所做的那样。这需要您有一个 Maven 存储库才能将其上传到。在这种方法中,传递依赖将 注册到相应的POM文件中。

  3. 如果项目位于同一台计算机上,您可以将库作为复合构建导入,并将其声明为项目依赖项。在这种方法中,Gradle 将从 Gradle 项目本身推断传递依赖项。

(*) 除非您使用 list 文件或将其构建为“胖”jar,我认为您不会也不会推荐这样做。

关于java - 使用库时出现 ClassNotFoundException 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57893461/

相关文章:

java - Lucene 演示类中的 Servlet 异常

Java/Selenium 应用程序 - 如何获取被测应用程序的 session ID?

java - 无法使用 openapi-generator-gradle-plugin 生成接口(interface)

android - 无法找到可选库 : android. test.runner

android - Groupie RecyclerView单击特定项目

java - 为什么只得到一小部分空点异常堆栈

java - 如何在较新版本的 Android 3.1 及更高版本中实现 Firebase Recycler Adapter?

gradle - 如何根据Spring Boot运行时环境在Gradle中删除依赖项?

androidx.navigation.NavGraph 无法转换为 androidx.navigation.compose.ComposeNavigator$Destination

android - kotlin 中的 lambda 是如何赋值的