2011-07-22 12 views
7

La documentación del método context.getBean (nombre, usuario) diceprimavera y el paso de parámetros a la fábrica-método en el tiempo de ejecución

permite especificar argumentos de constructor explícitas método/fábrica argumentos

pero no importa lo que haga (intenté todo), con la configuración más lógica que obtengo cuando los beans se cargan durante la inicialización:

org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'fileValidator' defined in 
PortletContext resource 
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied 
dependency expressed through constructor argument with index 0 of type 
[com.liferay.portal.model.User]: Ambiguous factory method argument 
types - did you specify the correct bean references as factory method 
arguments? 
    org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'fileValidator' defined in 
PortletContext resource 
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied 
dependency expressed through constructor argument with index 0 of type 
[com.liferay.portal.model.User]: Ambiguous factory method argument 
types - did you specify the correct bean references as factory method 
arguments? 

<bean id="fileValidator" 
     class="cz.instance.transl.validation.file.FileValidator" 
     factory-method="createInstance" /> 

private FileValidator(User user) { 
    this.user = user; 
} 

public static FileValidator createInstance(User user) { 
    return new FileValidator(user); 
} 

El comentario dice que puede hacerlo, pero si especifica argumentos de constructor en definiton xml de que el frijol o no, falla.

Respuesta

15

El javadoc dice:

args - argumentos a utilizar si la creación de un prototipo utilizando argumentos explícitos a un método de fábrica estática.

Así, la definición de frijol debe ser un prototipo de frijol con ámbito, es decir

<bean id="fileValidator" 
     scope="prototype" 
     class="cz.instance.transl.validation.file.FileValidator" 
     factory-method="createInstance" /> 
+0

lamentablemente falla de la misma manera que el prototipo. Usando 3.1.0.M2 – lisak

+0

@lisak: Bueno, primero, deja de usar una versión beta, apega a la versión estable (es decir, 3.0.x) – skaffman

+2

Debe ser un error en 3.1.0.M2 ... es bastante complicado allí para encontrar el motivo, intentaré subir un boleto si lo encuentro. gracias – lisak

7

Para llamar a su método de fábrica, Spring necesita acceder a una instancia de usuario para pasar a createInstance. En este caso estoy sólo la creación de un frijol y pasándolo en:

<bean id="user" class="something.something.User"> 
</bean> 

<bean id="validator" class="cz.instance.transl.validation.file.FileValidator" factory-method="createInstance"> 
    <constructor-arg ref="user"/> 
</bean> 
+2

dije que necesitaba para pasar argumentos en tiempo de ejecución - context.getBean (nombre, usuario). – lisak

6

Puede utilizar una fábrica de resumen también establecer el atributo de frijol fábrica. Aquí tenemos una ActionFactory que crea acciones.

<bean id="actions_factory" class="com.imagina.control.actions.impl.ActionFactoryImpl"/> 

<bean id="load_person_action" class="com.imagina.control.actions.impl.LoadPersonAction" 
    factory-bean="actions_factory" factory-method="create"> 
    <constructor-arg value="load_person_action"/>  
</bean> 

Para utilizar esta configuración, usted tiene que tomar estos puntos en cuenta:

  1. crean método no es estática. Ahora pertenece a una instancia
  2. constructor-arg es el parámetro del método de fábrica
10

de lectura a través de 20 puestos, descubrí que no era evidente cómo conseguir un método de fábrica personalizada para tomar los parámetros en tiempo de ejecución, especialmente porque nos vemos obligados a usar las etiquetas constructor-arg y referirnos a un bean existente en el contexto como se establece a continuación y la clase en cuestión actúa como un método de fábrica estático.

<bean id="user" class="something.something.User" /> 

<bean id="fileValidator" 
     class="cz.instance.transl.validation.file.FileValidator" 
     factory-method="createInstance" > 
     <constructor-args ref="user" /> 
</bean> 

Lo tengo trabajo por ir a buscar una instancia del grano utilizado en el constructor-arg fuera del contexto y poblarlo con los valores que los que está trabajando en tiempo de ejecución. Este bean se usará como parámetro cuando obtenga el frijol generado en fábrica.

public class X { 

    public void callFactoryAndGetNewInstance() { 
     User user = context.getBean("user"); 
     user.setSomethingUsefull(...); 
     FileValidator validator = (FileValidator)context.getBean("fileValidator"); 
     ... 
    } 
} 

Nota esto no resuelve el problema de utilizar pedido context.getBean (arg1, arg2) que el método no es relevante en este escenario.La razón por la que no es así es porque todos estos beans son únicos y en este punto no se invoca el constructor. ¡No es un problema ni nada por lo que preocuparse si trabaja en un sistema de usuario único ya que solo tiene 1 usuario Bean en su contexto en cualquier momento y de todos modos!

Sin embargo, para un sistema multiusuario, deberá asegurarse de tener un bean de usuario único para cada usuario real y de utilizar el bean de usuario correcto en la invocación de método de fábrica.

Para hacer esto en un sistema multiusuario, necesitará cambiar los tipos de frijoles para que sean prototipos Y debe crear un frijol de su FileValidator que represente a la fábrica (si planea inyectar la dependencia en la fábrica) y otro bean FileValidator que representa su nueva instancia. Ambos serán del mismo tipo de clase, pero debe darle a cada uno un nombre único. Vea a continuación:

<bean id="user" scope="prototype" class="something.something.User" /> 

<bean id="validatorFactory" 
      class="cz.instance.transl.validation.file.FileValidator"> 
    <constructor-arg value="something" /> 
</bean> 

<bean id="fileValidatorBean" 
      class="cz.instance.transl.validation.file.FileValidator" 
    scope="prototype" 
    factory-method="createInstance" > 
    <constructor-arg ref="user" /> 
</bean> 

y en la clase en la que desea obtener este nuevo bean FileValidator de la fábrica, se puede utilizar la técnica de abajo:

public void someMethod() { 
    ... 
    User user = context.getBean("user"); 
    user.setSomethingUsefull(...); 

    FileValidator fileValidator = 
       (FileValidator)context.getBean("fileValidatorBean", 
               user); 
    ... 
} 
+0

Soy nuevo en la primavera. He intentado su enfoque sugerido y funcionó perfecto para mí. Pero no puedo entender una cosa por la cual necesitamos dos referencias del mismo bean (es decir, validatorFactory y fileValidatorBean). Lo he intentado con single bean (es decir, fileValidatorBean) pero no funciona. ¿Puede por favor dedicar algo de tiempo para explicar el motivo? Por favor. – mrugeshthaker

Cuestiones relacionadas