El patrón Singleton es un patrón de diseño que garantiza que una clase tenga una única instancia y proporciona un punto de acceso global a esa instancia. Este patrón es útil cuando solo debe existir una única instancia de una clase en toda la aplicación, como en el caso de la configuración de una aplicación o una conexión a la base de datos, o por ejemplo un servicio único en Spring Boot.
Multihilo #
Es importante notar que, en un entorno multihilo, cada thread podría obtener una nueva instancia. Para asegurarse de que la operación sea thread safe, se deberá utilizar «syncronized».
Ejemplo de Singleton en Java #
En general, hay 3 condiciones:
Se puede inicializar de dos maneras, Lazy o Eager.
- Hacer privado el constructor
- Asegurarse de que la variable con la instancia sea static
- Proveer un método public static
A continuación un ejemplo de cada una.
Singleton con Lazy Initialization #
En este caso, la instancia de la clase Singleton se crea solo cuando es requerida, es decir, cuando se llama al método getInstance() por primera vez. Esto puede ser útil si la creación de la instancia es costosa en términos de recursos o tiempo.
public class SingletonLazy {
// Instancia única de la clase, inicialmente nula
private static SingletonLazy instancia;
// Constructor privado para evitar instanciación desde fuera
private SingletonLazy() {
// Inicialización de recursos si es necesario
}
// Método público para obtener la instancia única de la clase
public static SingletonLazy getInstance() {
if (instancia == null) {
instancia = new SingletonLazy();
}
return instancia;
}
// Método de ejemplo en la clase Singleton
public void mostrarMensaje() {
System.out.println("Hola desde Singleton con Lazy Initialization!");
}
}
Uso del Singleton con Lazy Initialization:
public class Main {
public static void main(String[] args) {
SingletonLazy singleton = SingletonLazy.getInstance();
singleton.mostrarMensaje();
}
}
En este ejemplo, la instancia de SingletonLazy solo se crea cuando se llama al método getInstance() por primera vez. Si el método nunca es llamado, la instancia nunca se crea.
Singleton con Eager Initialization #
En el caso de Eager Initialization, la instancia de la clase Singleton se crea en el momento en que se carga la clase. Esto asegura que la instancia esté disponible inmediatamente, pero también significa que se creará incluso si nunca se utiliza, lo que puede ser un desperdicio de recursos en algunos casos.
public class SingletonEager {
// Instancia única de la clase, creada al cargar la clase
private static final SingletonEager instancia = new SingletonEager();
// Constructor privado para evitar instanciación desde fuera
private SingletonEager() {
// Inicialización de recursos si es necesario
}
// Método público para obtener la instancia única de la clase
public static SingletonEager getInstance() {
return instancia;
}
// Método de ejemplo en la clase Singleton
public void mostrarMensaje() {
System.out.println("Hola desde Singleton con Eager Initialization!");
}
}
Uso del Singleton con Eager Initialization:
public class Main {
public static void main(String[] args) {
SingletonEager singleton = SingletonEager.getInstance();
singleton.mostrarMensaje();
}
}
En este ejemplo, la instancia de SingletonEager se crea en el momento en que la clase es cargada por el JVM, incluso si nunca se utiliza. Esto asegura que la instancia esté disponible inmediatamente, pero podría ser ineficiente si la instancia nunca es necesaria.
Conclusión #
- Lazy Initialization: La instancia se crea solo cuando es necesario, lo que puede ahorrar recursos si la instancia no siempre se usa.
- Eager Initialization: La instancia se crea tan pronto como se carga la clase, lo que asegura que esté disponible de inmediato, pero puede ser menos eficiente si la instancia no es utilizada.
Ejemplo de Singleton en Spring Boot #
En Spring Boot, el patrón Singleton es implementado por defecto en los beans de Spring, ya que los beans son Singleton por defecto. Aquí tienes un ejemplo simple:
import org.springframework.stereotype.Service;
@Service
public class SingletonService {
// Método de ejemplo en el bean Singleton
public void mostrarMensaje() {
System.out.println("Hola desde Singleton en Spring Boot!");
}
}
Uso del Singleton en Spring Boot:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Autowired
private SingletonService singletonService;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
singletonService.mostrarMensaje();
}
}
En este ejemplo:
- La clase
SingletonServicees un bean administrado por Spring. - La anotación
@Serviceindica que esta clase es un servicio de Spring, y Spring la manejará como un Singleton. - En la clase principal
DemoApplication, elSingletonServicese inyecta utilizando@Autowired, asegurando que la misma instancia se utiliza en todo el ciclo de vida de la aplicación.
Conclusión #
El patrón Singleton es ampliamente utilizado cuando se necesita garantizar que una clase tenga una única instancia en toda la aplicación. En Java puro, se implementa de forma explícita, mientras que en Spring Boot, los beans ya son Singleton por defecto, lo que simplifica su uso y gestión.