21‐Lazy‐Initialization - JuhMaran/Java-with-Spring-Boot GitHub Wiki
49. Lazy Initialization - Visão Geral
🔄 Inicialização dos Beans
- Por padrão, quando sua aplicação Spring inicia, todos os beans são criados imediatamente.
- Isso inclui todos os beans anotados com
@Component,@Service,@Repository,@Controller, etc. - O Spring cria uma instância de cada bean e os deixa prontos para uso.
🛠 Diagnóstico: adicionando println no construtor
@Component
public class CricketCoach implements Coach {
public CricketCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
}
getClass().getSimpleName()imprime o nome da classe, útil para ver quais beans estão sendo instanciados.
▶ Quando iniciamos a aplicação:
In constructor: BaseballCoach
In constructor: CricketCoach
In constructor: TennisCoach
In constructor: TrackCoach
- Isso mostra que todos os beans são criados na inicialização, mesmo que não sejam usados ainda.
💤 O que é Lazy Initialization?
- Lazy Initialization significa que o bean só será criado quando for realmente necessário.
- Um bean só é inicializado se:
- For usado em uma injeção de dependência.
- For solicitado diretamente no código.
🔧 Usando @Lazy em uma classe
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Lazy
@Component
public class TrackCoach implements Coach {
public TrackCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
}
✅ Injetando apenas o CricketCoach
@RestController
public class DemoController {
private Coach myCoach;
@Autowired
public DemoController(@Qualifier(value = "cricketCoach") Coach myCoach) {
this.myCoach = myCoach;
}
}
- Nesse exemplo, o
TrackCoachnão será inicializado, pois não está sendo injetado.
Saída esperada:
In constructor: BaseballCoach
In constructor: CricketCoach
In constructor: TennisCoach
🧩 E os outros beans?
- Se quiser aplicar Lazy Initialization a outros beans, será necessário adicionar
@Lazyem cada classe. - Isso pode se tornar trabalhoso em aplicações grandes.
🌐 Configuração Global com application.properties
Para ativar Lazy Initialization para todos os beans, use:
spring.main.lazy-initialization=true
- Agora, nenhum bean será criado até que seja realmente necessário.
- Até mesmo o
DemoControllersó será criado quando sua rota for acessada.
🖨 Adicionando println no DemoController
@Component
public class CricketCoach implements Coach {
public CricketCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
}
@RestController
public class DemoController {
private Coach myCoach;
@Autowired
public DemoController(@Qualifier(value = "cricketCoach") Coach myCoach) {
System.out.println("In constructor: " + getClass().getSimpleName());
this.myCoach = myCoach;
}
}
🔁 Como funciona o carregamento?
- O usuário acessa o endpoint REST
/dailywork. - O Spring identifica que precisa do
DemoController. - Para criar o
DemoController, ele precisa doCricketCoach. - Então o Spring cria primeiro o
CricketCoach, depois oDemoController.
Saída esperada:
In constructor: CricketCoach
In constructor: DemoController
⚖️ Vantagens e Desvantagens
✅ Vantagens
- Cria os objetos somente quando são usados.
- Pode melhorar o tempo de inicialização da aplicação, especialmente se ela tiver muitos beans.
⚠️ Desvantagens
- Beans como
@RestControllernão serão criados até serem chamados pela primeira vez. - Problemas de configuração só serão detectados no momento da criação, e não na inicialização.
- É preciso garantir que o sistema tenha memória suficiente para os beans quando forem carregados.
🧠 Dica final
- Lazy Initialization está desativado por padrão.
- Antes de ativá-lo, teste e analise sua aplicação.
- Evite a otimização prematura — só use se realmente trouxer benefícios.
50. Lazy Initialization - Codificação - Parte 1
Etapas desta aula:
- Remover a anotação
@Primary - Utilizar
@Qualifierpara definir qual implementação será injetada - Adicionar prints nos construtores para observar a criação dos objetos
Exemplo de código:
@RestController
public class DemoController {
private Coach myCoach;
@Autowired
public DemoController(@Qualifier("cricketCoach") Coach myCoach) {
System.out.println("In constructor: " + getClass().getSimpleName());
this.myCoach = myCoach;
}
@GetMapping("/dailyworkout")
public String getDailyWorkout() {
return myCoach.getDailyWorkout();
}
}
@Component
public class BaseballCoach implements Coach {
public BaseballCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
@Override
public String getDailyWorkout() {
return "Spend 30 minutes in batting practice";
}
}
@Component
public class CricketCoach implements Coach {
public CricketCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
@Override
public String getDailyWorkout() {
return "Practice fast bowling for 15 minutes";
}
}
@Component
public class TennisCoach implements Coach {
public TennisCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
@Override
public String getDailyWorkout() {
return "Practice your backhand volley";
}
}
@Component
public class TrackCoach implements Coach {
public TrackCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
@Override
public String getDailyWorkout() {
return "Run a hard 5k!";
}
}
Resultado da execução:
Quando executamos o projeto e acessamos o endpoint http://localhost:8080/dailyworkout, o Spring cria e carrega todas as classes marcadas com @Component, mesmo que nem todas estejam sendo utilizadas.
O log mostra a seguinte saída:
In constructor: BaseballCoach
In constructor: CricketCoach
In constructor: TennisCoach
In constructor: TrackCoach
In constructor: DemoController
51. Lazy Initialization - Codificação - Parte 2
Tornando uma classe "preguiçosa" com @Lazy
Se queremos que um bean só seja criado quando for realmente necessário, podemos usar a anotação @Lazy.
@Lazy
@Component
public class TrackCoach implements Coach {
public TrackCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
@Override
public String getDailyWorkout() {
return "Run a hard 5k!";
}
}
Resultado após aplicar @Lazy:
Se a classe TrackCoach não está sendo usada diretamente em nenhum lugar (não é injetada), o Spring não irá instanciá-la:
In constructor: BaseballCoach
In constructor: CricketCoach
In constructor: TennisCoach
In constructor: DemoController
Ou seja, o TrackCoach não aparece no log — pois o Spring não precisou dele.
Inicialização preguiçosa global
Se quisermos que todos os beans sejam carregados somente quando forem utilizados, podemos configurar isso no arquivo application.properties:
spring.main.lazy-initialization=true
Resultado:
Com essa configuração, o Spring só cria os beans no momento exato em que forem necessários:
In constructor: CricketCoach
In constructor: DemoController
Isso acontece porque o DemoController precisa do CricketCoach, então apenas esses dois foram instanciados. Os outros beans (BaseballCoach, TennisCoach, TrackCoach) não foram carregados porque não foram utilizados.
Conclusão
- Por padrão, o Spring cria todos os beans na inicialização da aplicação.
- Com
@Lazy, podemos indicar que um bean só deve ser criado quando for realmente necessário. - Também é possível ativar a inicialização preguiçosa globalmente, com a propriedade
spring.main.lazy-initialization=true. - Isso pode melhorar o tempo de inicialização da aplicação e economizar recursos, especialmente em aplicações grandes.