Рубрики
Без рубрики

Руководство по запуску логики при запуске весной

Запуск логики при запуске приложения является распространенным сценарием. В этой статье мы рассмотрим различные способы достижения этой цели в приложении Spring.

Автор оригинала: baeldung.

1. введение

В этой статье мы сосредоточимся на том, как запустить логику при запуске приложения Spring .

Дальнейшее чтение:

Настройка веб-приложения Spring Boot

Весенняя загрузка: Настройка основного класса

2. Запуск логики при запуске

Запуск логики во время/после запуска приложения Spring-это распространенный сценарий, но он вызывает множество проблем.

Чтобы извлечь выгоду из обратного контроля, нам, естественно, необходимо отказаться от частичного контроля над потоком приложения в контейнер – вот почему создание экземпляра, логика настройки при запуске и т. Д. Требуют особого внимания.

Мы не можем просто включить нашу логику в конструктор боба или вызвать методы после создания экземпляра любого объекта; мы просто не контролируем эти процессы.

Давайте рассмотрим пример из реальной жизни:

@Component
public class InvalidInitExampleBean {

    @Autowired
    private Environment env;

    public InvalidInitExampleBean() {
        env.getActiveProfiles();
    }
}

Здесь мы пытаемся получить доступ к полю autowired в конструкторе. При вызове конструктора компонент Spring еще не полностью инициализирован. Это проблематично, потому что вызов еще не инициализированных полей, конечно, приведет к NullPointerException s .

Весна дает нам несколько способов справиться с этой ситуацией.

2.1. Аннотация @PostConstruct

Javax @PostConstruct аннотацию можно использовать для аннотирования метода, который должен быть запущен один раз сразу после инициализации компонента . Имейте в виду, что аннотированный метод будет выполняться Spring, даже если ничего не нужно вводить.

Вот @PostConstruct в действии:

@Component
public class PostConstructExampleBean {

    private static final Logger LOG 
      = Logger.getLogger(PostConstructExampleBean.class);

    @Autowired
    private Environment environment;

