当前位置: 首页 > 知识库问答 >
问题:

获取CDI托管bean实例的规范方法:BeanManager#getReference()vs Context#get()

令狐跃
2023-03-14

我认为有两种一般的方法可以通过BeanManager获取自动创建的CDI托管bean实例,当仅具有一个Bean时

>

  • 通过BeanManager#getReference(),通常在代码段中显示:

    java prettyprint-override">Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class));
    TestBean testBean1 = (TestBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
    

    通过上下文#get(),这在代码段中很少显示:

    Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class));
    TestBean testBean2 = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean));
    

    实际上,它们最终做了完全相同的事情:返回对当前CDI托管bean实例的代理引用,并在范围中不存在bean实例时自动创建该实例。

    但是它们的做法有点不同:BeanManager#getReference()总是创建一个全新的代理实例,而上下文#get()则重用以前创建过的现有代理实例。当在现有TestBean实例的操作方法中执行上述代码时,这一点很明显:

    System.out.println(testBean1 == testBean2); // false
    System.out.println(testBean1 == this); // false
    System.out.println(testBean2 == this); // true
    

    Context#get()的javadoc在以下方面非常明确:

    返回特定上下文类型的现有实例,或通过调用上下文类型创建新实例。创建(CreationContext)并返回新实例。

    BeanManager#getReference() 的javadoc对此不够明确:

    获取特定bean和该bean的特定bean类型的上下文引用。

    这让我很困惑。你什么时候用这个或那个?对于这两种方法,您都需要Bean

    我可以想象Context#get()更节省内存,因为它不会不必要地创建另一个代理实例来引用相同的底层bean实例,而只是找到并重用现有的代理实例。

    这让我想到了以下问题:BeanManager#get参考()到底什么时候比Context#get()更有用?它更经常显示在片段中,也更经常被推荐为解决方案,但它只会不必要地创建一个新的代理,即使一个代理已经存在。

  • 共有3个答案

    钮博裕
    2023-03-14

    这在将CDI与javafx集成时非常有用,因为我需要引用正确的作用域对象,而不是依赖作用域的代理。。。

    我使用producer方法获得一个javaFX节点,该节点被注入到控件中,如下所示:

    @Inject
    @ApplicationScoped
    @FXMLFile("javafx/wares.fxml")
    @FXMLController(WaresController.class)
    Parent wares;
    

    但是当使用BeanManager#getReference()时,我得到的代理会“吃掉”FXMLLoader(getContext)设置的所有值。找到解决问题的方法。

    Thnx用于此

    濮阳唯
    2023-03-14

    我有一个使用getReference()方法获取引用的单例。尽管单例已经初始化,但每次使用getReference()时,通过getReference()创建的代理都会调用@PostConstruct。

    @Startup
    @ApplicationScoped
    @Singleton
    
    @PostConstruct
    private void initialize() {}
    

    通过切换到getContext()。方法,则不再进行不必要的@PostConstruct代理调用。

    商品
    2023-03-14

    BeanManager#getInformation为您提供了一个客户端代理的新实例,但是客户端代理会将方法调用转发到特定上下文的当前上下文实例。一旦您获得代理并保留它,方法调用将在当前实例上被调用(例如当前请求)。如果上下文实例不可序列化,它也很有用——客户端代理将在反序列化后重新连接。

    BeanManager#getContext在没有客户端代理的情况下获取目标实例。您仍然可以在类名中看到Weld的代理,但这是一个提供拦截和修饰的增强子类。如果bean未被拦截或修饰,那么这将是给定bean的普通实例。

    通常(1)更合适,除非您有一个需要直接访问目标实例(例如访问其字段)的特殊用例。

    1) BeanManager#getReference将返回一个“上下文引用”,并为bean提供一个正常的作用域代理。如果一个bean与@SessionScoped一样

    @SessionScoped User user;
    

    然后上下文引用用户将指向当前会话的每个调用的相应用户实例(上下文实例)。两个不同的Web浏览器对user.getName()的两个不同调用将为您提供不同的答案。

    2) Context#get()将返回内部“Context Instance”的值,而不使用正常的作用域代理。这通常是用户不应该自称的。如果您以这种方式获得“Bob”的用户用户,并将其存储在@ApplicationScopedbean或静态变量中,那么它将始终保持为用户“Bob”-即使是来自其他浏览器的web请求!您将得到一个直接的、非代理的html" target="_blank">实例。

     类似资料:
    • 我想从方法中检索注释(自定义编写的注释)。通常我可以通过访问 但是如果bean由CDI容器管理(我使用的是OpenWebBeans),那么类在运行时会得到增强。然后我必须使用超类来请求注释。目前,我试图通过在类名中查找“$$”来检测是否管理该类。但对我来说,这似乎是一个非常肮脏的解决方案。 有什么好方法可以从CDI管理的bean中检索注释吗? 详细地说,我的代码是这样的:我创建了一个注释“Cool

    • 我正计划将一个web应用程序从使用JSF托管bean转换为使用CDI托管bean。我知道我需要做以下工作: 在WEB-INF中添加空beans.xml文件。 将所有JSF@ManagedBean替换为CDI@Named Annotations。 用CDI或OmniFaces作用域注释替换所有JSF作用域注释。 将所有JSF@ManagedProperty替换为CDI@Inject Annotati

    • 我的JavaEE应用程序中有一个单例类。我通过使用注释类并让CDI处理所有事情来实现这一点。 我的问题是,我是否可以防止这个类的意外手动实例化,因为CDI要求我有一个非私有的无参数构造函数? “经典”非CDI解决方案将有一个私有构造函数、一个静态字段和一个返回此实例的静态工厂方法。

    • 我有一个@SessionScoped CDIBean,用于跟踪web应用程序中的用户会话信息。有没有办法从另一个@ApplicationScoped bean中找到这个bean的所有对象?

    • 我有一个会话范围的CDI托管bean: 在某个流之后,我需要从会话中删除这个bean,对于该流,我使用了以下代码,如下面的答案所示: 但是,它不起作用,仍然留在会话中。 我是否遗漏了什么?

    • 主要内容:实例,运行测试结果以下代码显示了如何进行bean注入。 我们先定义一个消息bean,它有一个字符串属性来存储消息。 然后我们再定义另一个托管bean,并使用注解注入。 实例 打开 NetBean8.2,创建一个名为: InjectManagedBeans 的工程,并加入以下文件代码。 以下是文件:UserBean.java 中的代码 - 以下是是文件:index.xhtml 中的代码 - 以下是文件:Message