【问题标题】:Spring boot: Inclusion of external jar dependency with scanBasePackagesSpring Boot:使用 scanBasePackages 包含外部 jar 依赖项
【发布时间】:2020-06-01 16:58:27
【问题描述】:

我将首先描述问题,此处引用的文件可以在下面找到。


我正在尝试以 jar 文件的形式使用外部库。这个库包含我在 Spring @Configuration 文件中使用的代码。因此,我已将其作为实现依赖项包含在我的 build.gradle 中(请参见下面的代码)。

所有库文件都包含在包com.rusticisoftware.tincan 中。我自己的代码位于de.my.example 下。

将@SpringBootApplication 保留为默认值(与de.my.example 相同,因为这是Application.java 类在使用Gradle assemble 任务组装项目时所在的位置。然后我可以从我的 IDE 和一切都按预期工作。

但是,在运行 Gradle test 任务和执行由 spring boot 的 bootJar 任务创建的 bootJar 时,都会抛出以下错误:

    java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
        Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at ConstructorResolver.java:798
            Caused by: org.springframework.beans.factory.BeanCreationException at ConstructorResolver.java:656
                Caused by: org.springframework.beans.BeanInstantiationException at SimpleInstantiationStrategy.java:185
                    Caused by: java.lang.NoClassDefFoundError at Config.java:29
                        Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:581

Caused by: java.lang.NoClassDefFoundError at Config.java:29 在代码中引用此行:RemoteLRS lrs = new RemoteLRS(); RemoteLRS 是来自 com.rusticisoftware.tincan 中包含的 jar 库中的类。

我可以通过在@SpringBootApplication 注释中指定scanBasePackages 来消除此错误,如下所示:@SpringBootApplication(scanBasePackages = {"com.rusticisoftware.tincan"})。但是,这样做将不再扫描并找到导致 REST 服务无法加载的 MyResource.java。

为了解决这个问题,我尝试手动将自己的包与 jar 中的包一起添加到 @SpringBootApplication,导致:@SpringBootApplication(scanBasePackages = {"com.rusticisoftware.tincan", "de.my.example"})。

这再次加载了 REST 服务,但在运行 test 任务或执行 bootJar 任务生成的 jar 时遇到了与之前相同的问题。我还手动检查了生成的 bootJar,可以确认库 jar 包含在其中。


项目结构

Project
 |
 +-- build.gradle
 |    
 +-- src
 |    |
 |    +-- main/java/
 |    |        |  
 |    |        +-- de/my/example
 |    |                   |
 |    |                   +-- Application.java
 |    |                   |
 |    |                   +-- Config.java
 |    |                   |
 |    |                   +-- controller
 |    |                           |
 |    |                           +-- MyResource.java
 |    +-- test/java/
 |             |  
 |             +-- de/my/example
 |                        |
 |                        +-- ApplicationTests.java
 +-- libs
      |
      +-- tincan-1.1.0.jar

build.gradle

plugins {
    id "java"
    id "idea"
    id 'org.springframework.boot' version '2.3.0.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}

// project settings
group 'de.my.example'
version '1.0'
sourceCompatibility = 11

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    // spring
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }

    // tin-can xAPI
    implementation files('libs/tincan-1.1.0.jar')
}

test {
    useJUnitPlatform()
}

Application.java

@SpringBootApplication(scanBasePackages = {"com.rusticisoftware.tincan", "de.my.example"})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

ApplicationTests.java

@SpringBootTest
class ApplicationTests {

    @Test
    void contextLoads() {
    }

}

TestResource.java

public class TestResource {

    private final LearningRecordStore learningRecordStore;

    public TestResource(LearningRecordStore learningRecordStore) {
        this.learningRecordStore = learningRecordStore;
    }

    @GetMapping(value = "/ping", produces = MediaType.TEXT_PLAIN_VALUE)
    public String ping() {
        return "pong";
    }
}

Config.java

@Configuration
public class Config {

    @Bean
    public LearningRecordStore learningData() {
        RemoteLRS lrs = new RemoteLRS();
        return new LearningRecordStore(lrs);
    }

}

【问题讨论】:

    标签: java spring spring-boot gradle dependency-injection


    【解决方案1】:

    最简单的检查方法是在 Gradle 构建后探索构建文件,以确保它存在于构建包中。这样,您将确保它被包含在内并且不应该抛出 class-not-found 异常。此外,您可能需要在 scanBasePackage 中包含这两个包。

    【讨论】:

    • 感谢您的回答!如上所述,我研究了任务的输出。图书馆在场。我还将这两个包都包含在scanBasePackage 中 - 如上所述,我得到的结果与根本不包含它们相同。我认为这是 Springs 类路径和依赖管理的问题,而不是 Gradle 或 Gradle 任务。
    猜你喜欢
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 2018-03-05
    • 2018-12-19
    • 2016-02-08
    • 1970-01-01
    相关资源
    最近更新 更多