52

我已经阅读了 CDI 中的 @Produces 注释,但我不了解它的用法。

public class Resources {

// Expose an entity manager using the resource producer pattern
@SuppressWarnings("unused")
@PersistenceContext
@Produces
private EntityManager em;                                        // 

@Produces
Logger getLogger(InjectionPoint ip) {                            // 
    String category = ip.getMember()
                        .getDeclaringClass()
                        .getName();
    return Logger.getLogger(category);
}

@Produces
FacesContext getFacesContext() {                                 // 
    return FacesContext.getCurrentInstance();
}

}

取自: http ://www.jboss.org/jdf/quickstarts/jboss-as-quickstart/guide/GreeterQuickstart/#GreeterQuickstart-

容器如何知道调用生产者方法?如果我注入一个EntityManager,容器如何调用@produces EntityManager?以及如何调用 getLogger 生产者方法?

我也看不出经历所有麻烦的理由。

4

2 回答 2

82

CDI 规范的第 3.3 节对@Produces注释的使用进行了很好的高级概述:

生产者方法充当要注入的对象的来源,其中:

• 要注入的对象不需要是 bean 的实例,或者
• 要注入的对象的具体类型可能在运行时有所不同,或者
• 对象需要一些不由 bean 构造函数执行的自定义初始化。

例如,假设您想在 Java EE 托管组件(如实体管理器)和其他 CDI 组件之间架起一座桥梁,您可以使用@Produces注释。另一个好处是您可以避免在@PersistenceContext整个数据域层中重复注释。

class A {
    @PersistenceContext       // This is a JPA annotation
    @Produces                 // This is a CDI 'hook'
    private EntityManager em; 
}

class B {
   @Inject                    // Now we can inject an entity manager
   private EntityManager em;
}

另一个方便的用途是绕过没有 CDI 友好 bean 的库(例如,没有默认构造函数):

class SomeTPLClass {
    public SomeTPLClass(String id) {
    }
}

class SomeTPLClassProducer {
    @Produces
    public SomeTPLClass getInstance() {
        return new SomeTPLClass("");
    }
}

生成的 Javadoc 还显示了一个有趣的(但相当罕见的情况)生成命名集合,该集合以后可以注入其他托管 bean(非常酷):

public class Shop { 
    @Produces @ApplicationScoped 
    @Catalog @Named("catalog") 
    private List<Product> products = new LinkedList<Product>(8);

    //...
}

public class OrderProcessor {
    @Inject
    @Catalog
    private List<Product> products;
}

容器负责处理所有标有@Produces 注解的方法和字段,并且通常会在部署应用程序时执行此操作。然后,处理后的方法和字段将根据需要用作托管 bean 的注入点解析的一部分。

于 2013-05-14T04:10:00.570 回答
1

这个例子对我来说不太适用。它的工作是一个小的调整:

@Alternative
class SomeTPLClass {
    public SomeTPLClass(String id) {
    }
}

class SomeTPLClassProducer {
    @Produces
    public SomeTPLClass getInstance() {
        return new SomeTPLClass("");
    }
}

所以我不得不在我的课堂上添加@Alternative以消除@Default有两个选项的错误。

于 2017-11-07T14:48:22.160 回答