Ошибка автоматического подключения BuildProperties Spring Boot 2.1.5 и eclipse

Я создаю очень простое приложение с несколькими REST API, и в настоящее время оно работает правильно, пока я не попытаюсь использовать BuildProperties в моем API проверки работоспособности. При запуске моего приложения я получаю следующую ошибку:

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\". У меня также есть другие элементы "Autowired", которые не имеют проблем.

Где мой код не работает:

@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()
}

сборка-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

Вы используете IntelliJ?

Rohit 17.06.2019 17:10

нет, я использую затмение. Я также вставил содержимое файла сборки gradle на тот случай, если это какая-то известная проблема с одним из плагинов, например плагином eclipse или чем-то еще.

ROOTKILL 17.06.2019 17:12

Какую версию JDK вы используете в своем приложении с весенней загрузкой?

Borislav Markov 17.06.2019 17:38

У вас есть какие-либо из них, определенные в вашем проекте: «@SpringBootApplication» или «@EnableAutoConfiguration»?

Borislav Markov 17.06.2019 17:40

Не могли бы вы также указать содержимое build-info.properties в вопросе, пожалуйста?

Borislav Markov 17.06.2019 17:43

@BorislavMarkov openJDK 12, у меня есть «@SpringBootApplication» в моем основном классе, и в результате build-info.properties выглядит следующим образом: #Properties #Mon 17 Jun 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

ROOTKILL 17.06.2019 17:53

Можете ли вы также упомянуть, как вы запускаете процесс, из командной строки или из eclipse? У вас такая же ошибка, когда вы начинаете с java -jar <jarname>?

Borislav Markov 17.06.2019 17:54

Я запускаю его с помощью плагина весенней загрузки в eclipse, «щелкните правой кнопкой мыши проект» -> «запустить как» или «отладить как» -> приложение Spring Boot. Я не пробовал запускать его из командной строки, вскоре опубликую результаты. Спасибо

ROOTKILL 17.06.2019 17:58
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
27
8
38 302
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Я бы предложил попробовать запустить под JDK 8 и запустить из командной строки с помощью java -jar <your jar name> просто чтобы убедиться, что вы правильно поняли свойства сборки.

Возможно, Jdk 12 еще не подходит для весенней загрузки. Думаю, у вас могут быть и другие проблемы. Многие фреймворки Java не сертифицированы на 100% для работы с JDK 12.

Я думаю, что план состоит в том, чтобы официально поддерживать Java 12 начиная с Spring Boot 2.2.

Я запустил приложение в командной строке как с JDK 8, так и с JDK 12, и они, кажется, работают нормально через командную строку. Похоже, это связано с плагином весенней загрузки для eclipse. Спасибо за помощь!!!

ROOTKILL 17.06.2019 20:16
Ответ принят как подходящий

Как предложил @Borislav Markov, я попытался запустить его через командную строку, и, похоже, он отлично работает независимо от того, использую ли я JDK 12 или JDK 8. Я думаю, что проблема связана с плагином eclipse, который я использую для запуска приложения через IDE.

В моем случае я использую Intellij. Я сделал следующее: настройки> сборка> gradle> runner> проверить делегирование действий сборки/запуска IDE для gradle

user666 17.12.2019 11:52

@user666 user666 Теперь это находится в разделе «Настройки»> «Сборка, выполнение, развертывание»> «Инструменты сборки»> «Gradle», а затем функция под названием «Сборка и запуск с использованием».

Jelle Blaauw 06.02.2020 17:12

