Инициализировать данные при запуске в серии статей springboot

задняя часть Spring контейнер API

предисловие

Когда мы используем springboot для сборки проекта, мы иногда сталкиваемся с необходимостью инициализировать некоторые операции при запуске проекта.Для этого требования springboot (spring) предоставляет нам следующие параметры:

  • ApplicationRunnerиCommandLineRunnerинтерфейс
  • InitializingBean, метод init и PostConstruct для инициализации Spring Bean
  • Механизм событий Spring

ApplicationRunner и CommandLineRunner

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

ApplicationRunner

Создайте класс для реализации интерфейса ApplicationRunner.

@Component
public class ApplicationRunnerTest implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner");
    }
}

Результаты запуска проекта представлены на рисунке:

application

CommandLineRunner

Для этих двух интерфейсов мы можем указать порядок вызова через аннотацию Order или с помощью интерфейса Ordered,@Order()Чем меньше значение в , тем выше приоритет

@Component
@Order(1)
public class CommandLineRunnerTest implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner...");
    }
}

Конечно, мы также можем использоватьApplicationRunnerиCommandLineRunner, первый по умолчанию выполняется перед вторым, но это не обязательно, просто используйте один

Связь и различие между ними

Как упоминалось ранее, оба интерфейса имеют метод run(), но их параметры различаются. Параметр CommandLineRunner — самый примитивный параметр без какой-либо обработки. Параметр ApplicationRunner — это ApplicationArguments, который является дальнейшим шагом к исходному параметру.

отслеживание источника

Затем мы кратко проследим исходный код, чтобы увидетьApplicationRunner(CommandLineRunner)Как это называется.

Когда Springboot запустится, он создастSpringApplicationПример, что касается того, как устроен этот пример, я не буду его здесь рассматривать, если вам интересно, вы можете перейти к исходному коду. В основном здесьApplicationRunnerкак называется, и его вызов находится вSpringApplicationЭтот экземпляр вызывает метод run.

@SpringBootApplication
public class Application {


    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Введите метод запуска

	public static ConfigurableApplicationContext run(Class<?> primarySource,
			String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}

Выполнить метод запуска SpringApplication

	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

Нажмите run() до упора, чтобы прийти сюда

context
Выяснил, что вызов ApplicationRunner на самом деле находится в методе callRunners
runer
Для CommandLineRunner или ApplicationRunner следует отметить два момента.:

  • Время выполнения всех команд CommandLineRunner/ApplicationRunner начинается после того, как ApplicationContext приложения SpringBoot полностью инициализируется и начинает работать.callRunners()Видно, что это последний метод, вызываемый внутри метода run (его можно рассматривать как последний шаг перед выполнением основного метода)
  • Пока любой CommandLineRunner/ApplicationRunner существует в ApplicationContext текущего приложения SpringBoot, он будет загружен и выполнен (независимо от того, регистрируетесь ли вы вручную или автоматически сканируете в контейнер Ioc)

InitializingBean, метод init и PostConstruct для инициализации Spring Bean

Интерфейс InitializingBean

InitializingBeanинтерфейсbeanПредоставляет способ инициализации метода, он включает толькоafterPropertiesSet()метод.

Когда Spring инициализирует bean-компонент, если bean-компонент реализуетInitializingBeanинтерфейс, метод afterPropertiesSet() не будет вызываться до тех пор, пока не будут инициализированы все свойства объекта

@Component
public class InitialingzingBeanTest implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean..");
    }
}

in

Конечно, мы можем видеть, что bean-компонент инициализации spring обязательно будет в Перед вызовом интерфейсов ApplicationRunner и CommandLineRunner.

Конечно, мы должны обратить внимание на то, что хотя использованиеinitialingBeanИнтерфейс может реализовать действие инициализации, но официал не рекомендует нам его использоватьInitializingBeanинтерфейс, поскольку он связывает ваш код с кодом Spring, официальная рекомендация — указать его в файле конфигурации bean-компонента.init-methodметод или в@Beanустановить вinit-methodАтрибуты

init

init-метод и @PostConstruct

Как упоминалось ранее, не рекомендуется использовать официальную документацию.InitializingBeanинтерфейс, но мы можем<bean>Атрибут метода init-метода элемента указывает метод работы после инициализации компонентов, либо на указанном методе @postconstruct добавлять аннотации к разработке метода, называемого после инициализации

@SpringBootApplication
public class Application {


    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @PostConstruct
    public void init() {
        System.out.println("init...");
    }
}

Для получения дополнительной информации о жизненном цикле Spring Bean обратитесь к книгам или блогам, связанным с Spring.Жизненный цикл Spring Bean

Механизм событий Spring

Механизм событий Spring на самом деле является типичным применением шаблона наблюдателя в шаблоне проектирования.Шаблон проектирования Head FirstШаблон наблюдателя определяется следующим образом:

