【问题标题】:MVP with CDI; avoiding circular dependencyCDI MVP;避免循环依赖
【发布时间】:2012-08-10 19:54:42
【问题描述】:

我尝试使用 MVP 范式构建 Webapp。因为我希望 API 是干净的并且让所有东西都易于测试,所以我尝试通过构造函数注入来注入所有可能的东西。现在我已经到了可以查看多个文本字段的地步。当数据库中有值时,这些文本字段由演示者填充,因此我的演示者需要视图的引用,但 vie 显然也需要演示者的引用。 CDI 告诉我,由于循环依赖关系,无法将 Presenter 注入视图,否则是不可能的。是否可以通过 setter 方法避免在视图中设置演示者?代码如下所示:

查看:

public Class ViewImpl implements view {

private PresenterImpl presenter;
private User user;

@Inject
public ViewImpl(PresenterImpl presenter, User user) {
   super();
   this.presenter = presenter;
   this.user = user;
}

public void attach() {
   super.attach();

   presenter.fetchNames();

   showUser();
   }

public void setUser(User user) {
   this.user = user;
   }
}

演讲者:

public Class PresenterImpl implements Presenter {

private ViewImpl view;
private User user;

@Inject
public PresenterImpl(ViewImpl view, User user) {
   this.view = view;
   this.user = user;
}


public void fetchNames() {
   fetchFromDB();
   view.setUser(user);
}
}

这里我得到了循环依赖。为了避免这种情况,我尝试使用实例接口并将演示者更改为:

演讲者:

public Class PresenterImpl implements Presenter {

private ViewImpl view;
private Instance<ViewImpl> instanceView;
private User user;

@Inject
public PresenterImpl(Instance<ViewImpl> instanceView, User user) {
   this.instanceView = instanceView;
   this.user = user;

   bind();
}

public void bind() {
   this.view = instanceView.get();
}

public void fetchNames() {
   fetchFromDB();
   view.setUser(user);
}
}

但是当我这样做时,我得到一个 java.lang.NoClassDefFoundError: org/jboss/weld/injection/Exceptions

更新:这是堆栈跟踪

[com.vaadin.Application] (http-localhost-127.0.0.1-8080-2) Terminal error:: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_05]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_05]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_05]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_05]
at com.vaadin.terminal.gwt.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:141) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.terminal.gwt.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:89) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleBurst(AbstractCommunicationManager.java:1660) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1543) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleUidlRequest(AbstractCommunicationManager.java:577) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:461) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:350) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at de.me.main.web.MEAppServlet.service(MEAppServlet.java:60) [classes:]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_05]
Caused by: com.vaadin.event.ListenerMethod$MethodException: Invocation of method click in de.me.login.view.LoginViewImpl$1 failed.
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:530) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:164) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.ui.AbstractComponent.fireEvent(AbstractComponent.java:1035) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
at com.vaadin.ui.Embedded$1.click(Embedded.java:97) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
... 30 more
Caused by: java.lang.NoClassDefFoundError: org/jboss/weld/injection/Exceptions
at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:125) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.createInstance(ManagedBean.java:333) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean$ManagedBeanInjectionTarget.produce(ManagedBean.java:200) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:289) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.context.unbound.DependentContextImpl.get(DependentContextImpl.java:61) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:616) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:681) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ParameterInjectionPoint.getValueToInject(ParameterInjectionPoint.java:120) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.getParameterValues(ConstructorInjectionPoint.java:170) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:117) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.createInstance(ManagedBean.java:333) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean$ManagedBeanInjectionTarget.produce(ManagedBean.java:200) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:289) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.context.unbound.DependentContextImpl.get(DependentContextImpl.java:61) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:616) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:681) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ParameterInjectionPoint.getValueToInject(ParameterInjectionPoint.java:120) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.getParameterValues(ConstructorInjectionPoint.java:170) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:117) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.createInstance(ManagedBean.java:333) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean$ManagedBeanInjectionTarget.produce(ManagedBean.java:200) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:289) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.context.unbound.DependentContextImpl.get(DependentContextImpl.java:61) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:616) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:681) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ParameterInjectionPoint.getValueToInject(ParameterInjectionPoint.java:120) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.getParameterValues(ConstructorInjectionPoint.java:170) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:117) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.createInstance(ManagedBean.java:333) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean$ManagedBeanInjectionTarget.produce(ManagedBean.java:200) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:289) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.context.unbound.DependentContextImpl.get(DependentContextImpl.java:61) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:616) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:681) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ParameterInjectionPoint.getValueToInject(ParameterInjectionPoint.java:120) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.getParameterValues(ConstructorInjectionPoint.java:170) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:117) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.createInstance(ManagedBean.java:333) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean$ManagedBeanInjectionTarget.produce(ManagedBean.java:200) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:289) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.context.unbound.DependentContextImpl.get(DependentContextImpl.java:61) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:616) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:681) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ParameterInjectionPoint.getValueToInject(ParameterInjectionPoint.java:120) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.getParameterValues(ConstructorInjectionPoint.java:170) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:117) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.createInstance(ManagedBean.java:333) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean$ManagedBeanInjectionTarget.produce(ManagedBean.java:200) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:289) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.context.AbstractContext.get(AbstractContext.java:107) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:90) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:79) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at de.me.main.layout.MainLayouter$Proxy$_$$_WeldClientProxy.go(MainLayouter$Proxy$_$$_WeldClientProxy.java) [MainService-0.0.5-SNAPSHOT.jar:]
at de.me.controller.MainController.showMainView(MainController.java:81) [MainService-0.0.5-SNAPSHOT.jar:]
at de.me.controller.MainController.access$0(MainController.java:80) [MainService-0.0.5-SNAPSHOT.jar:]
at de.me.controller.MainController$1.onLogin(MainController.java:48) [MainService-0.0.5-SNAPSHOT.jar:]
at de.me.presenter.LoginPresenterImpl.doLogin(LoginPresenterImpl.java:69) [UserManagement-0.0.5-SNAPSHOT.jar:]
at de.me.view.LoginViewImpl$1.click(LoginViewImpl.java:60) [UserManagement-0.0.5-SNAPSHOT.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_05]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_05]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_05]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_05]
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510) [vaadin-7.0.0.alpha3.jar:7.0.0.alpha3]
... 33 more

