Запуск данных настройки при запуске весной
1. Вступление
В этой статье мы сосредоточимся на том, какrun logic at the startup of a Spring application.
Дальнейшее чтение:
Настройте веб-приложение Spring Boot
Некоторые из наиболее полезных конфигов для приложения Spring Boot.
Spring Boot: настройка основного класса
Узнайте, как настроить основной класс приложения Spring Boot в Maven и Gradle.
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-компонентами вы можете объединить перечисленные выше механизмы.
Порядок исполнения следующий:
-
Конструктор
-
аннотированные методы@PostConstruct
-
методafterPropertiesSet() InitializingBean
-
метод инициализации, указанный как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.