Olá programador, aqui é o Gui, e hoje você vai entender o que é uma inicialização lenta no Framework Spring. Primeiro, vamos começar com o básico: o que é Lazy Initialization? Bem, imagine que você está em casa e tem várias tarefas para fazer ao longo do dia, mas você decide começar apenas quando realmente precisar.
Talvez você precise arrumar a cama só quando for dormir, ou lavar a louça só quando não tiver mais pratos limpos. Lazy Initialization é mais ou menos isso, mas no mundo da programação.
Em termos técnicos, Lazy Initialization é uma estratégia de inicialização atrasada, onde um objeto ou recurso só é carregado quando realmente é necessário, e não no início da aplicação. Isso ajuda a economizar memória e a melhorar o desempenho do sistema, especialmente em aplicações grandes e complexas.
Como ativar Lazy Initialization no Spring Boot?
No seu arquivo application.properties adicione a seguinte linha:
spring.main.lazy-initialization=true
Ou se estiver utilizando application.yml:
spring: main: lazy-initialization: true
Isso é tudo! A partir daí, o Spring Boot vai adotar essa abordagem de inicialização preguiçosa por padrão, porém ainda precisamos especificar quais objetos ele deve atrasar, veremos logo abaixo como realizar este procedimento.
Exemplos Práticos
Agora que você já entendeu o básico, vamos ver um exemplo prático para deixar tudo ainda mais claro.
Exemplo 1: Sem Lazy Initialization
Suponha que você tenha uma aplicação simples que se conecta a um banco de dados e busca dados de usuários. Sem Lazy Initialization, o Spring Boot vai inicializar todos os beans no startup, incluindo a conexão com o banco de dados, mesmo que você nem sempre precise dela.
package br.com.virandoprogramador.lazyinitialization.service; package br.com.virandoprogramador.lazyinitialization.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserService { @Autowired private UserRepository userRepository; public List<User> getAllUsers() { return userRepository.findAll(); } }
Nesse exemplo, o UserRepository será inicializado na partida da aplicação, mesmo que o método getAllUsers() nunca seja chamado.
Exemplo 2: Com Lazy Initialization
Agora, vamos adicionar o Lazy Initialization para ver como isso muda o comportamento.
package br.com.virandoprogramador.lazyinitialization.service; package br.com.virandoprogramador.lazyinitialization.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.context.annotation.Lazy; import java.util.List; @Service public class UserService { @Autowired @Lazy private UserRepository userRepository; public List<User> getAllUsers() { return userRepository.findAll(); } }
Observe que estamos importante a anotação @Lazy do pacote: import org.springframework.context.annotation.Lazy, indicando que possui uma configuração interna do Framework para trabalhar com inicializações lentas.
Adicionamos a anotação @Lazy no UserRepository. Agora, o UserRepository só será inicializado quando o método getAllUsers() for chamado. Se esse método nunca for usado, o bean UserRepository nunca será carregado, economizando recursos.
Exemplo 3: Serviços com Múltiplas Dependências
Vamos imaginar que você está desenvolvendo um sistema de gerenciamento de pedidos, onde cada pedido passa por várias etapas, como validação, processamento de pagamento, e notificação. Cada uma dessas etapas pode ter seus próprios serviços, e alguns deles podem ser custosos em termos de recursos.
Separei um exemplo bem comum de como você pode implementar na sua camada de Service:
package br.com.virandoprogramador.lazyinitialization.service; package br.com.virandoprogramador.lazyinitialization.service.ValidacaoService; package br.com.virandoprogramador.lazyinitialization.service.PagamentoService; package br.com.virandoprogramador.lazyinitialization.service.NotificacaoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.context.annotation.Lazy; @Service public class PedidoService { @Autowired @Lazy private ValidacaoService validacaoService; @Autowired @Lazy private PagamentoService pagamentoService; @Autowired @Lazy private NotificacaoService notificacaoService; public void processaPedido(Pedido pedido) { validacaoService.valida(pedido); pagamentoService.processaPagamento(pedido); notificacaoService.enviaNotificacao(pedido); } }
Explicação:
ValidacaoService, PagamentoService, e NotificacaoService são serviços que só serão inicializados quando o método processaPedido() for chamado.Se, por exemplo, sua aplicação iniciar sem precisar processar pedidos imediatamente, esses serviços não serão carregados, economizando memória e tempo de inicialização.
Quando não usar Lazy Initialization?
Primeiro, é importante entender que Lazy Initialization, por natureza, introduz uma certa “preguiça” no carregamento dos componentes. Isso significa que, ao invés de termos tudo pronto logo na inicialização da aplicação, alguns elementos vão sendo carregados ao longo do tempo, conforme são requisitados.
Em muitas situações, isso é ótimo, mas pode se tornar problemático quando a aplicação precisa de previsibilidade ou quando o tempo de resposta deve ser de imediato.
Uma das situações em que essa técnica pode ser problemática é em aplicações onde a previsibilidade do comportamento é essencial. Imagine um sistema em produção onde você precisa garantir que todos os componentes estejam prontos e funcionando assim que a aplicação subir. Se alguns desses componentes forem inicializados de forma preguiçosa, você pode acabar enfrentando comportamentos inesperados, especialmente em momentos críticos de execução.
Imagine também que você tem um serviço com uma alta demanda que só será inicializado quando chamado pela primeira vez. Se houver algum problema nessa inicialização tardia, ele só será descoberto no meio do processamento, o que pode causar falhas em cascata e afetar a experiência do usuário.
Encerramento sobre o assunto
Esses exemplos demonstram como o Lazy pode ser aplicado em cenários mais complexos para otimizar o uso de recursos e melhorar o desempenho da aplicação. Ele é particularmente útil quando se trata de inicialização de serviços caros, manipulação de transações, e integração com múltiplos sistemas externos.
Espero que esses exemplos tenham ajudado a entender melhor como e quando usar Lazy Initialization no Spring Boot. Se você tiver alguma dúvida, pode comentar abaixo que irei responder o mais breve possivel =).