Ръководство за стартиране на логика при стартиране през пролетта

1. Въведение

В тази статия ще се съсредоточим върху това как да стартираме логика при стартиране на приложение Spring .

2. Стартиране на Logic при стартиране

Изпълнението на логиката по време на / след стартирането на пролетното приложение е често срещан сценарий, но такъв, който причинява множество проблеми.

За да се възползваме от Inverse of Control, естествено трябва да се откажем от частичния контрол върху потока на приложението към контейнера - поради което инстанцирането, логиката на настройка при стартиране и т.н. се нуждае от специално внимание.

Не можем просто да включим нашата логика в конструкторите на зърната или методите за извикване след инстанциране на който и да е обект; ние просто не контролираме по време на тези процеси.

Нека да разгледаме примера от реалния живот:

@Component public class InvalidInitExampleBean { @Autowired private Environment env; public InvalidInitExampleBean() { env.getActiveProfiles(); } }

Тук се опитваме да получим достъп до автоматично свързано поле в конструктора. Когато се извика конструкторът, Spring bean все още не е напълно инициализиран. Това е проблематично, тъй като извикването на още не инициализирани полета, разбира се, ще доведе до NullPointerException s .

Пролетта ни дава няколко начина за управление на тази ситуация.

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

Анотацията @PostConstruct на Javax може да се използва за анотиране на метод, който трябва да се изпълни веднъж веднага след инициализирането на боб . Имайте предвид, че анотираният метод ще бъде изпълнен до 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())); } }

В примера по-горе можете да видите, че околната среда инстанция е безопасно инжектиран и след това се нарича в @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 атрибут Initmethod

В initMethod Имотът може да се използва за изпълнение на метод след инициализация на Бийн.

Ето как изглежда боб:

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

Пролетното зареждане осигурява интерфейс CommandLineRunner с метод за обратно извикване () , който може да бъде извикан при стартиране на приложението, след като е създаден контекстът на пролетното приложение.

Нека разгледаме един пример:

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

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

За да постигнете пълен контрол над вашите зърна, може да искате да комбинирате горните механизми заедно.

Редът на изпълнение е както следва:

  1. Конструкторът
  2. на @PostConstruct анотирани методи
  3. на InitializingBean на afterPropertiesSet () метод
  4. методът за инициализация, посочен като 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.