2013-03-15 44 views
2

在我的MVP应用我使用的代码如电线我演示以下和查看:MVP与Spring IOC没有循环引用?

View view = new View(); 
Presenter presenter = new Presenter(view); 
view.setPresenter(presenter); 

View类是在暂时无效状态构造,其调用setPresenter整流。如果在没有配置Presenter的情况下使用View,我在View类中有一些代码会抛出IllegalStateException

我希望春天能与配置连接到一起了这种关系,如:

<bean id="presenter" class="com.foo.Presenter"> 
    <constructor-arg ref="view" /> 
</bean> 

<bean id="view" class="com.foo.View"> 
    <property name="presenter" ref="presenter" /> 
</bean> 

这失败,一个漫长的圆形依赖性例外。

有没有一种方法可以告诉Spring构建view bean,然后在最终调用view之前调用setter,然后构造presenter bean?


有关的问题是Spring setter dependency injection after all beans have been created。但是,suggested solutions之一是通过使用基于setter的布线解决循环依赖关系,这正是我在这里没有做到的。该latest manual似乎也同意 - 见“循环依赖”框:

一个可能的解决方法是编辑一些类的源代码,通过制定者,而不是构造器进行配置。或者,避免构造函数注入并仅使用setter注入。换句话说,虽然不推荐使用,但您可以使用setter注入配置循环依赖关系。

+0

如果您使用更好的容器,如Guice,它会自动为您找出循环依赖关系。Spring是IoC框架的一个缓慢的,过时的恐龙。这在2004年非常好,但这是2013年。现在是时候继续改进。 – rees 2013-04-24 22:21:46

回答

1

一些进一步的研究已经发现了一个解决方案。起初,我试图扭转在XML配置文件中的bean定义的顺序和它的工作:

<bean id="view" class="com.foo.View"> 
    <property name="presenter" ref="presenter" /> 
</bean> 

<bean id="presenter" class="com.foo.Presenter"> 
    <constructor-arg ref="view" /> 
</bean> 

然而,正如我相信我不应该依赖于文件排序,以确保这个感觉不对事情并没有打破。这就导致了depends-on可以解决问题的实现:

<bean id="presenter" class="com.foo.Presenter" depends-on="view"> 
    <constructor-arg ref="view" /> 
</bean> 

<bean id="view" class="com.foo.View"> 
    <property name="presenter" ref="presenter" /> 
</bean> 

我欢迎这是否是一个好办法的意见。这是非常有道理的,我以一种不符合我的意愿的方式将我的愿望屈服于我的意志。

2

我敢肯定有一个更好的解决方案,但如果一切都失败了,你可以在 “手动” 做到这一点:

配置:

<bean id="presenter" class="com.foo.Presenter"> 
</bean> 

<bean id="view" class="com.foo.View" init-method="init"> 
</bean> 

视图类:

public class View implements ApplicationContextAware { 

    private ApplicationContext applicationContext; 
    private Presenter presenter; 

    public void init(){ 
     presenter = (Presenter)applicationContext.getBean("presenter"); 
    } 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     this.applicationContext = applicationContext; 
    } 
} 

作为一个额外的说明,如果你有你的配置annotation-driven你可以做@Autowired private ApplicationContext applicationContext;而不是实施ApplicationContextAware接口。

+0

谢谢你的回应。但是,我非常希望有更好的解决方案,因为这需要更多的努力,而不是使用Spring来进行布线。 – 2013-03-15 08:55:35

+1

我的希望也是如此。这是一个有趣的问题,我也想知道是否有更好的/正确的方法来做到这一点。 – 2013-03-15 09:09:03

+0

看起来有可能,[请参阅我的回答](http://stackoverflow.com/a/15428829/474189)。如果有更好的方法,我会在一段时间内将问题保留开放(或者如果我的想法因为任何原因被拒绝)。 – 2013-03-15 09:34:52