Запуск данных настройки при запуске весной

Запуск данных настройки при запуске весной

1. Вступление

В этой статье мы сосредоточимся на том, какrun logic at the startup of a Spring application.

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

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

Некоторые из наиболее полезных конфигов для приложения Spring Boot.

Read more

Spring Boot: настройка основного класса

Узнайте, как настроить основной класс приложения Spring Boot в Maven и Gradle.

Read more

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

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

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

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

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

@Component
public class InvalidInitExampleBean {

    @Autowired
    private Environment env;

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

Здесь мы пытаемся получить доступ к полюautowired в конструкторе. Когда вызывается конструктор, bean-компонент Spring еще не полностью инициализирован. Это проблематично, потому чтоcalling not yet initialized fields will of course result in NullPointerExceptions.

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

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

Аннотацию Javax@PostConstruct можно использовать для аннотирования метода, который должен быть запущенonce immediately after the bean’s initialization. Имейте в виду, что аннотированный метод будет выполняться 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. ApplicationListener

Этот подход можно использовать дляrunning logic after the Spring context has been initialized, поэтому мы не фокусируемся на каком-либо конкретном bean-компоненте, а ждем, пока все они инициализируются.

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

@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

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

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

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:

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

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


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

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

@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. Пружинный ботинокCommandLineRunner

Spring boot предоставляет интерфейсCommanLineRunner с методом обратного вызова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++;
    }
}

Полный исходный код можно найти наGithub.

Note: как упоминалось вdocumentation, несколько bean-компонентовCommandLineRunner могут быть определены в одном контексте приложения и могут быть упорядочены с использованием интерфейса@Ordered или аннотации@Order .

2.7. Пружинный ботинокApplicationRunner

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

ИнтерфейсApplicationArguments имеет методы для получения значений аргументов, которые являются параметрами и значениями простых аргументов. Аргумент с префиксом - - это дополнительный параметр.

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

@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++;
    }
}

Полный исходный код можно найти наGithub.

3. Комбинирующие механизмы

Для достижения полного контроля над вашими bean-компонентами вы можете объединить перечисленные выше механизмы.

Порядок исполнения следующий:

  1. Конструктор

  2. аннотированные методы@PostConstruct

  3. методafterPropertiesSet() InitializingBean

  4. метод инициализации, указанный какinit-method в XML

Давайте создадим bean-компонент Spring, сочетающий в себе все механизмы:

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