如何将bean属性绑定到另一个属性并观察Spring Framework中的更改

时间:2009-05-21 09:03:51

标签: spring javabeans

我想知道如果有一种方法可以将spring bean的属性绑定到另一个bean的属性,那么如果在运行时对绑定属性进行任何更改,我所期望的是引用bean的属性也会发生变化。我会用一些代码片段解释一下。

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

行。这适用于初始bean连接,但我真正想要的是绑定属性,因此如果属性在运行时更改,则引用bean也会更改。如果我想用一个比喻来表示它会是这样的。

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

我是否过多地超载了弹簧的概念,或者这可能没有太多技巧?

谢谢..

4 个答案:

答案 0 :(得分:1)

最简单的方法 - 使该属性成为另外两个bean引用的bean,例如对于String值,有一个StringHolder类:

public class StringHolder {
     private String value;

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

}

答案 1 :(得分:1)

Spring背后的整个想法是(是?)保持一个干净的面向对象设计,由普通的旧Java对象组成,并使用spring框架来处理繁琐的对象创建。至于AOP,这应该只处理跨领域的问题。我完全不相信这是AOP是一个好主意的案例之一。您的应用程序依赖于这些电话号码相互同步的行为,这是主要功能之一。因此,您的设计应该反映这一点。

处理这个特定问题的最合乎逻辑的方法可能是将电话号码设为自己的班级(如果你想区分不同类型的电话号码,这也很方便。)

如果您有一个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>

当然,你是否将它映射到静态文件中是另一回事,但事情就是在这种情况下你很明显只需要一个引用/指针。

答案 2 :(得分:0)

我不认为你在Spring 2.5中做了什么。使用新的表达式语法可以在Spring 3中实现 ,但我不这么认为。

即便如此,我想也会感到困惑。最好将您的共享值粘贴到自己的类中,并将该类的实例注入需要共享它的其他bean中。

答案 3 :(得分:0)

我可以想到两种可能性。

一个是(它有点像黑客),如果你没有很多需要像示例中那样链接的bean,你可以将johnWork注入johnHome bean,并在johnHome.setPhone中注入可以更新johnWork手机属性,如:

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,然后对它进行相同的注入。

如果你有大量的豆需要这个(就像你的应用程序实际上是在处理联系信息),使用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种方法可以优化这一点,因为我正在键入它的顶部;也就是说,如果你想首先走这条路。理论上它应该可以工作,但我根本没有测试过它。

无论如何,快乐的春天!