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 .