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


211

Я хочу запустити код після того, як мій додаток Spring -boot починає стежити за каталогом змін.

Я спробував запустити новий потік, але @Autowiredслужби не було встановлено на той момент.

Мені вдалося виявити ApplicationPreparedEvent, що викликає перед встановленням @Autowiredанотацій. В ідеалі я хотів би, щоб подія стартувала після запуску програми для обробки запитів http.

Чи є краща подія для використання чи кращий спосіб запуску коду після того, як додаток перебуває у прямому режимі завантаження ?



Весняне завантаження забезпечує два інтерфейси 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
це не працює, коли ви розгортаєте додаток як файл війни на зовнішній tomcat. Працює лише з вбудованим томатком
Саураб

Ні, це не працює. Але в цьому випадку використання мені подобається більш чіткий спосіб замість цього @Component. Дивіться відповідь від @cjstehno, щоб він працював у файлі війни.
Антон Бессонов

320

Це так просто, як це:

@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)замість цього, що спрацьовує після створення bean, але до запуску сервера. З його допомогою можна виконувати дії, перш ніж будь-які запити потрапляють на сервер.
neeraj

3
@neeraj, питання про запуск коду після запуску Spring Boot. Якщо ви користуєтесь ContextRefreshedEvent, вона також працюватиме після кожного оновлення.
cahen

4
протестований на Спрінг завантаження 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 відправляється, якщо є виняток при запуску.

...


11
Як альтернативу, ви можете зробити це, використовуючи @EventListenerанотацію за методом Bean, передаючи в якості аргументу подію класу, до якої потрібно підключити.
паділо

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метод не буде викликатися до будь-якого автоматичного зв'язування не робиться для бобу.


14
Іноді @PostConstructпожежі занадто рано. Наприклад, коли використовується Spring Cloud Stream Kafka, @PostConstructпожежі перед додатком прив'язуються до Kafka. Рішення Дейва Сайера краще, оскільки воно вчасно стріляє.
Ельнур Абдурахімов

9
@PostConstructвідбувається під час ініціалізації, а не після. Хоча це може бути корисно в деяких випадках, це неправильна відповідь, якщо ви хочете запуститись після запуску Spring Boot. Наприклад, @PostConstructне закінчившись, жодна з кінцевих точок недоступна.
cahen

63

Способом "Весняного завантаження" є використання CommandLineRunner. Просто додайте квасоля такого типу, і ви добре їдете. Навесні 4.1 (Boot 1.2) також SmartInitializingBeanє зворотний дзвінок після ініціалізації. А є SmartLifecycle(з весни 3).


Будь-який приклад цього? Чи можливо виконати бін після запуску програми, за допомогою командного рядка в довільний момент?
Еміліо

5
Не знаю, що ви маєте на увазі під "довільним моментом". Посібник користувача та зразки Spring Boot мають приклади використання CommandLineRunner(і новіших ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Дейв Сайер

Я виявив, що життєвий цикл є кращим варіантом виконання асинхронних завдань на стадіях запуску / зупинки програми, і я намагаюся виявити інші відмінності між CommandLineRunner та InitializingBeans, але нічого не можу знайти з цього приводу.
сальджуама

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

    }
}

Ідеально підходить до весняного черевика. Але метод run () викликався двічі при застосуванні ApplicationScope для класу. Тож метод PostConstruct із вищезазначеним працював краще.
Сем

26

ApplicationReadyEventдійсно корисний лише в тому випадку, якщо завдання, яке ви хочете виконати, не є вимогою до правильної роботи сервера. Початок завдання асинхронізації відстежувати щось за змінами - хороший приклад.

Якщо, однак, ваш сервер перебуває у стані "не готовий" до того, як завдання не буде виконано, тоді краще його реалізувати, SmartInitializingSingletonоскільки ви отримаєте зворотний виклик до того, як ваш REST-порт буде відкритий і ваш сервер відкритий для бізнесу.

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


Це має бути обрана відповідь. Як вказує @Andy, SmartInitializingSingleton викликається безпосередньо перед відкриттям портів.
Шрікант

24

З конфігурацією пружини:

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

12

Використовуйте SmartInitializingSingletonквасолю навесні> 4.1

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

}

В якості альтернативи CommandLineRunnerможе бути реалізований боб або анотація методу бобів за допомогою @PostConstruct.


Чи можу я вимагати залежності від автоматичного з'єднання всередині цього методу? Я хотів би встановити Профілі
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 
    }
}

6

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

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}

Помістіть його у клас додатка для весняного завантаження не випадковим чином@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. Використання біна бігу командного рядка

@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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.