使用库时出现 ClassNotFoundException 异常

ClassNotFoundException exception when using library

我创建了一个公共库以在我的 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[=10=](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"
    }
}

如果您查看您的消费项目,您会像这样声明对公共库的依赖关系

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

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

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

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

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

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

(*) 除非您正在使用清单文件或将其构建为 "fat" jar,否则我认为您不会也不会推荐。