2015-01-30 3 views
12

В моем приложении загрузки Spring мне нужно дождаться, когда веб-сервер (по умолчанию Tomcat) будет полностью инициализирован и готов принять трафик, прежде чем отправлять сообщения другим приложениям, сообщающим им отправлять HTTP-запросы для меня (в частности, система мониторинга, которая поражает мой /health).Spring Boot - Подождите, пока веб-сервер запустится

Я попытался поместить логику, отправляющую сообщения в другие приложения, в ApplicationListener<ContextRefreshedEvent>, но все еще слишком рано. Другие приложения пытаются запросить меня и провалиться. Прямо сейчас я положил задержку в onApplicationEvent, и это работает, но это взломано и ярко.

Я также попытался добавить ServletContextInitializer, но уволен еще раньше.

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

+0

Вы видели: HTTP : //stackoverflow.com/a/4747639/283084? Кроме того, возможно, вы можете скрыть свое приложение за LB, и LB не будет принимать ваше приложение в свой пул, пока запрос '/ health' не вернет HTTP OK (200). – harpun

ответ

16

Проще всего сделать это отправить сообщение после того, как SpringApplication.run() вернулся. Этот метод не вернется, пока Tomcat (или любой другой поддерживаемый встроенный контейнер) не будет полностью запущен и не прослушивает сконфигурированные порты. Однако, хотя это просто, это не очень аккуратный подход, поскольку он смешивает проблемы вашего основного класса конфигурации и некоторой логики выполнения приложения.

Вместо этого вы можете использовать SpringApplicationRunListener. finished() не будет вызываться до тех пор, пока Tomcat не будет полностью запущен и не прослушивает сконфигурированный порт.

Создайте файл с именем src/main/resources/META-INF/spring.factories, в котором перечислены ваши слушатели. Например:

org.springframework.boot.SpringApplicationRunListener=com.example.MyRunListener 

Создать свой запуск слушатель с требуемым конструктором и реализовать SpringApplicationRunListener. Например:

package com.example; 

import org.springframework.boot.SpringApplication; 
import org.springframework.boot.SpringApplicationRunListener; 
import org.springframework.context.ConfigurableApplicationContext; 
import org.springframework.core.env.ConfigurableEnvironment; 

public class MyRunListener implements SpringApplicationRunListener { 

    public MyRunListener(SpringApplication application, String[] args) { } 

    @Override 
    public void started() { } 

    @Override 
    public void environmentPrepared(ConfigurableEnvironment environment) { } 

    @Override 
    public void contextPrepared(ConfigurableApplicationContext context) { } 

    @Override 
    public void contextLoaded(ConfigurableApplicationContext context) { } 

    @Override 
    public void finished(ConfigurableApplicationContext context, Throwable exception) { 
     // Send message; Tomcat is running and listening on the configured port(s) 
    } 
} 
+1

Отлично работает. Я создал другой интерфейс, который могут реализовать заинтересованные компоненты, и мой 'SpringApplicationRunListener' вытаскивает их из контекста и вызывает их, поэтому логика может оставаться в соответствующих компонентах. – sourcedelica

5

С весны загрузки 1.3.0 это также может быть достигнуто за счет внедрения ApplicationListener<ApplicationReadyEvent>

пример:

public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent>, Ordered { 

    @Override 
    public void onApplicationEvent(ApplicationReadyEvent event) { 
     //do stuff now that application is ready 
    } 

    @Override 
    public int getOrder() { 
     return Ordered.LOWEST_PRECEDENCE; 
    } 
} 

Кроме того, как было упомянуто в принятом ответе, вы можете создать файл с именем src/main/resources/META-INF/spring.factories с указанием вашего ApplicationListener. Например: однако

org.springframework.context.ApplicationListener=com.example.MyApplicationListener 

, в моем случае, я только нужен этот приемник для работы под определенным профилем

поэтому я добавил следующее свойство application-<profile_name>.properties

context.listener.classes=com.example.MyApplicationListener