Запуск кода после запуска Spring Boot

211

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

Я попытался запустить новый поток, но @Autowiredслужбы не были установлены в этот момент.

Я был в состоянии найти ApplicationPreparedEvent, который срабатывает до того, как @Autowiredаннотации установлены. В идеале я хотел бы, чтобы событие запускалось, когда приложение готово к обработке запросов http.

Есть ли лучшее событие для использования или лучший способ запуска кода после того, как приложение будет запущено при весенней загрузке ?

stewsters
источник
Spring boot предоставляет два интерфейса ApplicationRunner и CommandLineRunner, которые можно использовать, когда вы хотите запустить код после запуска весенней загрузки. Вы можете обратиться к этой статье за ​​примером реализации - jhooq.com/applicationrunner-spring-boot
Рахул Ваг

Ответы:

121

Пытаться:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application extends SpringBootServletInitializer {

    @SuppressWarnings("resource")
    public static void main(final String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

        context.getBean(Table.class).fillWithTestdata(); // <-- here
    }
}
Антон Бессонов
источник
6
это не работает, когда вы развертываете приложение как файл war на внешнем коте. Работает только со встроенным котом
Saurabh
Нет, это не работает. Но в этом случае я предпочитаю более явный способ, чем @Component. Смотрите ответ @cjstehno, чтобы заставить его работать в файле войны.
Антон Бессонов
322

Это так просто, как это:

@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
    System.out.println("hello world, I have just started up");
}

Проверено на версии 1.5.1.RELEASE

Каен
источник
7
Спасибо вам. это заставило мой код работать без каких-либо изменений. Еще раз спасибо за такой простой ответ. Это также будет работать с аннотацией @RequestMapping без каких-либо проблем.
Харшит
16
Кто-то может также захотеть использовать @EventListener(ContextRefreshedEvent.class)вместо этого, который запускается после создания компонента, но до запуска сервера. Его можно использовать для выполнения действий до того, как какие-либо запросы попадут на сервер.
neeraj
3
@neeraj, вопрос о запуске кода после запуска Spring Boot. Если вы используете ContextRefreshedEvent, он будет работать после каждого обновления тоже.
Cahen
4
протестирован на Spring boot 2.0.5. RELEASE
ritesh
2
Проверено на версии 2.2.2. это работает отлично. это решение экономит мое время.
Арфил
96

Вы пробовали ApplicationReadyEvent?

@Component
public class ApplicationStartup 
implements ApplicationListener<ApplicationReadyEvent> {

  /**
   * This event is executed as late as conceivably possible to indicate that 
   * the application is ready to service requests.
   */
  @Override
  public void onApplicationEvent(final ApplicationReadyEvent event) {

    // here your code ...

    return;
  }
}

Код от: http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/

Вот что упоминается в документации о событиях запуска:

...

События приложения отправляются в следующем порядке по мере запуска приложения:

ApplicationStartedEvent отправляется в начале выполнения, но перед любой обработкой, кроме регистрации слушателей и инициализаторов.

ApplicationEnvironmentPreparedEvent отправляется, когда среда, используемая в контексте, известна, но до создания контекста.

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

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

ApplicationFailedEvent отправляется, если при запуске возникает исключение.

...

raspacorp
источник
11
В качестве альтернативы вы можете сделать это, используя @EventListenerаннотацию к методу Bean, передавая в качестве аргумента событие класса, к которому вы хотите подключиться.
Padilo
2
Это должен быть выбранный ответ.
varun113
2
Это изменилось в весенней загрузке 2. Если вы портируете с 1.x и используете ApplicationStartedEvent, то теперь вы хотите вместо этого использовать ApplicationStartingEvent.
Энди Браун
Это работает абсолютно нормально, и я думаю, что лучший способ сделать это.
АВИНАШ ШРИМАЛИ
ты лучший
ancm
83

Почему бы просто не создать компонент, который запускает ваш монитор при инициализации, что-то вроде:

@Component
public class Monitor {
    @Autowired private SomeService service

    @PostConstruct
    public void init(){
        // start your monitoring in here
    }
}

initметод не будет вызываться до любого автоматического связывания не делается для боба.

cjstehno
источник
14
Иногда @PostConstructсрабатывает слишком рано. Например, при использовании Spring Cloud Stream Kafka @PostConstructсрабатывает перед привязкой приложения к Kafka. Решение Дэйва Сайера лучше, потому что оно срабатывает своевременно.
Эльнур Абдуррахимов
9
@PostConstructпроисходит во время инициализации, а не после. Хотя это может быть полезно в некоторых случаях, это неправильный ответ, если вы хотите запустить после запуска Spring Boot. Например, пока @PostConstructне заканчивается, ни одна из конечных точек не доступна.
Каен
64

«Spring Boot» - это использование CommandLineRunner. Просто добавьте бобы этого типа, и все готово. В Spring 4.1 (Boot 1.2) также есть SmartInitializingBeanфункция обратного вызова после того, как все инициализировано. И есть SmartLifecycle(с весны 3).

