Entendiendo getBean () en Spring

1. Introducción

En este tutorial, veremos diferentes variantes del método BeanFactory.getBean () .

En pocas palabras, como también sugiere el nombre del método, este es responsable de recuperar una instancia de bean del contenedor Spring .

2. Configuración de Spring Beans

Primero, definamos algunos Spring beans para probar. Hay varias formas en las que podemos proporcionar definiciones de bean para el contenedor Spring, pero en nuestro ejemplo, usaremos una configuración de Java basada en anotaciones:

@Configuration class AnnotationConfig { @Bean(name = {"tiger", "kitty"}) @Scope(value = "prototype") Tiger getTiger(String name) { return new Tiger(name); } @Bean(name = "lion") Lion getLion() { return new Lion("Hardcoded lion name"); } interface Animal {} } 

Hemos creado dos frijoles. Lion tiene el alcance singleton predeterminado. Tiger se establece explícitamente en el alcance del prototipo. Además, tenga en cuenta que definimos nombres para cada bean que usaremos en solicitudes posteriores.

3. Las API getBean ()

BeanFactory proporciona cinco firmas diferentes del método getBean () que examinaremos en las siguientes subsecciones.

3.1. Recuperando Bean por Nombre

Veamos cómo podemos recuperar una instancia de bean Lion usando su nombre:

Object lion = context.getBean("lion"); assertEquals(Lion.class, lion.getClass());

En esta variante, proporcionamos un nombre y, a cambio, obtenemos una instancia de la clase Object si existe un bean con el nombre dado en el contexto de la aplicación. De lo contrario, tanto esta como todas las demás implementaciones arrojan NoSuchBeanDefinitionException si falla la búsqueda del bean.

La principal desventaja es que después de recuperar el bean, tenemos que convertirlo al tipo deseado. Esto puede producir otra excepción si el bean devuelto tiene un tipo diferente al esperado .

Supongamos que intentamos conseguir un Tigre con el nombre de "león". Cuando lanzamos el resultado a Tiger , lanzará una ClassCastException :

assertThrows(ClassCastException.class, () -> { Tiger tiger = (Tiger) context.getBean("lion"); });

3.2. Recuperando Bean por Nombre y Tipo

Aquí necesitamos especificar tanto el nombre como el tipo del bean solicitado:

Lion lion = context.getBean("lion", Lion.class);

En comparación con el método anterior, este es más seguro porque obtenemos la información sobre la falta de coincidencia de tipos al instante:

assertThrows(BeanNotOfRequiredTypeException.class, () -> context.getBean("lion", Tiger.class)); }

3.3. Recuperando Bean por Tipo

Con la tercera variante de getBean (), es suficiente especificar solo el tipo de bean:

Lion lion = context.getBean(Lion.class);

En este caso, debemos prestar especial atención a un resultado potencialmente ambiguo :

assertThrows(NoUniqueBeanDefinitionException.class, () -> context.getBean(Animal.class)); }

En el ejemplo anterior, debido a que tanto Lion como Tiger implementan la interfaz Animal , la mera especificación del tipo no es suficiente para determinar de forma inequívoca el resultado. Por lo tanto, obtenemos una NoUniqueBeanDefinitionException .

3.4. Recuperar Bean por nombre con parámetros de constructor

Además del nombre del bean, también podemos pasar parámetros de constructor:

Tiger tiger = (Tiger) context.getBean("tiger", "Siberian");

Este método es un poco diferente porque solo se aplica a beans con alcance de prototipo .

En el caso de los singleton, obtendremos una BeanDefinitionStoreException.

Debido a que un bean prototipo devolverá una instancia recién creada cada vez que se solicite desde el contenedor de la aplicación, podemos proporcionar parámetros de constructor sobre la marcha al invocar getBean () :

Tiger tiger = (Tiger) context.getBean("tiger", "Siberian"); Tiger secondTiger = (Tiger) context.getBean("tiger", "Striped"); assertEquals("Siberian", tiger.getName()); assertEquals("Striped", secondTiger.getName());

Como podemos ver, cada Tiger recibe un nombre diferente según lo que especificamos como segundo parámetro al solicitar el bean.

3.5. Recuperar Bean por tipo con parámetros de constructor

Este método es análogo al último, pero necesitamos pasar el tipo en lugar del nombre como primer argumento:

Tiger tiger = context.getBean(Tiger.class, "Shere Khan"); assertEquals("Shere Khan", tiger.getName());

Similar a recuperar un bean por nombre con parámetros de constructor, este método solo se aplica a beans con alcance de prototipo .

4. Consideraciones de uso

A pesar de estar definido en la interfaz BeanFactory , el método getBean () se accede con mayor frecuencia a través de ApplicationContext. Normalmente, no queremos utilizar el método getBean () directamente en nuestro programa .

Los frijoles deben ser manejados por el contenedor. Si queremos usar uno de ellos, debemos confiar en la inyección de dependencia en lugar de una llamada directa a ApplicationContext.getBean () . De esa manera, podemos evitar mezclar la lógica de la aplicación con detalles relacionados con el marco.

5. Conclusión

En este tutorial rápido, analizamos todas las implementaciones del método getBean () desde la interfaz BeanFactory y describimos los pros y los contras de cada uno.

Todos los ejemplos de código que se muestran aquí están disponibles en GitHub.