Шаблон Observer определяет зависимость «один ко многим», которая позволяет одному или нескольким объектам-наблюдателям прослушивать объект-субъект. Таким образом, когда состояние наблюдателя изменяется, соответствующие наблюдатели должны быть уведомлены, чтобы эти наблюдатели могли обновляться автоматически.

watch

Базовые концепты

Модель Spring, управляемая событиями, состоит из трех частей.

  • событие:ApplicationEvent, унаследовано от JDKEventObject, все события должны наследовать его, т. е. наблюдаемое
  • Издатель мероприятия:ApplicationEventPublisherиApplicationEventMulticasterИнтерфейс, используя этот интерфейс, вы можете публиковать события
  • Прослушиватель событий:ApplicationListener, унаследовано от JDKEventListener, его наследуют все слушатели, которых мы называем наблюдателями, конечно, мы также можем использовать аннотации@EventListener, эффект тот же

событие

В среде Spring для событий ApplicationEvent по умолчанию предоставляется следующая поддержка:

  • ContextStartedEvent: событие, инициированное после запуска ApplicationContext.
  • ContextStoppedEvent: событие запускается после остановки ApplicationContext.
  • Событие ContextRefreshedEvent:Событие запускается после завершения инициализации или обновления ApplicationContext; (Вызывается после инициализации контейнера, поэтому мы можем использовать это событие для выполнения некоторых операций инициализации)
  • ContextClosedEvent: событие, инициированное после закрытия ApplicationContext (например, когда веб-контейнер закрывается, закрытие контейнера Spring будет автоматически запущено. Если это обычное приложение Java, вам нужно вызвать ctx.registerShutdownHook() ; регистрируем хук при закрытии виртуальной машины)
    application

Создайте класс для наследования ApplicationEvent

public class TestEvent extends ApplicationEvent {

    private static final long serialVersionUID = -376299954511699499L;
    private String message;
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public TestEvent(Object source) {
        super(source);
    }

    public void getMessage() {
        System.out.println(message);
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

Создать прослушиватель событий

Существует два способа создания слушателей: один — напрямую реализовать интерфейс ApplicationListener, а другой — использовать аннотации.@EventListener,Аннотации добавляются в метод слушателя, следующий пример является прямой реализацией интерфейса

@Component
public class ApplicationListenerTest implements ApplicationListener<TestEvent> {
    @Override
    public void onApplicationEvent(TestEvent testEvent)
    {
        testEvent.getMessage();
    }
}

выпуск события

Для публикации событий делегатом являетсяApplicationEventPublisherиApplicationEventMulticaster, реализация, обеспечиваемая системой, выглядит следующим образом

a
Интерфейс ApplicationContext наследует ApplicationEventPublisher и реализует определенный код в AbstractApplicationContext.Фактическое выполнение делегируется ApplicationEventMulticaster (которое можно рассматривать как многоадресную рассылку).

Ниже приведен тестовый пример издателя событий:

@RunWith(SpringRunner.class)
@SpringBootTest
public class EventTest {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void publishTest() {
        TestEvent testEvent = new TestEvent("");
        testEvent.setMessage("hello world");
        applicationContext.publishEvent(testEvent);
    }
}
//output:
hello world

Используйте событие ContextRefreshedEvent для инициализации

Так много предзнаменований было сделано ранее, давайте перейдем к сегодняшней теме, используем механизм событий Spring для инициализации некоторых операций, на самом деле, как упоминалось ранее, используя механизм событий SpringContextRefreshedEventсобытие инициализировано, событиеApplicationContextИнициализировать событие, называемое после завершения, мы можем использовать это событие для реализации слушателя, вonApplicationEvent()Инициализировать операцию в методе

@Component
public class ApplicationListenerTest implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("我被调用了..");
    }
}

listener

Уведомление: В традиционном проекте Spring на основе XML конфигурации будет проблема двух вызовов, то есть метод вызывается дважды.Причина в том, что в традиционном проекте Spring MVC в системе два контейнера, корневой контейнер и проект-сервлет Подконтейнер, соответствующий .xml, вызовет этот метод один раз при инициализации двух контейнеров, поэтому возникает проблема вторичного вызова, но эта проблема не существует для проектов на основе Springboot.

резюме

Выше кратко суммированы несколько схем инициализации операций при запуске Springboot, Эти методы могут удовлетворить наши потребности и использовать соответствующие схемы для конкретных сценариев. Однако CommandLineRunner или ApplicationRunner не являются исходными вещами среды Spring.Они относятся к интерфейсам расширений обратного вызова для конкретных приложений SpringBoot, поэтому их легко расширять, и они широко используются в некоторых микросервисных приложениях.

использованная литература