En este tutorial veremos cómo simular un inyección opcional gracias a Spring, a pesar de ser un comportamiento que no está definido en el estándar.
Índice de contenidos
1. Introducción
Con Spring Framework es muy sencillo hacer un inyección de dependencias opcional gracias la anotación @Autowired(required=false)
. De esta forma conseguimos que si no está definido el bean al que se está haciendo referencia, su valor quedará a null
y podremos obrar en consecuencia para, por ejemplo, proporcionar un valor por defecto.
import org.springframework.stereotypeorg.Service; import org.springframework.beans.factory.annotation.Autowired; @Service public class Foo { @Autowired(required=false) private Bar bar; @PostConstruct void afterPropertiesSet() { if (bar == null) { bar = new DefaultBar(); } } ... }
Pero @Autowired
es una anotación específica de Spring y no pertenece al estándar JSR 330, así que ¿cómo podemos hacerlo usando la anotación estandar @Inject
?
En este tutorial vamos a dar respuesta a esta pregunta.
2. Entorno
El tutorial está escrito usando el siguiente entorno:
-
Hardware: Portátil MacBook Pro 15» (2.5 GHz Intel i7, 16GB 1600 Mhz DDR3, 500GB Flash Storage).
-
AMD Radeon R9 M370X
-
Sistema Operativo: Mac OS X El Capitan 10.11.6
-
Java v1.8.0_112
-
Maven v3.3.9
-
Spring 1.3.7.RELEASE
3. Usando Spring + @Inject + Optional
Gracias a Spring podemos simular una inyección opcional, comportamiento que no está definido en el estándar:
import org.springframework.stereotypeorg.Service; import javax.inject.Inject; import java.util.Optional; @Service public class Foo { @Inject private Optional<Bar> optionalBar; private Bar bar; @PostConstruct void afterPropertiesSet() { bar = optionalBar.orElse(new DefaultBar()); } ... }
Podemos ver como en la línea 8 estamos usando la anotación estándar @Inject
sobre un tipo Optional
. Es aquí donde Spring se encarga de hacer la «magia» y dar valor a este atributo en función de si existe o no un bean de tipo Bar
.
Luego en el @PostConstruct
, en la línea 15 es donde, igual que en el ejemplo anterior, comprobamos la existencia del bean y en caso de no estar presente inicializamos el atributo con el valor por defecto.
4. Conclusiones
Ojo, y no penséis que os estoy recomendando esta construcción, de hecho más bien lo contrario. Tener un Bean opcional es raro, y usar la clase Optional
si no es como valor de retorno de un método es más que cuestionable. Así que cuidado con hacer este tipo de cosas porque si no está muy justificado puede ser un mal olor.
Esto lo descubrí el otro día por casualidad y simplemente quería mostrároslo en este tutorial porque me ha parecido curioso.
6. Referencias
Imágen inicial extraída del artículo: http://www.arquitecturajava.com/spring-inject-cdi-y-standards/
5. Sobre el autor
Alejandro Pérez García (@alejandropgarci)
Ingeniero en Informática (especialidad de Ingeniería del Software) y Certified ScrumMaster
Socio fundador de Autentia Real Business Solutions S.L. – «Soporte a Desarrollo»
Socio fundador de ThE Audience Megaphone System, S.L. – TEAMS – «Todo el potencial de tus grupos de influencia a tu alcance»
Hay muchas manera de hacer DI, pero para mi la más recomendable es con Setters,
Siento disentir.
Siempre recomendaría hacer la DI mediante el constructor. La semántica que esto aporta es que se inicializan los colaboradores de un objeto en tiempo de construcción y estos no cambian. Salvo raras excepciones no tiene sentido cambiar los colaboradores a lo largo del ciclo de vida del objeto.
De hecho esto nos permite también trabajar con objetos inmutables que nos evita problemas de concurrencia.