Дейв Сайер
источник
Любой пример этого? Можно ли выполнить bean-компонент после запуска приложения через командную строку в произвольный момент?
Эмилио
5
Не знаю, что вы подразумеваете под «произвольным моментом». В руководстве пользователя Spring Boot и в примерах приведены примеры использования CommandLineRunner(и более новых ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Дэйв Сайер
Я обнаружил, что жизненный цикл является предпочтительным вариантом для выполнения асинхронных задач на этапах запуска / остановки приложения, и я пытаюсь обнаружить другие различия между CommandLineRunner и InitializingBeans, но не могу ничего найти по этому поводу.
saljuama
3
пара обычно пример кода использованияCommandLineRunner
Алексей Симонов
41

Вы можете расширить класс, используя ApplicationRunner, переопределить run()метод и добавить туда код.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {

        //code goes here

    }
}
Gimhani
источник
Идеально в Spring Boot. Но метод run () вызывался дважды при наличии ApplicationScope для класса. Так что метод PostConstruct с вышеописанным сработал лучше.
Сэм
26

ApplicationReadyEventдействительно полезно, только если задача, которую вы хотите выполнить, не является обязательной для правильной работы сервера. Хороший пример - запуск асинхронной задачи для отслеживания изменений.

Однако, если ваш сервер находится в состоянии «не готов» до тех пор, пока задача не будет завершена, его лучше реализовать, SmartInitializingSingletonпоскольку вы получите обратный вызов до того, как ваш порт REST будет открыт, а ваш сервер открыт для бизнеса.

Не поддавайтесь искушению использовать @PostConstructдля задач, которые должны произойти только один раз. Вы получите грубый сюрприз, когда заметите, что он вызывается несколько раз ...

Энди Браун
источник
Это должен быть выбранный ответ. Как указывает @Andy, SmartInitializingSingleton вызывается непосредственно перед открытием портов.
Срикант
25

С пружинной конфигурацией:

@Configuration
public class ProjectConfiguration {
    private static final Logger log = 
   LoggerFactory.getLogger(ProjectConfiguration.class);

   @EventListener(ApplicationReadyEvent.class)
   public void doSomethingAfterStartup() {
    log.info("hello world, I have just started up");
  }
}
freemanpolys
источник
12

Используйте SmartInitializingSingletonбоб весной> 4.1

@Bean
public SmartInitializingSingleton importProcessor() {
    return () -> {
        doStuff();
    };

}

В качестве альтернативы CommandLineRunnerbean-компонент может быть реализован или аннотировать метод bean-компонента с помощью @PostConstruct.

Джефф
источник
Могу ли я требовать зависимости Autowired внутри этого метода? Я хотел бы установить Профили
LppEdd
7

Предоставление примера для ответа Дейва Сайера, который работал как обаяние:

@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(CommandLineAppStartupRunner.class);

    @Override
    public void run(String...args) throws Exception {
        logger.info("Application started with command-line arguments: {} . \n To kill this application, press Ctrl + C.", Arrays.toString(args));
    }
}
Пауло Педросо
источник
7

Попробуйте это, и он запустит ваш код, когда контекст приложения полностью запустится.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent arg0) {
                // EXECUTE YOUR CODE HERE 
    }
}
Kalifornium
источник
6

Мне очень нравится предложение об использовании EventListenerаннотации @cahen ( https://stackoverflow.com/a/44923402/9122660 ), поскольку она очень чистая. К сожалению, я не смог заставить это работать в настройках Spring + Kotlin. Что работает для Kotlin, так это добавление класса в качестве параметра метода:

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}
Ostecke
источник
Поместите это в класс приложения весенней загрузки не случайно@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ахмед на
вам не нужно указывать это в классе @SpringBootApplication. подойдет любой класс конфигурации
Джордж Марин
5

Лучший способ выполнить блок кода после запуска приложения Spring Boot - использовать аннотацию PostConstruct. Или вы также можете использовать для этой цели средство запуска командной строки.

1. Использование аннотации PostConstruct

@Configuration
public class InitialDataConfiguration {

    @PostConstruct
    public void postConstruct() {
        System.out.println("Started after Spring boot application !");
    }

}

2. Использование bean-компонента командной строки

@Configuration
public class InitialDataConfiguration {

    @Bean
    CommandLineRunner runner() {
        return args -> {
            System.out.println("CommandLineRunner running in the UnsplashApplication class...");
        };
    }
}
Нареш Бхадке
источник
3

просто внедрите CommandLineRunner для весенней загрузки приложения. Вам нужно реализовать метод запуска,

public classs SpringBootApplication implements CommandLineRunner{

    @Override
        public void run(String... arg0) throws Exception {
        // write your logic here 

        }
}
прасад кп
источник
0

Наилучший способ использования CommandLineRunner или ApplicationRunner Единственное отличие заключается в том, что метод run () CommandLineRunner принимает массив строк, а ApplicationRunner принимает ApplicationArugument.

Руши Ванга
источник