Pregunta ¿Por qué usar constructor sobre setter injection en CDI?


No pude encontrar ninguna respuesta razonable aquí en SO, así que espero que no sea un duplicado. Entonces, ¿por qué debería preferir la inyección de setter o constructor sobre simple

@Inject
MyBean bean;

Obtengo el uso de la inyección de constructor si necesitas hacer algo con Bean inyectado durante la inicialización de tu clase, como

public void MyBean(@Inject OtherBean bean) {
    doSomeInit(bean);
    //I don't need to use @PostConstruct now
}

pero aún así, es casi lo mismo @PostConstruct método y no tengo inyección de setter, ¿no es solo una reliquia después de Spring y otros frameworks DI?


11
2017-10-15 12:56


origen


Respuestas:


La inyección de propiedades y constructores le ofrece la opción de inicializar el objeto incluso en un entorno que no sea CDI, por ejemplo, una prueba unitaria.

En un entorno que no sea CDI, puede simplemente usar el objeto simplemente pasando el constructor arg.

OtherBean b = ....;
new MyBean(b);

Si solo usa la inyección de campo, debe usar el reflejo para acceder al campo si es privado, por ejemplo.

Si usa la inyección de propiedad también puede escribir código en el colocador. Por lo tanto, depende de sus necesidades de implementación.

Setter contra inyección de constructor

En la programación orientada a objetos, un objeto debe estar en un estado válido después de la construcción y cada invocación de método cambia el estado a otro estado válido.

Para inyección setter esto significa que puede requerir un manejo de estado más complejo, porque un objeto debe estar en un estado válido después de la construcción. Incluso si el setter no ha sido invocado aún. Por lo tanto, el objeto debe estar en un estado válido incluso si la propiedad no está configurada. P.ej. utilizando un valor predeterminado o un objeto nulo.

Si tiene una dependencia entre la existencia del objeto y la propiedad, la propiedad debe ser un argumento de constructor. Esto también hará que el código esté más limpio, porque si usa un parámetro de constructor documenta que la dependencia es necesaria.

Entonces, en lugar de escribir una clase como esta

public class CustomerDaoImpl implements CustomerDao {

  private DataSource dataSource;

  public Customer findById(String id){
     // Is the dataSource set?!
     Connection con = dataSource.getConnection();
     ...
     return customer;
  }

  public void setDataSource(DataSource dataSource){
     this.dataSource = dataSource;
  }

}

deberías usar inyección de constructor

public class CustomerDaoImpl implements CustomerDao {

  private DataSource dataSource;

  public CustomerDaoImpl(DataSource dataSource){
      if(dataSource == null){
        throw new IllegalArgumentException("Parameter dataSource must not be null");
     }
     this.dataSource = dataSource;
  }

  public Customer findById(String id) {    
      Customer customer = null;
     // We can be sure that the dataSource is not null
     Connection con = dataSource.getConnection();
     ...
     return customer;
  }
}

Mi conclusión

  • Utilizar propiedades para cada dependencia opcional.
  • Utilizar constructor args para cada dependencia obligatoria.

PD: Mi blog La diferencia entre pojos y java explica mi conclusión con más detalle.


12
2017-10-15 13:08



Cuando se usa CDI, no hay ninguna razón para usar la inyección de constructor o instalador. Como se indicó en la pregunta, agregas un @PostConstruct método para lo que de otro modo se haría en un constructor.

Otros pueden decir que necesita usar Reflection para inyectar campos en pruebas unitarias, pero ese no es el caso; burlarse de las bibliotecas y otras herramientas de prueba hacen eso por usted.

Finalmente, la inyección del constructor permite que los campos sean final, pero esto no es realmente una desventaja de @Inject-campos anotados (que no pueden ser final) La presencia de la anotación, combinada con la ausencia de un código que establezca explícitamente el campo, debe dejar en claro que debe ser establecida solo por el contenedor (o la herramienta de prueba). En la práctica, nadie volverá a asignar un campo inyectado.

La inyección de constructor y setter tenía sentido en el pasado, cuando los desarrolladores generalmente tenían que instanciar manualmente e inyectar dependencias en un objeto probado. Hoy en día, la tecnología ha evolucionado y la inyección de campo es una opción mucho mejor.


4
2018-02-24 21:01