BuildProperties Spring Boot 2.1.5和eclipse自动布线失败

时间:2019-06-17 15:06:54

标签: java spring-boot autowired

我正在使用几个REST API创建一个非常简单的应用程序,并且在我尝试在运行状况检查API上使用BuildProperties之前,它一直可以正常工作。启动我的应用程序时,出现以下错误:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-06-17 09:54:29.210 ERROR 10796 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Field buildProperties in com.controller.HealthCheck required a bean of type 'org.springframework.boot.info.BuildProperties' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)

The following candidates were found but could not be injected:
    - Bean method 'buildProperties' in 'ProjectInfoAutoConfiguration' not loaded because @ConditionalOnResource did not find resource '${spring.info.build.location:classpath:META-INF/build-info.properties}'


Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.boot.info.BuildProperties' in your configuration.

我去了构建文件,我还查看了由构建创建的jar文件,我看到build-info.properties实际上在那里。在jar文件中,文件的路径为“ BOOT-INF \ classes \ META-INF \”。我还有其他没有问题的“自动装配”元素。

我的代码失败的地方:

@RestController
public class HealthCheck {

    @Autowired
    Environment environment;

    @Autowired 
    BuildProperties buildProperties;


    @GetMapping("/health")
    public HealthCheckResponse healthCheck() {
        return getHealthCheckResponse();
    }

