Как сделать так, чтобы приложение весенней загрузки завершалось при запуске - PullRequest
5 голосов
/ 15 мая 2019

Я хочу реализовать следующий вариант использования - мое приложение весенней загрузки должно запускаться, только если задано определенное свойство в application.yaml:

myapp
    active: true

Если свойство не установлено, инициализация контекста должнаОшибка с сообщением о том, что свойство отсутствует.

Я нашел в этой теме, как этого добиться: Spring Boot - обнаружение и завершение, если свойство не установлено? , но проблема, почему я могу 'Этот подход заключается в том, что возможно, что инициализация контекста завершится неудачно до загрузки bean-компонента, который проверяет это свойство.

Например, если не удается загрузить какой-либо другой bean-компонент из-за отсутствия другого свойства, контекстинициализация завершится неудачей, и мой bean-компонент, который проверяет желаемое свойство, не будет загружен.Это не нормально для меня, потому что я хочу, чтобы свойство myapp.active было проверено в первую очередь, до того, как будут загружены любые другие bean-компоненты.

Причина, по которой я хочу это сделать, заключается в том, чтопри запуске приложения должен быть установлен определенный профиль - application- [profile] .yaml содержит как «myapp.active: true», так и некоторые другие обязательные свойства, необходимые для загрузки контекста.

Я хочу, чтобы мое приложение всегда вызывало сбой, поскольку myapp.active не соответствует действительности, поэтому я могу вывести значимое сообщение о том, что профиль отсутствует и что приложение должно быть запущено с одним из профилей (из заданногосписок профилей).Некоторые ребята, которые не являются разработчиками, запускают приложение, поэтому я хочу, чтобы они знали, почему приложение не запускалось, иначе они подумают, что в приложении есть какая-то ошибка.

Как мне этого добиться?Можно ли как-то прочитать свойство до загрузки bean-компонентов?Я хотел бы избежать установки @ DependsOn на всех компонентах (или делать то же самое через BeanPostProcesser) и ищу более элегантное решение.

1 Ответ

5 голосов
/ 15 мая 2019

Приложение не запустится, если вы используете условие на свойстве.Достаточно быстро?

 @SpringBootApplication
 @ConditionalOnProperty(name = "myapp.active")
 public class FastFailWhenPropertyNotPresentApplication {

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

}

В основном @SpringBootApplication - это просто класс @Configuration.

У вас есть опция matchIfMissing, которую можно использовать, чтобы указать, должно ли условие соответствовать, еслисвойство не установлено.По умолчанию используется значение false.

РЕДАКТИРОВАТЬ:

Лучшим решением является настройка вашей собственности с помощью @ConfigurationProperties в сочетании с @Validated, чтобы вы могли использовать javax.validation.constraints annotations.

package stackoverflow.demo;

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

@Component
@ConfigurationProperties(prefix = "myapp")
@Validated
public class MyAppProperties {

  @AssertTrue
  @NotNull
  private Boolean active;

  public Boolean getActive() {
    return active;
  }

  public void setActive(Boolean active) {
    this.active = active;
  }

}

примечание: вы можете не указывать @ConditionalOnProperty(name = "myapp.active")

использовать @AssertTrue в сочетании с @NotNull, поскольку @AssertTrue считает нулевые элементы действительными.

и spring-boot бесплатно генерирует красивое сообщение об ошибке:

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

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'myapp' to stackoverflow.demo.MyAppProperties failed:

    Property: myapp.active
    Value: false
    Origin: class path resource [application.properties]:1:16
    Reason: must be true


Action:

Update your application's configuration

EDIT (после обновленного вопроса)


Более быстрый способ: ваше приложение не запустится, и контекст приложения не будет загружен

package stackoverflow.demo;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.ClassPathResource;

@SpringBootApplication
public class FastFailWhenPropertyNotPresentApplication {

  static Boolean active;

  static {

    YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
    yaml.setResources(new ClassPathResource("application.yaml"));

    active = (Boolean) yaml.getObject().getOrDefault("myapp.active", false);

  }


    public static void main(String[] args) {
        if (!active) {
          System.err.println("your fail message");
        } else {
          SpringApplication.run(FastFailWhenPropertyNotPresentApplication.class, args);
        }
    }

}

РЕДАКТИРОВАТЬ

другое решение, которое, вероятно,лучше всего соответствует вашим потребностям ...

Прослушивая событие ApplicationEnvironmentPreparedEvent

, опубликованное, когда запускается {@link SpringApplication} и * {@link Environment}сначала доступны для проверки и модификации.*

примечание: вы не можете использовать @EventListener, но вы добавили Слушатель к SpringApplication

package stackoverflow.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;

@SpringBootApplication
public class FastFailWhenPropertyNotPresentApplication {


  static class EnvironmentPrepared implements ApplicationListener<ApplicationEnvironmentPreparedEvent>{
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
      Boolean active = event.getEnvironment().getProperty("myapp.active",Boolean.class,Boolean.FALSE);
      if(!active) {
        throw new RuntimeException("APPLICATION FAILED TO START: ACTIVE SHOULD BE TRUE ");
      }
    }
  };


  public static void main(String[] args) throws Exception {
    SpringApplication springApplication = new SpringApplication(FastFailWhenPropertyNotPresentApplication.class);
    springApplication.addListeners(new FastFailWhenPropertyNotPresentApplication.EnvironmentPrepared());
    springApplication.run(args);
  }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...