【发布时间】: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