【问题讨论】:

  • 至少将org.jboss.weld.injection.Exceptions添加到类路径中,这样您就可以看到异常是什么

标签: java cdi


【解决方案1】:

尝试将注入点从构造函数移动到属性。所以用@Injection 注释属性,而不是构造函数。我认为这种方式焊接首先创建类的实例,然后才注入依赖项。并将您的构造函数替换为默认值。
如果您在创建 Presenter 时注释构造函数焊接需要有 View 的实例,但要创建 View 他需要 Presenter。使用默认构造函数和带注释的属性,它可以同时创建 View 和 Presenter,然后才能将它们相互注入。

【讨论】:

    【解决方案2】:

    在我看来,Vaadin 与问题无关。

    可能(可能)存在循环依赖注入问题,但问题在于ClassNotFoundException。您要部署到哪个应用程序服务器?它是成熟的 Java EE 6 AS 吗?如果没有,您的部署中可能缺少一些库。

    【讨论】:

    • 我使用的是 JBoss 7.1。这应该不是问题。
    【解决方案3】:

    我现在开始工作了。 Nikita Beloglazov 的提示很有帮助,因为据我了解,问题确实是实例化完成的那一刻。因为我想继续使用构造函数注入,所以我选择了第二种方法:

    public Class PresenterImpl implements Presenter {
    
    private ViewImpl view;
    private Instance<ViewImpl> instanceView;
    private User user;
    
    @Inject
    public PresenterImpl(Instance<ViewImpl> instanceView, User user) {
       this.instanceView = instanceView;
       this.user = user;
    
       bind();
    }
    
    public void bind() {
       this.view = instanceView.get();
    }
    
    public void fetchNames() {
       fetchFromDB();
       view.setUser(user);
    }
    }
    

    为了让它工作,我必须在构造函数注入时只注入一个代理对象,并在对对象执行第一个操作时获取真实实例。这是正常作用域 bean 的正常行为。所以我制作了演示者和视图@SessionScoped,并从Serializable 扩展了接口。现在构造函数注入工作并且 ViewImpl 是“惰性注入”。

    【讨论】:

    • 这种方法确实解决了循环依赖,但请注意,此异常表明您的架构存在问题。见@nick 的this answer
    【解决方案4】:

    有一些解决循环依赖的方法,但是当抛出这种异常时,请注意您的架构可能有问题。

    但是考虑看看this answer

    【讨论】:

      猜你喜欢
      • 2013-02-06
      • 1970-01-01
      • 2012-02-15
      • 1970-01-01
      • 1970-01-01
      • 2013-04-02
      • 2011-06-16
      • 2023-03-11
      相关资源
      最近更新 更多