    private HealthCheckResponse getHealthCheckResponse(){
        HealthCheckResponse healthResponse = new HealthCheckResponse();
        String[] profiles = environment.getActiveProfiles();

        healthResponse.setServerTime(new Date());
        healthResponse.setVersion(buildProperties.getVersion());
        healthResponse.setEnvironment(profiles[0]);

        return healthResponse;
    }

我的gradle构建文件:

plugins {
    id 'org.asciidoctor.convert' version '1.5.3'
    id 'org.springframework.boot' version '2.1.5.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'
apply plugin: 'eclipse'
apply plugin: 'java'

group = 'com'
version = '0.0.1'
sourceCompatibility = '12'

repositories {
    mavenCentral()
}

ext {
    set('snippetsDir', file("build/generated-snippets"))
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-jersey'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:2.1.1'
    runtimeOnly 'mysql:mysql-connector-java'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.restdocs:spring-restdocs-webtestclient'
    testImplementation 'org.springframework.security:spring-security-test'
}

test {
    outputs.dir snippetsDir
}

asciidoctor {
    inputs.dir snippetsDir
    dependsOn test
}

springBoot {
    buildInfo()
}

build-info.properties:

#Properties
#Mon Jun 17 10:52:04 EDT 2019
build.version=0.0.1
build.group=com
build.name=app
build.artifact=app
build.time=2019-06-17T14\:52\:04.829909200Z

11 个答案:

答案 0 :(得分:8)

简而言之:此问题与IDE有关(已在Eclipse和Idea上进行了检查),并且不会影响在gradle构建系统上的启动脚本中运行/调试spring boot应用程序。 / p>

此外,以eclipse和JDK的启动插件产生此问题为前提也不完全正确。

此问题的根源::使用不同的编译器编译的构建工件的位置不同,并且缺少build-info.properties

说明:

gradle执行构建时,通常使用JDK编译器生成Java工件,并将输出放置在构建目录中。

另一方面,当eclipse执行构建时,它会与Eclipse JDT产生冲突,并将输出放置到bin目录中。

请注意,将这两者混合可能会导致意外的行为。日食团队已经分析了这个“特征”,并且被拒绝(由于无效而关闭)。更多信息here

由于gradle任务buildInfo是由gradle运行的,这说明了build-info.properties文件存在于gradle的默认输出文件夹中的事实(默认情况下,它必须位于此处:{{1 }}。

从@ROOTKILL的问题可以看出,他试图从BuildProperties类中获取信息。在后台,当Spring检测到类路径上有build-info.properties文件时,除非显式声明,否则它将创建BuildProperties bean。 有用的信息是here

请看看这种方法:

build/resources/main/META-INF/

根据IDE使用不同的输出目录的事实,缺少了build-info.properties文件,这会产生显示的错误(@ConditionalOnResource(resources = "${spring.info.build.location:classpath:META-INF/build-info.properties}") @ConditionalOnMissingBean @Bean public BuildProperties buildProperties() throws Exception { return new BuildProperties( loadFrom(this.properties.getBuild().getLocation(), "build")); } )。 另一方面,这解释了为什么一切都可以通过gradle运行。

解决方案:

根据这些事实,解决方案很明确:eclipse和IntelliJ Idea IDE都必须使用gradle的任务,而不是运行/调试自己的任务。

  • 对于 Eclipse IDE :可以通过gradle任务启动应用程序(从gradle任务视图启动bootRun)。
  • 对于 IDE IDE :可以添加设置以将IDE构建/运行操作委托给gradle,这是@ user666之前已经指出的。

由于此解决方案使用gradle,因此将在Bean method 'buildProperties' in 'ProjectInfoAutoConfiguration' not loaded because @ConditionalOnResource did not find resource '${spring.info.build.location:classpath:META-INF/build-info.properties}'位置(渐变的默认设置)使用build-info.properties文件,当然,该文件也是可见的。结果,将创建Bean BuildProperties并将其可用。

答案 1 :(得分:4)

只需运行一个mvn clean程序包,然后从eclipse / intelliJ重新启动引导应用程序

答案 2 :(得分:2)

我的Spring Boot服务在maven-spring-boot插件中有一个Maven build-info部分,因此当我尝试从非.jar存档中运行该服务时,出现了此错误BuildProperties cannot be found。因此,要将服务作为常规的Spring Boot运行配置运行,我必须添加此条件Bean,现在一切正常,既可以作为.jar版本,也可以作为非调试调试版本运行:

@ConditionalOnMissingBean
@Bean
public BuildProperties buildProperties() {
    Properties properties = new Properties();
    properties.put("group", "com.example");
    properties.put("artifact", "demo");
    properties.put("version", "not-jarred");
    return new BuildProperties(properties);
}

答案 3 :(得分:2)

正如@André Schonrock正确提到的,问题的原因是here

<块引用>

Maven 插件和 Gradle 插件都允许生成构建 包含坐标、名称和版本的信息 项目。插件也可以配置为添加额外的 属性通过配置。当存在这样的文件时,Spring 启动自动配置 BuildProperties bean。

因此您需要在 spring-boot-maven-plugin 中添加 POM

<executions>
    <execution>
        <goals>
            <goal>build-info</goal>
        </goals>
    </execution>
</executions> 

或添加build.gradle

springBoot {
    buildInfo()
}

作为替代方式,可以以比 @djangofan 显示的更短的形式显式添加 Bean

@Bean @ConditionalOnMissingBean(BuildProperties.class)
BuildProperties buildProperties() {
    return new BuildProperties(new Properties());
}

在配置文件中。

注意:如果您更新了 POMbuild.gradle,但错误仍然出现,请尝试使用(例如对于 Maven)生命周期命令 {{1 }} 然后 clean 并再次运行该项目。

答案 4 :(得分:1)

在pom.xml的末尾添加/修改:

<build>
        <finalName>{NAME_YOUR_PROJECT}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>build-info</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

答案 5 :(得分:0)

我建议尝试在JDK 8下运行,并从命令行运行 java -jar <your jar name>只是为了确保您正确获得了构建属性。

也许Jdk 12还不适合春季引导。我想您可能还有其他问题。许多Java框架尚未100%认证可与JDK 12一起使用。

我认为计划是从Spring Boot 2.2开始正式支持Java 12

答案 6 :(得分:0)

正如@Borislav Markov所建议的那样,我尝试通过命令行运行它,无论使用JDK 12还是JDK 8,它似乎都可以正常运行。我认为问题与我用来通过以下方式运行应用程序的eclipse插件有关IDE。

答案 7 :(得分:0)

我认为您的IDE困惑于“胖罐子”覆盖普通罐子的事实。 IDE可以理解普通的jar +生成的build-info.properties资源的类路径。

我总是以不同的名称来构建jar,因此我可以通过部分构建来避免这种问题。

https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#packaging-executable-and-normal

  

为避免将可执行存档和普通存档写入同一位置,应将一个或另一个配置为使用其他位置。一种方法是配置分类器:

bootJar {
    classifier = 'boot'
}

答案 8 :(得分:0)

正如其他答案所表明的,这是由于IDE未创建文件。对于vscode,我通过定义一个任务将Gradle的 build / resources / main / META-INF 目录中的 build-info.properties 文件复制到vscode的中来解决了该问题bin / main / META-INF ,这样构建就可以在其中找到它。

通常我最近运行过Gradle构建,而build-info.properties的较陈旧版本足以让我在vscode中运行调试。

创建类似于以下内容的 .vscode / tasks.json

{
    "version": "2.0.0",
    "tasks": [
        {
            // This task keeps vscode from failing when using BuildProperties
            "label": "Copy build-info from Gradle",
            "type": "shell",
            "command": "mkdir -p ./bin/main/META-INF/ && cp ./build/resources/main/META-INF/build-info.properties ./bin/main/META-INF/build-info.properties"
        }
    ]
}

然后将任务作为 preLaunchTask 添加到您的 .vscode / launch.json 中:

{
    "configurations": [
        {
            "type": "java",
            "name": "Spring Boot-Application<example>",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "console": "internalConsole",
            "mainClass": "com.example.Application",
            "projectName": "example",
            "args": "",
            "preLaunchTask": "Copy build-info from Gradle"
        }
    ]
}

答案 9 :(得分:0)

我尝试了ProjectInfoAutoConfiguration解决方案,并认为最好使用@ConditionalOnMissingBean (BuildProperties.class) @ConditionalOnResource (resources = "$ {spring.info.build.location: classpath: META-INF / build-info.properties}")

因为我可以控制创建BuildProperties的方式:

    @ConditionalOnMissingBean(BuildProperties.class)
    @Bean
    public BuildProperties buildProperties() throws IOException {
            Resource r = this.properties.getBuild().getLocation();
            if (r.exists())
                // build-info.properties exists in my jar
                return new BuildProperties(
                    loadFrom(r, "build")); // see ProjectInfoAutoConfiguration code
            else {
                // No, we running via IDE. So let's build a stub:
                Properties properties = new Properties();
                properties.put("group", "com.example");
                properties.put("artifact", "demo");
                properties.put("version", "not-jarred");
                return new BuildProperties(properties);
            }
    }

答案 10 :(得分:0)

如果您使用的是 lombok,请确保排除 spring-boot-maven-plugin 的配置,例如,

    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <excludes>
                <exclude>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                </exclude>
            </excludes>
        </configuration>
        <executions>
            <execution>
                <id>build-info</id>
                <goals>
                    <goal>build-info</goal>
                </goals>
            </execution>
        </executions>
    </plugin>