Spring Boot 2 - сделать что-то до инициализации bean-компонентов - PullRequest
6 голосов
/ 06 ноября 2019

Постановка проблемы

Я хочу загрузить свойства из файла свойств в classpath или во внешнем расположении до инициализации bean-компонентов. Потому что эти свойства также будут частью инициализации Бина. Я не могу автоматически связать эти свойства со стандартным application.properties Spring или его настройкой, потому что один и тот же файл свойств должен быть доступен нескольким depoyables.

Что я пробовал

I 'm осведомлен о событиях весенних приложений ;На самом деле, я уже подключаю ContextRefreshedEvent для выполнения некоторых задач после инициализации контекста Spring (компоненты Bean также инициализируются на этом этапе).

Для моего постановки задачи из описания SpringДокументы ApplicationEnvironmentPreparedEvent выглядели многообещающе, но я не могу заставить их работать.


@SpringBootApplication
public class App {

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


    @EventListener
    public void onStartUp(ContextRefreshedEvent event) {
        System.out.println("ContextRefreshedEvent");    // WORKS
    }

    @EventListener
    public void onShutDown(ContextClosedEvent event) {
        System.out.println("ContextClosedEvent");   // WORKS
    }

    @EventListener
    public void onEvent6(ApplicationStartedEvent event) {
        System.out.println("ApplicationStartedEvent");  // WORKS BUT AFTER ContextRefreshedEvent
    }


    @EventListener
    public void onEvent3(ApplicationReadyEvent event) {
        System.out.println("ApplicationReadyEvent");    // WORKS WORKS BUT AFTER ContextRefreshedEvent
    }


    public void onEvent1(ApplicationEnvironmentPreparedEvent event) {
        System.out.println("ApplicationEnvironmentPreparedEvent");  // DOESN'T WORK
    }


    @EventListener
    public void onEvent2(ApplicationContextInitializedEvent event) {
        System.out.println("ApplicationContextInitializedEvent");   // DOESN'T WORK
    }


    @EventListener
    public void onEvent4(ApplicationContextInitializedEvent event) {
        System.out.println("ApplicationContextInitializedEvent");
    }

    @EventListener
    public void onEvent5(ContextStartedEvent event) {
        System.out.println("ContextStartedEvent");
    }

}

Обновление

Как подсказано M.Deinum в комментариях, япопытался добавить инициализатор контекста приложения, как показано ниже. Похоже, он тоже не работает.

    public static void main(String[] args) {
        new SpringApplicationBuilder()
                .sources(App.class)
                .initializers(applicationContext -> {
                    System.out.println("INSIDE CUSTOM APPLICATION INITIALIZER");
                })
                .run(args);

    }

Обновление # 2

Хотя мое постановление проблемы касается загрузки свойств, мой вопрос / любопытство действительно о как запуститьнекоторый код перед тем, как классы инициализируются как бины и помещаются в контейнер Spring IoC . Теперь этим компонентам требуются значения некоторых свойств во время инициализации, и я не могу / не хочу автоматически связывать их по следующей причине.

Хотя, как указано в комментариях и ответах, то же самое можно сделать с помощьюВнешняя конфигурация и профили Spring Boot. Однако мне нужно поддерживать свойства приложения и свойства, связанные с доменом, отдельно. Ожидается, что свойства базового домена будут иметь не менее 100 свойств, которые будут расти со временем. У каждого из них есть файл свойств, каждый для своей среды (dev, SIT, UAT, Production), который будет переопределять одно или несколько базовых свойств. Это 8 файлов свойств. Теперь одно и то же приложение необходимо развернуть в нескольких регионах. Это делает его 8 * n файлами свойств, где n - количество географических регионов. Я хочу, чтобы все они хранились в общем модуле, чтобы к нему могли обращаться различные развертываемые объекты. Окружение и география будут известны во время выполнения как системные свойства.

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

public class MyPropUtil {
     private static Map<String, Properties> repository;

     public static initialize(..) {
         ....
     }

     public static String getDomainProperty(String key) {
        return repository.get("domain").getProperty(key);
     }

     public static String getAppProperty(String key) {
         return repository.get("app").getProperty(key);
     }

     public static String getAndAddBasePathToAppPropertyValue(String key) {
        ...
     }

}

@Configuration
public class MyComponent {

    @Bean
    public SomeClass getSomeClassBean() {
        SomeClass obj = new SomeClass();
        obj.someProp1(MyPropUtil.getDomainProperty('domainkey1'));
        obj.someProp2(MyPropUtil.getAppProperty('appkey1'));
        // For some properties
         obj.someProp2(MyPropUtil.getAndAddBasePathToAppPropertyValue('some.relative.path.value'));
        ....
        return obj;
    }

}

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

Ответы [ 11 ]

0 голосов
/ 09 ноября 2019

Как объяснено в этом посте , вы можете добавить внешние файлы свойств, например так:

public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
    properties.setLocation(new FileSystemResource("/Users/home/conf.properties"));
    properties.setIgnoreResourceNotFound(false);
    return properties;
}

Если вы не хотите использовать это, просто прочитайте файл свойств с Джексоном иустановите свойства System.setProperty("key","value") в методе main до начала весны.

Если вы не хотите использовать это тоже, взгляните на метод BeanPostProcessor#postProcessBeforeInitialization. Он запускается до того, как свойства бина будут инициализированы весной.

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