Cuando trabajamos con Spring Framework, una de las primeras cosas que aprendemos es que los beans por defecto son singleton. Es decir, Spring crea una única instancia de cada bean y la reutiliza a lo largo de toda la aplicación. Ojo aca, no es igual que el patron singleton, porque el patron singleton es una instancia por clase. Spring realiza una instancia por bean, pero varios beans pueden ser de la misma clase.
Pero de igual manera nos podemos preguntar ¿No podría causar problemas si múltiples hilos usan el mismo objeto?
Veamos por qué no, y en qué casos sí.
Cuando marcamos una clase con @Component, @Service, @Repository, etc., sin indicar un @Scope, Spring crea una única instancia de esa clase cuando arranca el contexto, y luego la reutiliza para inyectarla donde haga falta.
@Service
public class MiServicio {
public void hacerAlgo() {
// lógica
}
}
Este bean se compartirá entre todas las partes de la aplicación que lo necesiten.
¿Y si lo usan varios hilos?
Acá es donde entra el concepto de thread safety. Si el bean no guarda estado mutable (es stateless), no hay ningún problema. Puede ser accedido por múltiples hilos al mismo tiempo sin consecuencias.
Pero si el bean mantiene estado mutable (por ejemplo, una variable de instancia que se modifica en cada método), entonces puede haber condiciones de carrera, errores y comportamiento impredecible.
Veamos un ejemplo peligroso:
@Component
public class ContadorCompartido {
private int contador = 0;
public void incrementar() {
contador++;
}
public int getContador() {
return contador;
}
}
Este bean no es thread-safe: si lo usan múltiples hilos al mismo tiempo, el contador puede tener resultados inesperados.
Otra pregunta puede ser ¿Spring crea múltiples instancias si hay mucha carga?
No. Este es un mito común. Spring no crea múltiples instancias de un bean singleton automáticamente bajo carga. La única forma en que podrías tener más de una instancia es:
- Si usamos un @Scope("prototype"), @RequestScope, etc.
- Si instanciás manualmente objetos sin pasar por el contenedor de Spring (lo cual rompe la inyección de dependencias).
- O si usás proxies o mecanismos especiales para aislar contexto por request, como ocurre con algunos beans en entornos web.
Podemos concluir que :
- Si tu bean necesita guardar estado por usuario o por request, no lo hagas singleton. Usá un scope adecuado.
- Si tu bean puede ser stateless, mantenelo así. Es más simple, más eficiente y seguro en entornos multihilo.
- Si el bean debe tener estado compartido, usá sincronización o mecanismos thread-safe como AtomicInteger, ConcurrentHashMap, etc.
En Spring, los beans singleton son una gran herramienta para reutilización de lógica y eficiencia de memoria. Pero es tu responsabilidad asegurarte de que no mantengan estado mutable que pueda generar conflictos en concurrencia.