Executando código ao iniciar sua classe ou aplicação Java

Não é raro o cenário onde você acaba tendo que executar código durante a inicialização de uma certa classe ou aplicação. Esse artigo apresenta algumas opções sobre como você pode conseguir fazer isso.

Executar código quando a classe é inicializada

Neste cenário, você quer executar alguma lógica quando a classe é carregada pela JRE, e você quer que essa lógica seja executada somente uma única vez, independentemente do número de instâncias daquela classe. Para isso, você pode usar um static initialization block.

Você também pode assistir o vídeo abaixo (em inglês), onde mostro passo-a-passo a criação dos exemplos e alguns detalhes a mais:

StaticBlock.java
package com.lucianomolinari.startup;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StaticBlock {

	private static final Logger LOGGER = LoggerFactory.getLogger(StaticBlock.class);
	
	static {
		LOGGER.info("Static block being initialized");
	}
	
	public static void someStaticMethod() {
		LOGGER.info("SomeStaticMethod invoked");
	}
	
	public StaticBlock() {
		LOGGER.info("Constructor being initialized");
	}
	
}

O output da classe abaixo mostra que a message é imprimida a primeira vez que a classe é carregada e inclusive isso ocorre antes da primeira instância ser criada. Como podemos ver, um static initialization block é declarado usando a palavra-chave static e então usando chaves para definir o escopo do bloco.

StaticBlockTest.java
package com.lucianomolinari.startup;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StaticBlockTest {

	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	@Test
	public void instantiateClass() {
		logger.info("Invoking static method");
		StaticBlock.someStaticMethod();
		logger.info("Instantiating class");
		new StaticBlock();
		new StaticBlock();
	}
	
}
Saída da execução do teste
[main] INFO com.lucianomolinari.startup.StaticBlockTest - Invoking static method
[main] INFO com.lucianomolinari.startup.StaticBlock - Static block being initialized
[main] INFO com.lucianomolinari.startup.StaticBlock - SomeStaticMethod invoked
[main] INFO com.lucianomolinari.startup.StaticBlockTest - Instantiating class
[main] INFO com.lucianomolinari.startup.StaticBlock - Constructor being initialized
[main] INFO com.lucianomolinari.startup.StaticBlock - Constructor being initialized

Executar código toda vez que uma instância da classe é criada

Você pode estar imaginando: “Eu posso fazer isso usando o construtor da classe, certo?”. Sim, você obviamente pode. Porém, existe uma outra maneira que você deve conhecer: Initialization block, que tem a mesma idéia do static initializer block, mas nesse caso o código é executado toda vez uma instância é criada, antes da execução do código do construtor. Na verdade, o código de um de um bloco de inicialização é copiado para dentro de todos os construtores pelo compilador, então é uma forma simple de compartilhar código sem ter que explicitamente invocá-lo de todos os construtores.

InitializationBlock.java
package com.lucianomolinari.startup;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class InitializationBlock {

	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	{
		logger.info("Initialization block being invoked");
	}
	
	public InitializationBlock() {
		logger.info("Default constructor");
	}
	
	public InitializationBlock(String message) {
		logger.info("Constructor with string {}", message);
	}
	
}

Um bloco de inicialização é definido usando somente as chaves. É bem similar ao bloco de inicialização estático, com exceção da palavra-chave static.

InitializationBlockTest.java
package com.lucianomolinari.startup;

import org.junit.Test;

public class InitializationBlockTest {

	@Test
	public void instantiateClass() {
		new InitializationBlock();
		new InitializationBlock("Hello world");
	}
	
}
Saída da execução do teste
[main] INFO com.lucianomolinari.startup.InitializationBlock - Initialization block being invoked
[main] INFO com.lucianomolinari.startup.InitializationBlock - Default constructor
[main] INFO com.lucianomolinari.startup.InitializationBlock - Initialization block being invoked
[main] INFO com.lucianomolinari.startup.InitializationBlock - Constructor with string Hello world

Como você pode ver, a mensagem é exibida toda vez que uma instância da classe é criada, antes do código do construtor. É o mesmo comportamento que adicionar o código como parte dos seus construtores.

Executando código quando uma aplicação JEE é inicializada

As abordagens exibidas acima funcionam muito bem nos casos em que você tem algum código para ser executado quando uma classe é inicializada/instanciada. No entanto, em muitos casos você tem uma aplicação enterprise/web e você quer executar algum código assim que a aplicação é implantada. Para esses cenários, você precisa de diferentes formas de executar código de inicialização, e o Java EE fornece algumas maneiras de se fazer isso.

Servlet Context Listener

O primeiro jeito é criar um Servlet Context Listener e colocar a lógica dentro do método contextInitialized(). Esse tipo de listener é ativado assim que sua aplicação é implantada e então o método contextInitialized() é invocado pelo container.Veja abaixo um exemplo dessa abordagem.

InitializerListener.java
package com.lucianomolinari.startup;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebListener
public class InitializerListener implements ServletContextListener {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	public void contextInitialized(ServletContextEvent event) {
		logger.info("--> Servlet listener invoked");
	}

	public void contextDestroyed(ServletContextEvent event) {
	}

}

Servlet init method

A Servlet lifecycle specification fala que apenas uma instância de um Servlet é criada e então o método init() é invocado. No entanto, por padrão o Servlet só é criado na primeira vez que ele é invocado, mas é possível mudar esse comportamento para eager inicialização usando o atributo loadOnStartup, como exibido abaixo.

InitializerServlet.java
package com.lucianomolinari.startup;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet(loadOnStartup = 1)
public class InitializerServlet extends HttpServlet {
	private static final long serialVersionUID = 583565687437382094L;
	
	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	@Override
	public void init() throws ServletException {
		logger.info("--> Servlet initialized");
	}
	
}

Singleton EJB

Se você está executando sua aplicação em um container JEE, também é possível criar um
Singleton EJB e então usar as anotações Startup e PostConstruct. A anotação Startup vai fazer com que seu EJB seja criado assim que a aplicação é implantada e, consequentemente, o método anotado com PostConstruct será invocado.

InitializerEJB.java
package com.lucianomolinari.startup;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
@Startup
public class InitializerEJB {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	@PostConstruct
	public void init() {
		logger.info("--> EJB being initialized");
	}

}

Conclusão

O objetivo desse artigo foi mostrar alguma opções de como executar código de inicialização para uma classe/aplicação. Espero que seja útil pra você.


Quer aprender muito mais? Não deixe de ver meu curso Construa uma aplicação do zero com JEE 7, Java 8 e Wildfly.

Esta entrada foi publicada em Java EE com as etiquetas , . ligação permanente.

2 respostas a Executando código ao iniciar sua classe ou aplicação Java

  1. Egerton diz:

    Muito Obrigado!

  2. Obrigado pelo dica.

Deixe um comentário