Gids voor het uitvoeren van logica bij het opstarten in het voorjaar

1. Inleiding

In dit artikel zullen we ons concentreren op hoe voer logica uit bij het opstarten van een Spring-applicatie.

2. Logica uitvoeren bij opstarten

Logica uitvoeren tijdens / na het opstarten van de Spring-applicatie is een veelvoorkomend scenario, maar een scenario dat meerdere problemen veroorzaakt.

Om te profiteren van Inverse of Control, moeten we natuurlijk afstand doen van gedeeltelijke controle over de stroom van de applicatie naar de container - daarom hebben instantiatie, setup-logica bij het opstarten, enz. Speciale aandacht nodig.

We kunnen onze logica niet simpelweg opnemen in de constructors van de bonen of methoden aanroepen na instantiatie van een object; tijdens die processen hebben we simpelweg geen controle.

Laten we eens kijken naar het echte voorbeeld:

@Component openbare klasse InvalidInitExampleBean {@Autowired private Environment env; openbare InvalidInitExampleBean () {env.getActiveProfiles (); }}

Hier proberen we toegang te krijgen tot een automatisch bedraad veld in de constructor. Wanneer de constructor wordt aangeroepen, is de Spring bean nog niet volledig geïnitialiseerd. Dit is problematisch omdat het aanroepen van nog niet geïnitialiseerde velden zal natuurlijk resulteren in NullPointerExceptions.

De lente biedt ons een aantal manieren om met deze situatie om te gaan.

2.1. De @PostConstruct Annotatie

Javax's @PostConstruct annotatie kan worden gebruikt voor het annoteren van een methode die moet worden uitgevoerd eenmaal onmiddellijk na de initialisatie van de boon. Houd er rekening mee dat de geannoteerde methode door Spring wordt uitgevoerd, zelfs als er niets te injecteren is.

Hier is @PostConstruct in actie:

@Component openbare klasse PostConstructExampleBean {privé statische laatste Logger LOG = Logger.getLogger (PostConstructExampleBean.class); @Autowired private omgeving omgeving; @PostConstruct public void init () {LOG.info (Arrays.asList (environment.getDefaultProfiles ())); }}

In het bovenstaande voorbeeld kun je zien dat de Milieu instantie is veilig geïnjecteerd en vervolgens opgeroepen in de @PostConstruct geannoteerde methode zonder een NullPointerException.

2.2. De Initialiseren Bean Koppel

De Initialiseren Bean benadering werkt ongeveer hetzelfde als de vorige. In plaats van een methode te annoteren, moet u het Initialiseren Bean interface en de afterPropertiesSet () methode.

Hier ziet u het vorige voorbeeld geïmplementeerd met behulp van de Initialiseren Bean koppel:

@Component openbare klasse InitializingBeanExampleBean implementeert InitializingBean {privé statische laatste Logger LOG = Logger.getLogger (InitializingBeanExampleBean.class); @Autowired private omgeving omgeving; @Override public void afterPropertiesSet () gooit uitzondering {LOG.info (Arrays.asList (environment.getDefaultProfiles ())); }}

2.3. Een ApplicationListener

Deze benadering kan worden gebruikt voor logica uitvoeren nadat de Spring-context is geïnitialiseerd, dus we concentreren ons niet op een bepaalde boon, maar wachten tot ze allemaal zijn geïnitialiseerd.

Om dit te bereiken, moet u een boon maken die de ApplicationListener koppel:

@Component openbare klasse StartupApplicationListenerExample implementeert ApplicationListener {privé statische laatste Logger LOG = Logger.getLogger (StartupApplicationListenerExample.class); openbare statische int-teller; @Override public void onApplicationEvent (ContextRefreshedEvent-gebeurtenis) {LOG.info ("Incrementteller"); tegen ++; }} 

Dezelfde resultaten kunnen worden bereikt door de nieuw geïntroduceerde @EventListener annotatie:

@Component openbare klasse EventListenerExampleBean {privé statische laatste Logger LOG = Logger.getLogger (EventListenerExampleBean.class); openbare statische int-teller; @EventListener public void onApplicationEvent (ContextRefreshedEvent-gebeurtenis) {LOG.info ("Incrementteller"); tegen ++; }}

In dit voorbeeld hebben we gekozen voor de ContextRefreshedEvent. Zorg ervoor dat u een geschikt evenement kiest dat bij u past.

2.4. De @Boon Initmethod-kenmerk

De initMethod eigenschap kan worden gebruikt om een ​​methode uit te voeren na de initialisatie van een boon.

Hier is hoe een boon eruit ziet:

openbare klasse InitMethodExampleBean {privé statische laatste Logger LOG = Logger.getLogger (InitMethodExampleBean.class); @Autowired private omgeving omgeving; openbare void init () {LOG.info (Arrays.asList (environment.getDefaultProfiles ())); }}

U kunt zien dat er geen speciale interfaces zijn geïmplementeerd of dat er geen speciale annotaties zijn gebruikt.

Vervolgens kunnen we de boon definiëren met de @Boon annotatie:

@Bean (initMethod = "init") openbaar InitMethodExampleBean initMethodExampleBean () {retourneer nieuwe InitMethodExampleBean (); }

En dit is hoe een bean-definitie eruitziet in een XML-configuratie:

2.5. Constructor-injectie

Als u velden injecteert met Constructor Injection, kunt u eenvoudig uw logica in een constructor opnemen:

@Component openbare klasse LogicInConstructorExampleBean {privé statische laatste Logger LOG = Logger.getLogger (LogicInConstructorExampleBean.class); privé eindomgeving omgeving; @Autowired openbare LogicInConstructorExampleBean (omgevingsomgeving) {this.environment = environment; LOG.info (Arrays.asList (environment.getDefaultProfiles ())); }}

2.6. Spring Boot CommandLineRunner

Spring boot biedt een CommandLineRunner interface met een callback rennen() methode die kan worden aangeroepen bij het opstarten van de applicatie nadat de Spring-toepassingscontext is geïnstantieerd.

Laten we naar een voorbeeld kijken:

@Component openbare klasse CommandLineAppStartupRunner implementeert CommandLineRunner {privé statische laatste Logger LOG = LoggerFactory.getLogger (CommandLineAppStartupRunner.class); openbare statische int-teller; @Override public void run (String ... args) gooit uitzondering {LOG.info ("Increment counter"); tegen ++; }}

Opmerking: Zoals vermeld in de documentatie, multiple CommandLineRunner bonen kunnen worden gedefinieerd binnen dezelfde toepassingscontext en kunnen worden besteld met de @Besteld interface of @Bestellen annotatie.

2.7. Spring Boot ToepassingRunner

Gelijkwaardig aan CommandLineRunner, Spring boot biedt ook een ToepassingRunner interface met een rennen() methode die moet worden aangeroepen bij het opstarten van de toepassing. Echter in plaats van rauw Draad argumenten doorgegeven aan de callback-methode, hebben we een instantie van de ApplicationArguments klasse.

De ApplicationArguments interface heeft methoden om argumentwaarden te krijgen die opties en gewone argumentwaarden zijn. Een argument dat wordt voorafgegaan door - - is een optieargument.

Laten we naar een voorbeeld kijken:

@Component openbare klasse AppStartupRunner implementeert ApplicationRunner {privé statische laatste Logger LOG = LoggerFactory.getLogger (AppStartupRunner.class); openbare statische int-teller; @Override public void run (ApplicationArguments args) genereert Uitzondering {LOG.info ("Applicatie gestart met optienamen: {}", args.getOptionNames ()); LOG.info ("Verhogende teller"); tegen ++; }}

3. Combinatie van mechanismen

Om volledige controle over uw bonen te krijgen, wilt u misschien de bovenstaande mechanismen combineren.

De volgorde van uitvoering is als volgt:

  1. De constructeur
  2. de @PostConstruct geannoteerde methoden
  3. de InitializingBean's afterPropertiesSet () methode
  4. de initialisatiemethode gespecificeerd als init-methode in XML

Laten we een springboon maken die alle mechanismen combineert:

@Component @Scope (waarde = "prototype") openbare klasse AllStrategiesExampleBean implementeert InitializingBean {privé statische laatste Logger LOG = Logger.getLogger (AllStrategiesExampleBean.class); openbaar AllStrategiesExampleBean () {LOG.info ("Constructor"); } @Override public void afterPropertiesSet () gooit uitzondering {LOG.info ("InitializingBean"); } @PostConstruct openbare leegte postConstruct () {LOG.info ("PostConstruct"); } public void init () {LOG.info ("init-methode"); }}

Als u deze bean probeert te instantiëren, kunt u logboeken zien die overeenkomen met de hierboven gespecificeerde volgorde:

[main] INFO o.b.startup.AllStrategiesExampleBean - Constructor [main] INFO o.b.startup.AllStrategiesExampleBean - PostConstruct [main] INFO o.b.startup.AllStrategiesExampleBean - InitializingBean [main] INFO o.ExampleBean-start-up.

4. Conclusie

In dit artikel hebben we meerdere manieren geïllustreerd om logica uit te voeren bij het opstarten van de Spring-applicatie.

Codevoorbeelden zijn te vinden op GitHub.