    @PostConstruct
    public void init() {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

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

2.2. Интерфейс InitializingBean

Подход InitializingBean работает примерно так же, как и предыдущий. Вместо аннотирования метода необходимо реализовать интерфейс InitializingBean и метод afterPropertiesSet () .

Здесь вы можете увидеть предыдущий пример, реализованный с использованием интерфейса InitializingBean :

@Component
public class InitializingBeanExampleBean implements InitializingBean {

    private static final Logger LOG 
      = Logger.getLogger(InitializingBeanExampleBean.class);

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

2.3. Список приложений

Этот подход может быть использован для выполнения логики после инициализации контекста Spring , поэтому мы не фокусируемся на каком-либо конкретном компоненте, а ждем, пока все они будут инициализированы.

Для этого вам необходимо создать компонент, реализующий интерфейс ApplicationListener :

@Component
public class StartupApplicationListenerExample implements 
  ApplicationListener {

    private static final Logger LOG 
      = Logger.getLogger(StartupApplicationListenerExample.class);

    public static int counter;

    @Override public void onApplicationEvent(ContextRefreshedEvent event) {
        LOG.info("Increment counter");
        counter++;
    }
}

Те же результаты могут быть достигнуты с помощью недавно введенной аннотации @EventListener :

@Component
public class EventListenerExampleBean {

    private static final Logger LOG 
      = Logger.getLogger(EventListenerExampleBean.class);

    public static int counter;

    @EventListener
    public void onApplicationEvent(ContextRefreshedEvent event) {
        LOG.info("Increment counter");
        counter++;
    }
}

В этом примере мы выбрали ContextRefreshedEvent. Обязательно выберите подходящее мероприятие, которое соответствует вашим потребностям.

2.4. Атрибут метода инициализации @Bean

Свойство init Method может использоваться для выполнения метода после инициализации компонента.

Вот как выглядит боб:

public class InitMethodExampleBean {

    private static final Logger LOG = Logger.getLogger(InitMethodExampleBean.class);

    @Autowired
    private Environment environment;

    public void init() {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

Вы можете заметить, что не реализовано никаких специальных интерфейсов и не используются никакие специальные аннотации.

Затем мы можем определить боб, используя аннотацию @Bean :

@Bean(initMethod="init")
public InitMethodExampleBean initMethodExampleBean() {
    return new InitMethodExampleBean();
}

И вот как выглядит определение компонента в конфигурации XML:


2.5. Инъекция конструктора

Если вы вводите поля с помощью инъекции конструктора, вы можете просто включить свою логику в конструктор:

@Component 
public class LogicInConstructorExampleBean {

    private static final Logger LOG 
      = Logger.getLogger(LogicInConstructorExampleBean.class);

    private final Environment environment;

    @Autowired
    public LogicInConstructorExampleBean(Environment environment) {
        this.environment = environment;
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

2.6. Spring Boot CommandLineRunner

Spring boot предоставляет интерфейс CommandLineRunner с обратным вызовом run () , который может быть вызван при запуске приложения после создания экземпляра контекста приложения Spring.

Давайте рассмотрим пример:

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

    public static int counter;

    @Override
    public void run(String...args) throws Exception {
        LOG.info("Increment counter");
        counter++;
    }
}

Примечание : Как упоминалось в документации , несколько компонентов CommandLineRunner могут быть определены в одном контексте приложения и могут быть упорядочены с помощью интерфейса @Ordered или аннотации @Order .

2.7. SpringBootApplication Runner

Подобно CommandLineRunner, Spring boot также предоставляет интерфейс Application Runner с методом run () , вызываемым при запуске приложения. Однако вместо необработанных аргументов String , передаваемых методу обратного вызова, у нас есть экземпляр аргументов приложения |/класса.

Интерфейс Аргументы приложения имеет методы для получения значений аргументов, которые являются параметрами и обычными значениями аргументов. Аргумент с префиксом – – является аргументом опции.

Давайте рассмотрим пример:

@Component
public class AppStartupRunner implements ApplicationRunner {
    private static final Logger LOG =
      LoggerFactory.getLogger(AppStartupRunner.class);

    public static int counter;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        LOG.info("Application started with option names : {}", 
          args.getOptionNames());
        LOG.info("Increment counter");
        counter++;
    }
}

3. Комбинирование механизмов

Чтобы получить полный контроль над своими бобами, вы можете объединить вышеперечисленные механизмы вместе.

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

  1. Конструктор
  2. @PostConstruct аннотированные методы
  3. метод InitializingBean afterPropertiesSet()
  4. метод инициализации, указанный как init-метод в XML

Давайте создадим пружинный боб, который сочетает в себе все механизмы:

@Component
@Scope(value = "prototype")
public class AllStrategiesExampleBean implements InitializingBean {

    private static final Logger LOG 
      = Logger.getLogger(AllStrategiesExampleBean.class);

    public AllStrategiesExampleBean() {
        LOG.info("Constructor");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info("InitializingBean");
    }

    @PostConstruct
    public void postConstruct() {
        LOG.info("PostConstruct");
    }

    public void init() {
        LOG.info("init-method");
    }
}

Если вы попытаетесь создать экземпляр этого компонента, вы сможете увидеть журналы, соответствующие порядку, указанному выше:

[main] INFO o.b.startup.AllStrategiesExampleBean - Constructor
[main] INFO o.b.startup.AllStrategiesExampleBean - PostConstruct
[main] INFO o.b.startup.AllStrategiesExampleBean - InitializingBean
[main] INFO o.b.startup.AllStrategiesExampleBean - init-method

4. Заключение

В этой статье мы проиллюстрировали несколько способов выполнения логики при запуске приложения Spring.

Примеры кода можно найти на GitHub .