2009-05-21 7 views
7

Me pregunto si existe una forma de vincular la propiedad de un frijol con la propiedad de otro frijol, de modo que si ocurre algún cambio en la propiedad en tiempo de ejecución, Espero que la referencia a la propiedad de Bean también cambie. Explicaré más con un pequeño fragmento de código.Cómo vincular una propiedad de frijol a otra y observar cambios en Spring Framework

 
<bean id="johnHome" class="example.Contact"> 
    <property name="phone" value="5551333" /> 
</bean> 

<bean id="johnWork" class="example.Contact"> 
    <property name="phone"> 
     <util:property-path path="johnHome.phone" /> 
    </property> 
</bean> 

OK. Esto funciona en el cableado de beans inicial, pero lo que quiero exactamente es vincular la propiedad, de modo que si la propiedad cambia en tiempo de ejecución, el bean de referencia también cambia. Si me gustaría mostrar con una metáfora, se verá así.

 
<bean id="johnHome" class="example.Contact"> 
    <property name="phone" value="5551333" /> 
</bean> 

<bean id="johnWork" class="example.Contact"> 
    <property name="phone"> 
     <util:bind path="johnHome.phone" /> 
    </property> 
</bean> 

¿Estoy sobrecargando el concepto de la primavera demasiado o es posible sin muchos trucos?

Gracias ..

Respuesta

0

no creo que lo que está haciendo es posible en la primavera de 2,5. Es puede ser posible en la primavera 3, utilizando la nueva sintaxis de expresión, pero no lo creo.

Incluso si lo fuera, sería confuso, creo. Es mejor incluir su valor compartido en su propia clase e inyectar una instancia de esa clase en los otros beans que necesitan compartirlo.

0

Puedo pensar en dos posibilidades.

Una es (es una especie de truco), si no tiene muchos frijoles que deben estar vinculados como los de su ejemplo, puede inyectar johnWork en el frijol johnHome, y en johnHome.setPhone se podría actualizar la propiedad de teléfono johnWork, algo así como:

public class Contact { 
    private Contact myWorkContact; 
    private String phone; 

    public void setPhone(String phone) { 
     this.phone = phone; 
     if (this.myWorkContact != null) { 
      this.myWorkContact.setPhone(phone); 
     } 
    } 

    public void setWorkContact(Contact c) { 
     this.myWorkContact = c; 
    } 
} 

o podría tener InicioContactenos y WorkContact tanto extender una clase de contacto y hacer lo mismo con la inyección de eso.

Si tiene toneladas y toneladas de frijoles que necesitarán esto (como si su aplicación realmente trata con información de contacto), con AOP (necesitará AspectJ para el ejemplo dado) Creo que podría hacer algo como esto (Será un poco intensivo en memoria si obtienes una tonelada de objetos, pero puedes ver cómo funciona algo así):

Advertencia: esto se volvió complicado rápidamente, pero estoy bastante seguro de que funcionaría después de haber trabajado unos pocos problemas

public class Contact { 
    ... 

    private String phone; 
    private String name; 
    private Integer id; 

    public Contact(Integer id, String name, String phone) { 
     this.phone = phone; 
     this.name = name; 
     this.id = id; 
    } 

    public void setPhone(String phone) { 
     this.phone = phone. 
    } 

    //Other getters, setters, etc 

    ... 
} 


@Aspect 
public class ContactPhoneSynchronizer { 
    //there is probably a more efficient way to keep track of contact objects 
    //but right now i can't think of one, because for things like a tree, we need to 
    //be able to identify objects with the same name (John Smith), but that 
    //have different unique ids, since we only want one of each Contact object 
    //in this cache. 

    private List<Contact> contacts = Collections.synchronizedList(new ArrayList<Contact>()); 

    /** 
     This method will execute every time someone makes a new Contact object. 
     If it already exists, return it from the cache in this.contacts. Otherwise, 
     proceed with the object construction and put that object in the cache. 
    **/ 

    @Around("call(public Contact.new(Integer,String,String)) && args(id,name,phone)") 
    public Object cacheNewContact(ProceedingJoinPoint joinPoint, Integer id, String name, String phone) { 
     Contact contact = null; 

     for (Contact c : contacts) { 
      if (id.equals(c.getId()) { 
       contact = c; 
       break; 
      } 
     } 

     if (contact == null) { 
      contact = (Contact) joinPoint.proceed(); 
      this.contacts.add(contact);    
     } 

     return contact; 
    } 

    /**This should execute every time a setPhone() method is executed on 
     a contact object. The method looks for all Contacts of the same 
     name in the cache and then sets their phone number to the one being passed 
     into the original target class. 

     Because objects are passed by reference until you do a reassociation, 
     calling c.setPhone on the object in the cache should update the actual 
     instance of the object in memory, so whoever has that reference will 
     get the updated information. 
    **/ 

    @After("execution(example.Contact.setPhone(String) && args(phone)") 
    public void syncContact(JoinPoint joinPoint, String phone) { 
     Contact contact = joinPoint.getTarget(); 

     for (Contact c : this.contacts) { 
      if (c.getName().equals(contact.getName()) { 
       c.setPhone(phone); 
      } 
     } 
    } 
} 

una vez más, es probable que haya 100 wa Si pudieras optimizar esto, ya que estoy tipeándolo de la parte superior de mi cabeza; es decir, si quería ir a esta ruta en primer lugar. En teoría, debería funcionar, pero no lo he probado en absoluto.

De todos modos, Happy Springing!

1

Manera más simple: haga que la propiedad sea un frijol al que hagan referencia los otros dos granos, p. Ej. por un valor de cadena tienen una clase StringHolder:

public class StringHolder { 
    private String value; 

    // setter and getter elided due to author's lazyness 

} 
1

La idea detrás de la primavera es (era?) para mantener un diseño limpio orientado a objetos que consiste en objetos Plain Old Java y utilizar el marco de primavera para manejar el objeto tediosa creación. En cuanto a AOP, esto solo debería manejar preocupaciones transversales. No estoy del todo convencido de que este sea uno de esos casos en los que AOP es una buena idea.Su aplicación depende del comportamiento de estos números de teléfono para sincronizarse entre sí, es una de las principales funcionalidades. Como tal, su diseño debe reflejar esto.

Probablemente la forma más lógica de manejar este problema específico sea hacer que los números de teléfono sean de su propia clase (lo cual también es útil si alguna vez quiere distinguir diferentes tipos de números de teléfono).

Si usted tiene un objeto Fax que tiene el número como argumento del constructor del mapeo convertido en algo trivial:

<bean id="johnFirstPhone" class="example.PhoneNumber"> 
    <constructor-arg value="5551333" /> 
</bean> 

<bean id="johnHome" class="example.Contact"> 
    <property name="phone" ref="johnFirstPhone" /> 
</bean> 

<bean id="johnWork" class="example.Contact"> 
    <property name="phone" ref="johnFirstPhone" /> 
</bean> 

Por supuesto, si desea asignar así en un archivo estático es otra cuestión, pero el Lo que pasa es que en esta situación es muy obvio que solo necesitas una referencia/puntero.

Cuestiones relacionadas