Я думаю, что вашу IDE смущает тот факт, что «толстая банка» перезаписывает обычную банку. Среда IDE понимает путь к классу обычного jar + сгенерированного ресурса `build-info.properties.

Я всегда создаю банки под разными именами, поэтому я могу избежать подобных проблем с частичными сборками.

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

To avoid the executable archive and the normal archive from being written to the same location, one or the other should be configured to use a different location. One way to do so is by configuring a classifier:

bootJar {
    classifier = 'boot'
}

Добавить/изменить в конце 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>

Вкратце: Эта проблема связана с IDE (я проверял Eclipse и Idea), и это не влияет на запуск/отладку весеннего загрузочного приложения в сценариях запуска в системе сборки gradle.

Кроме того, предположение о том, что загрузочный плагин для eclipse и JDK создает эту проблему, не совсем верно.

Корень этой проблемы: Различное расположение артефактов сборки, которые скомпилированы разными компиляторами и отсутствуют build-info.properties.

Объяснение:

Когда gradle выполняет сборку, он обычно использует компилятор JDK для создания артефактов Java, а вывод помещается в каталог сборки.

С другой стороны, когда eclipse выполняет сборку, он создает артефакты с помощью Eclipse JDT, а выходные данные помещаются в каталог bin.

Обратите внимание, что смешивание этих двух может привести к неожиданному поведению. Эта «функция» уже проанализирована командой eclipse и отклонена (закрыта как недействительная). Дополнительная информация здесь.

В соответствии с тем фактом, что задача Gradle buildInfo запускается Gradle, это объясняет тот факт, что файл build-info.properties существует в выходной папке Gradle по умолчанию (по умолчанию он должен находиться здесь: build/resources/main/META-INF/).

Из вопроса @ROOTKILL видно, что он пытается получить информацию из класса BuildProperties. Под капотом, когда Spring обнаруживает, что в пути к классам есть файл build-info.properties, он создает bean-компонент BuildProperties, если он не объявлен явно. Полезная информация здесь.

Пожалуйста, взгляните на этот метод:

@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"));
}

В связи с тем, что IDE использует другой выходной каталог, отсутствует файл build-info.properties, что приводит к отображаемой ошибке (Bean method 'buildProperties' in 'ProjectInfoAutoConfiguration' not loaded because @ConditionalOnResource did not find resource '${spring.info.build.location:classpath:META-INF/build-info.properties}'). А с другой стороны, это объясняет, почему все запускается с помощью Gradle.

Решение:

В соответствии с этими фактами решение очевидно: как eclipse, так и IntelliJ Idea IDE должны использовать задачи gradle вместо собственных для запуска/отладки.

  • Для Затмение IDE: приложение можно запустить поверх задачи gradle (bootRun из представления задач gradle).
  • Для Идея IDE: можно добавить параметр, который делегирует действия по сборке/запуску IDE для gradle, который уже указан ранее @user666.

Поскольку в этом решении используется gradle, файл build-info.properties будет использоваться из местоположения build/resources/main/META-INF/ (по умолчанию для gradle), и, конечно же, он будет виден. Как следствие, будет создан bean-компонент BuildProperties, и его можно будет использовать.

Просто запустите mvn clean package, а затем перезапустите приложение весенней загрузки из Eclipse/IntelliJ.

Работает, спасибо! mvn clean package.

Lucas 22.10.2021 18:33

Это сработало для меня. Кто-нибудь знает, почему?

James Hackett 15.02.2022 14:13

@JamesHackett Этот файл (build-info.properties) читается Spring из папки META-INF/ вашего пути к классам. Делая это, он создается там вашим инструментом сборки (maven, gradle и т. д.).

Papa Cheikh Cisse 18.03.2022 15:33

В моем сервисе Spring Boot есть раздел информации о сборке Maven в плагине maven-spring-boot, поэтому я получаю эту ошибку BuildProperties cannot be found, когда пытаюсь запустить сервис, если он не из архива .jar. Итак, чтобы запустить мою службу как обычную конфигурацию запуска 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);
}

Это неправильное решение, если вы хотите использовать оригинальные свойства build-info.properties. Этот метод всегда переопределяет условный механизм Spring по умолчанию.

dobrosi 11.10.2021 10:26

Это неправильный способ сделать это. В идеале свойства должны автоматически загружаться из build-info.properties или должны поступать из pom.xml или build.gradle и внедряться.

arun 24.02.2022 00:43

Хорошо знать. Спасибо.

djangofan 25.02.2022 18:06

Как ясно из других ответов, это связано с тем, что среда IDE не создает файл. Для vscode я решил эту проблему, поставив задачу скопировать файл build-info.properties из каталога сборка/ресурсы/основной/META-INF Gradle в каталог корзина/основной/META-INF vscode, чтобы он находился там, где сборка ожидает его найти.

Обычно я недавно запускал сборку 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"
        }
    ]
}

Я попробовал решение Информация о проектеАвтоконфигурация и подумал, что вместо него лучше использовать @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);
            }
    }

Если вы используете ломбок, обязательно исключите его конфигурацию для 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>

Как правильно упомянул @Андре Шонрок, причиной проблемы является здесь:

Both the Maven plugin and the Gradle plugin allow generating build information containing the coordinates, name, and version of the project. The plugins can also be configured to add additional properties through configuration. When such a file is present, Spring Boot auto-configures a BuildProperties bean.

Итак, вам нужно либо добавить для spring-boot-maven-plugin в POM:

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

или добавить build.gradle:

springBoot {
    buildInfo()
}

В качестве альтернативы можно явно добавить Bean в более короткой форме, чем показано @djangofan:

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

в файле конфигурации.

Уведомление:, если вы обновили POM или build.gradle, но ошибка все еще появляется, попробуйте использовать (например, для Maven) команды жизненного цикла clean, а затем install и снова запустите проект.

Если вы используете Intelli и maven, вот скриншот о том, как изменить бегун и использовать бегун maven. В идеале это лучше всего предложить, так как мы можем точно так же запустить maven в ide.

Для проекта Gradle: добавьте это в файл build.gradle

    springBoot {
        buildInfo {
            properties {
                name = PROJECT_NAME
                additional = [
                        'yourCustomInfo': 'someInfo'
                ]
            }
        }
    }

Привет! Если бы я хотел иметь поле с именем build.version со значением version в моем build.gradle, как мне получить к нему доступ?

sebasira 19.12.2021 18:21

Проблема заключается в том, что STS и Intellij не запускают задачу buildinfo при запуске приложения в качестве приложения Spring Boot. Поскольку большинство разработчиков запускают приложение с помощью этого механизма, а не используют сборку gradle/maven, необходимо иметь решение, которое работает для обоих. Я последовал ответу Сергея К., и это сработало для загрузки Spring на основе IDE. Но для запуска gradle это не удалось, потому что BuildProperties автоматически подключались из файла конфигурации вместо сгенерированного файла build-info.properties.

Я смог преодолеть это, имея следующий компонент и автоматически подключив его.

@Component
public BuildValues{
   @Autowired(required = false)
   private buildProperties;
   
   public getBuildProperties(){
       if (buildProperties==null) {
          ResourceLoader resourceLoader = new DefaultResourceLoader();
          Resource r = resourceLoader.getResource("classpath:META-INF/build- 
        info.properties");
    if (r.exists()) {
        // build-info.properties exists in my jar
        Properties prop = PropertiesLoaderUtils.loadProperties(r);
        buildProperties =  new BuildProperties(prop);
    }else {
    // No, we running via IDE. So let's build a stub:
        Properties properties = new Properties();
        properties.put("buildTime", "2022-01-13T14:38:06.567Z");
        buildProperties = new BuildProperties(properties);
    }
    }
    return buildProperties;
   }

} 

Другие вопросы по теме