💻 Exemplos: Capítulo 02: Injeção de Dependências (@Autowired, @Service, @Repository) e Scopes
Especialização em Backend com Java & Spring Boot • Demonstrações Práticas Compiláveis
💻 Código de Exemplo 01 — Desambiguação de Beans com @Qualifier e Injeção por Construtor
package com.empresa.api.notificacao;
public interface NotificadorService {
void enviar(String destinatario, String mensagem);
}
package com.empresa.api.notificacao;
import org.springframework.stereotype.Service;
@Service("emailNotificador")
public class EmailNotificadorService implements NotificadorService {
@Override
public void enviar(String destinatario, String mensagem) {
System.out.println("[EMAIL] Para " + destinatario + ": " + mensagem);
}
}
package com.empresa.api.notificacao;
import org.springframework.stereotype.Service;
@Service("smsNotificador")
public class SmsNotificadorService implements NotificadorService {
@Override
public void enviar(String destinatario, String mensagem) {
System.out.println("[SMS] Para " + destinatario + ": " + mensagem);
}
}
package com.empresa.api.pedido;
import com.empresa.api.notificacao.NotificadorService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class PedidoService {
private final NotificadorService notificador;
public PedidoService(@Qualifier("smsNotificador") NotificadorService notificador) {
this.notificador = notificador;
}
public void finalizarPedido(Long id, String contatoCliente) {
notificador.enviar(contatoCliente, "Pedido " + id + " confirmado!");
}
}
💻 Código de Exemplo 02 — Bean Scope Prototype vs Singleton
package com.empresa.api.pedido;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class ContextoDeCalculoPedido {
private double totalAcumulado;
public void somar(double valor) {
this.totalAcumulado += valor;
}
public double getTotalAcumulado() {
return totalAcumulado;
}
}
package com.empresa.api.pedido;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;
@Service
public class CalculadoraPedidoService {
// ObjectProvider garante uma NOVA instância prototype a cada chamada,
// mesmo estando injetado dentro de um Service singleton.
private final ObjectProvider<ContextoDeCalculoPedido> contextoProvider;
public CalculadoraPedidoService(ObjectProvider<ContextoDeCalculoPedido> contextoProvider) {
this.contextoProvider = contextoProvider;
}
public double calcularTotal(double... itens) {
ContextoDeCalculoPedido contexto = contextoProvider.getObject();
for (double item : itens) {
contexto.somar(item);
}
return contexto.getTotalAcumulado();
}
}
💻 Código de Exemplo 03 — Ciclo de Vida com @PostConstruct e @PreDestroy
package com.empresa.api.cache;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class CacheDeCategoriasService {
private final Map<Long, String> cache = new HashMap<>();
@PostConstruct
void carregarCache() {
cache.put(1L, "Eletrônicos");
cache.put(2L, "Livros");
System.out.println("Cache de categorias carregado com " + cache.size() + " entradas.");
}
public String buscarNome(Long id) {
return cache.getOrDefault(id, "Desconhecida");
}
@PreDestroy
void limparCache() {
cache.clear();
System.out.println("Cache de categorias liberado no shutdown da aplicação.");
}
}