2010-08-04 15 views
196

En un bean administrado, se llama a @PostConstruct en función del constructor de objetos Java estándar.¿Por qué usar @PostConstruct?

¿Por qué usaría @PostConstruct para inicializar por bean, en lugar del propio constructor normal?

+0

Me dio la impresión de que la inyección de constructor generalmente se prefería para permitir que las dependencias fueran 'finales'. Dado ese patrón, ¿por qué se agrega '@ PostConstruct' a J2EE? ¿Deben haber visto otro caso de uso con seguridad? – mjaggard

Respuesta

288
  • porque cuando se llama al constructor, el grano aún no está inicializado - se inyectan es decir, no hay dependencias. En el método @PostConstruct, el bean está completamente inicializado y puede usar las dependencias.

  • porque este es el contrato que garantiza que este método se invocará solo una vez en el ciclo de vida del bean. Puede suceder (aunque poco probable) que un bean sea instanciado varias veces por el contenedor en su funcionamiento interno, pero garantiza que @PostConstruct se invocará solo una vez.

+7

en caso de que el propio constructor conecte todas las dependencias automáticamente, entonces el bean también puede inicializarse por completo en el constructor (después de configurar manualmente todos los campos autoconectados). – yair

+3

¿Cuál es el caso en el que el constructor de un bean se puede llamar más de una vez? – yair

+0

Probablemente algo así como "pasivación". Si el contenedor decide almacenar el frijol en la tienda de discos y luego restaurarlo desde allí. – Bozho

45

Si la clase realiza todas la inicialización en el constructor, @PostConstruct entonces es de hecho redundante.

Sin embargo, si su clase tiene sus dependencias inyectado utilizando métodos setter, a continuación, el constructor de la clase no puede inicializar plenamente el objeto y, a veces un poco de inicialización debe ser realizado después de que todos los métodos setter han sido llamados, por lo tanto, el caso de uso de @PostConstruct .

+0

@staffman: más uno de mi lado. Si deseo inicializar un campo de texto de entrada con un valor obtenido de la base de datos, puedo hacerlo con la ayuda de PostConstruct, pero falla cuando trato de hacer lo mismo dentro del constructor. Tengo este requisito para inicializar sin el uso de PostContruct. Si tiene tiempo, ¿puede responder este también: http://stackoverflow.com/questions/27540573/how-to-initialize-inputtextfield-with-a-value-from-database-on-runtime-without-t –

1

También la inicialización basada en el constructor no funcionará según lo previsto siempre que esté involucrado algún tipo de proxying o remoting.

El CT se llamará cada vez que un EJB se deserialized, y cada vez que un nuevo proxy se crea para ella ...

50

Las otras respuestas, especialmente @ Bozho de uno, ya se ha explicado la principal problema (entre el otros):

en un constructor, la inyección de las dependencias aún no ha ocurrido.

En caso de que alguien todavía tiene dudas acerca de lo que esto significa, este es un ejemplo del mundo real que acaba de ocurrir a mí:

public class Foo { 

    @Inject 
    Logger LOG; 

    @PostConstruct 
    public void fooInit(){ 
     LOG.info("This will be printed; LOG has already been injected"); 
    } 

    public Foo() { 
     LOG.info("This will NOT be printed, LOG is still null"); 
     // NullPointerException will be thrown here 
    } 
} 

Espero que ayude.

+4

'en un constructor, la inyección de las dependencias aún no se ha producido. 'true con setter o campo de inyección, pero no es cierto con la inyección de constructor. –

+0

¡Claro! Apenas considero esa * inyección *, sin embargo: a pesar del nombre, al final solo pasa el parámetro ... pero gracias por señalarlo –

+0

¿qué hay de Ejbs? como ejbUs = (UsEjbBeanRemote) sl.findServiceRemote ("Usuario"); ? , Creo que se inicializaron en el constructor –

2

cuenta la situación siguiente:

public class Car { 
    @Inject 
    private Engine engine; 

    public Car() { 
    engine.initialize(); 
    } 
    ... 
} 

Desde tiene coches para ser instanciado previamente a la inyección campo, el motor de punto de inyección sigue siendo nula durante la ejecución del constructor, resultando en una NullPointerException.

Este problema se puede resolver mediante JSR-330 Dependency Injection for Java constructor injection o JSR 250 Common Annotations para la anotación de método Java @PostConstruct.

@PostConstruct

JSR-250 define un conjunto común de anotaciones que se ha incluido en Java SE 6.

La anotación PostConstruct se utiliza en un método que tiene que ser ejecutados después de la inyección de dependencia se hace para realizar cualquier inicialización. Este método DEBE invocarse antes de poner en servicio la clase . Esta anotación DEBE ser compatible con todas las clases que admiten inyección de dependencia.

JSR-250 Chap. 2,5 javax.annotation.PostConstruct

La anotación @PostConstruct permite la definición de métodos para ser ejecutado después de que la instancia se ha instanciado y se han realizado todas inyecta.

public class Car { 
    @Inject 
    private Engine engine; 

    @PostConstruct 
    public void postConstruct() { 
    engine.initialize(); 
    } 
    ... 
} 

En lugar de realizar la inicialización en el constructor, el código se mueve a un método anotado con @PostConstruct.

El procesamiento de los métodos post-construcción es una simple cuestión de encontrar todos los métodos anotados con @PostConstruct e invocarlos sucesivamente.

private void processPostConstruct(Class type, T targetInstance) { 
    Method[] declaredMethods = type.getDeclaredMethods(); 

    Arrays.stream(declaredMethods) 
     .filter(method -> method.getAnnotation(PostConstruct.class) != null) 
     .forEach(postConstructMethod -> { 
     try { 
      postConstructMethod.setAccessible(true); 
      postConstructMethod.invoke(targetInstance, new Object[]{}); 
     } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {  
      throw new RuntimeException(ex); 
     } 
     }); 
} 

El procesamiento de los métodos posteriores a la construcción debe realizarse después de que la creación de instancias y la inyección se hayan completado.