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. Комбинирование механизмов
Чтобы получить полный контроль над своими бобами, вы можете объединить вышеперечисленные механизмы вместе.
Порядок исполнения выглядит следующим образом:
- Конструктор
- @PostConstruct аннотированные методы
- метод InitializingBean afterPropertiesSet()
- метод инициализации, указанный как 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 .