【问题标题】:Better way to pass class-reference to an injected instance将类引用传递给注入实例的更好方法
【发布时间】:2012-01-05 20:10:52
【问题描述】:

我正在尝试使用 CDI 和注释在 JSF2 应用程序中获取 MVP(被动视图)模式的运行示例。

我的目标是解耦所有相关项目,这意味着视图位于 jsf-war-project 中,而演示者位于单独的 jar 中。我在 Oracle 上略微关注 Adam Biens example,但我不希望演示者了解有关视图框架(在本例中为 JSF)的任何信息。

我的问题是演示者应该被注入到视图中,但是演示者应该有一个在当前视图实例中传递的参数构造函数。所以我希望@Inject-Annotation 允许@Inject(this) 之类的东西,但它不允许:-(

我通过带有 @PostConstruct 的 init 方法解决了这个问题,该方法在演示者上调用 setter 并将其传递给当前视图。我想这是根据 CDI 规范我能得到的最接近的值...如果我错了,请随时纠正我。

视图-注释:

@Stereotype
@Named
@RequestScoped
@Target(TYPE)
@Retention(RUNTIME)
@Documented
public @interface View {}

Presenter-Annotation:

@Stereotype
@Named
@Target(TYPE)
@Retention(RUNTIME)
@Documented
public @interface Presenter {}

Presenter-Instance:

@Presenter
public class BikeGaragePresenter {

    BikeGarageView view;

    protected BikeGaragePresenter(){}

    public BikeGaragePresenter(BikeGarageView view){
        assert view != null;
        this.view = view;
    }


    public void save(){
        System.out.println(view.getOwner());
    }

    public void setView(BikeGarageView view) {
        this.view = view;
    }   
}

视图实例:

@View
public class BikeGarageBB implements BikeGarageView {

    @Inject
    private BikeGaragePresenter presenter;

    @PostConstruct
    public void init(){
        this.presenter.setView(this);
    }

    private String owner;

    public void setOwner(String owner) {
        this.owner = owner;
    }

    @Override
    public String getOwner() {
        return this.owner;
    }

    @Override
    public void displayMessage(String message) {


    }

    public void save(){
        presenter.save();
    }
}

现在我的问题是:我可以以某种方式将这个样板代码(init-method)提取到注释中(有点类似于 Aspects)吗?我不太了解如何编写注释...我通常只使用它们:-D

编辑:更准确地说:我可以将注释用作装饰器吗?

【问题讨论】:

  • Presenter 没有使用 RequestScoped 注释 - 对吗?在这种情况下,BikeGaragePresenter 将是单例的。
  • 我不想对实际的前端技术有任何依赖(例如,对 rcp-app 也使用相同的演示者)。我认为 RequestScope 来自 Servlet-API。但是是的,presenter 不能是单例(每个视图都需要一个新的 Presenter)。
  • 是的,它不会是单例,因为默认范围是 @Dependendent,所以每次注入 BikeGaragePresenterit 时都会是一个新 bean。
  • 您是否考虑过使用 InjectionPoint CDI bean 来让您的 bean 了解其注入上下文?
  • 不...我刚开始使用 CDI。你能举个例子吗?

标签: java annotations mvp cdi


【解决方案1】:

实现您想要的最简单的方法是在演示者中延迟注入(以避免循环注入)视图。它看起来像这样:

Presenter-Instance:

@Presenter
public class BikeGaragePresenter {

    BikeGarageView view;

    @Inject
    @Any
    Instance<BikeGarageView> viewInstances;

    public BikeGarageView getView()
    {
        return viewInstances.get();
    }       

    public void save(){
        System.out.println(view.getOwner());
    }


}

视图实例:

@View
public class BikeGarageBB implements BikeGarageView {

    @Inject
    private BikeGaragePresenter presenter;

    private String owner;

    public void setOwner(String owner) {
        this.owner = owner;
    }

    @Override
    public String getOwner() {
        return this.owner;
    }

    @Override
    public void displayMessage(String message) {


    }

    public void save(){
        presenter.save();
    }
} 

【讨论】:

  • 非常感谢。今天晚些时候我会试试这个。我的第一印象是,这种方法与我的没有太大区别,但看起来更复杂(与将自身设置在演示者中的 @PostConstruct 方法相比)。除了所有东西都注入之外,还有什么其他的好处吗?
  • 有点不同,因为它带来了解耦(您的视图不必访问您的演示者)。可以增强以支持多个视图(使用限定符和所有视图的父类或接口)。你也可以创建一个装饰器来实现这个功能,并在装饰器中定义 getView() 方法。
  • 感谢您的解释。装饰器是我要找的。我可以请你用这个模式来增强你的例子吗?是否可以使用注解来做到这一点?
  • 我终于有时间测试你的方法,但我有一个小问题......或者至少 Weld 有。据我了解注入代码:由 CDI 创建的符合接口的任何实例都将被注入到 Instaces,然后我抓住一个。但是 Weld 似乎在某种循环中丢失了。我得到一个 java.lang.NoClassDefFoundError: org/jboss/weld/util/reflection/Formats$6 和很多调试输出(我在视图构造函数中添加了一个 sysout)虽然应该只有一行。不幸的是,我订购的 CDI 书还没有印刷 ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多