Cómo hacer una inyección de dependencias opcional gracias a Spring y la clase Optional

2
5014

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.

spring-inject

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»

2 COMENTARIOS

    • 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.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad