2009-05-21 16 views
7

Mi chiedo se esiste un modo per associare la proprietà di un bean spring alla proprietà di un altro bean, quindi se qualsiasi modifica sulla proprietà binded si verifica in runtime, mi aspetto che il riferimento alle proprietà del bean cambi anche. Spiegherò di più con un piccolo snippet di codice.Come associare una proprietà bean a un'altra e osservare le modifiche in 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. Questo funziona con il cablaggio iniziale del bean, ma quello che voglio esattamente è legare la proprietà, quindi se la proprietà cambia durante il runtime cambia anche il bean di riferimento. Se mi piacerebbe mostrare con una metafora, sembrerà così.

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

Sto sovraccaricando troppo il concetto della molla o è possibile senza trucchi?

Grazie ..

risposta

0

non credo quello che stai facendo è possibile in primavera 2.5. È possibile essere possibile nella primavera 3, utilizzando la nuova sintassi di espressione, ma io non la penso così.

Anche se lo fosse, sarebbe confuso, penso. Meglio attaccare il proprio valore condiviso alla propria classe e iniettare un'istanza di quella classe negli altri bean che devono condividerla.

0

Posso pensare a due possibilità.

Uno è (è una specie di modifica), se non si hanno molti bean che devono essere collegati come quelli nell'esempio, è possibile inserire johnWork nel bean johnHome e in johnHome.setPhone si potrebbe aggiornare la proprietà telefono johnWork, qualcosa di simile:

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; 
    } 
} 

Oppure si potrebbe avere HomeContact e WorkContact sia estendere una classe di contatto e fare lo stesso con quella di iniezione.

Se hai tonnellate e tonnellate di fagioli che ne avranno bisogno (come se la tua applicazione in realtà STA occupandosi di informazioni di contatto), con AOP (avrai bisogno di AspectJ per l'esempio dato) Penso che potresti fare qualcosa come questo (sarà un po 'impegnativo in termini di memoria se ottieni un sacco di oggetti, ma puoi vedere come funzionerebbe qualcosa):

Attenzione: questo in realtà è diventato complicato velocemente, ma sono abbastanza sicuro che funzionerebbe dopo aver lavorato fuori alcuni intoppi

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); 
      } 
     } 
    } 
} 

Anche in questo caso, c'è probabilmente 100 wa Si potrebbe ottimizzare questo, dal momento che sto digitandolo dalla cima della mia testa; cioè, se volessi percorrere questa strada in primo luogo. In teoria dovrebbe funzionare ma non l'ho ancora provato.

In ogni caso, Happy Springing!

1

Il modo più semplice: rendere a tale proprietà un bean a cui fanno riferimento gli altri due bean, ad es. per un valore String avere una classe cordiera:

public class StringHolder { 
    private String value; 

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

} 
1

L'idea alla base della molla è (era?) per mantenere una progettazione orientata agli oggetti pulita composta da oggetti semplici java vecchi e utilizzare il quadro di primavera per gestire l'oggetto noioso creazione. Per quanto riguarda AOP, questo dovrebbe solo gestire i problemi trasversali. Non sono affatto convinto che questo è uno di quei casi in cui AOP è una buona idea.La tua applicazione si basa sul comportamento di questi numeri di telefono sincronizzati tra loro, è una delle funzionalità principali. In quanto tale, il tuo design dovrebbe riflettere questo.

Probabilmente il modo più logico per gestire questo specifico problema è rendere i numeri di telefono propri della propria classe (utile anche se si desidera distinguere diversi tipi di numeri di telefono).

Se si dispone di un oggetto PhoneNumber che prende il numero come argomento del costruttore la mappatura diventa banale:

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

Naturalmente se ci si mappare come questo in un file statico è un altro discorso, ma la la cosa è in questa situazione, è chiaro che hai solo bisogno di un riferimento/puntatore.