7

Spring Bean のプロパティを別の Bean のプロパティにバインドする方法があれば、バインドされたプロパティの変更が実行時に発生した場合、Bean のプロパティの参照も変更されると思います。少しコードスニペットで詳しく説明します。

<bean id="johnHome" class="example.Contact">
    <プロパティ名="電話" 値="5551333" />
</bean>

<bean id="johnWork" class="example.Contact">
    <プロパティ名="電話">
        <util:property-path path="johnHome.phone" />
    </プロパティ>
</bean>

わかった。これは最初の Bean 配線で機能しますが、私が正確に望むのはプロパティをバインドすることです。そのため、実行時にプロパティが変更されると、参照する Bean も変更されます。比喩で示すとしたら、このようになります。

<bean id="johnHome" class="example.Contact">
    <プロパティ名="電話" 値="5551333" />
</bean>

<bean id="johnWork" class="example.Contact">
    <プロパティ名="電話">
        <util:bind path="johnHome.phone" />
    </プロパティ>
</bean>

スプリングのコンセプトを過負荷にしていますか、それとも多くのトリックなしで可能ですか?

ありがとう..

4

4 に答える 4

1

Spring の背後にある全体的なアイデアは (だった?) 単純な古い Java オブジェクトで構成されるクリーンなオブジェクト指向設計を維持し、Spring フレームワークを使用して退屈なオブジェクト作成を処理することです。AOP に関しては、これは分野横断的な問題のみを処理する必要があります。これが AOP が良いアイデアであるケースの 1 つであるとは、私にはまったく確信が持てません。アプリケーションは、これらの電話番号が相互に同期される動作に依存しており、これは主要な機能の 1 つです。そのため、デザインはこれを反映する必要があります。

おそらく、この特定の問題を処理する最も論理的な方法は、電話番号を独自のクラスにすることです (これは、さまざまな種類の電話番号を区別したい場合にも便利です)。

コンストラクターの引数として番号を取る PhoneNumber オブジェクトがある場合、マッピングは自明になります。

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

もちろん、このように静的ファイルにマップするかどうかは別の問題ですが、この状況では、参照/ポインターが必要なのは明らかです。

于 2009-07-01T13:47:12.570 に答える
0

Spring2.5ではあなたがしていることは不可能だと思います。Spring 3では、新しい式の構文を使用することは可能かもしれませんが、私はそうは思いません。

たとえそうだったとしても、混乱するだろうと思います。共有値を独自のクラスに固定し、そのクラスのインスタンスを共有する必要のある他のBeanに注入することをお勧めします。

于 2009-05-21T15:01:30.587 に答える
0

2つの可能性が考えられます。

1つは(一種のハックです)、例のようにリンクする必要があるBeanがあまりない場合は、johnWorkをjohnHome Beanに注入し、johnHome.setPhoneで更新できますjohnWork の phone プロパティ、次のようなもの:

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

または、HomeContact と WorkContact の両方でクラス Contact を拡張し、それで同じインジェクションを行うこともできます。

これを必要とする大量の Bean がある場合 (アプリケーションが実際に連絡先情報を処理している場合など)、AOP (この例では AspectJ が必要です) を使用すると、このようなことができると思います (大量のオブジェクトを取得すると、少しメモリが集中しますが、そのようなものがどのように機能するかを見ることができます):

警告: これは実際にはすぐに複雑になりましたが、いくつかの問題を解決すればうまくいくと確信しています。

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

繰り返しますが、これを最適化できる方法はおそらく 100 通りあります。つまり、そもそもこのルートに行きたかった場合です。理論的には動作するはずですが、まったくテストしていません。

とにかく、ハッピースプリング!

于 2009-06-01T21:28:59.403 に答える