我认为,只有一个Bean<T>
开始时,有两种通用方法可以通过BeanManager
获取自动创建的CDI托管bean实例(基于Class<T>
创建):
按BeanManager#getReference()
,更常见的是Context#get()
片段:
Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class));
TestBean testBean1 = (TestBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
按javadoc,在片段中不常显示:
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()
总是创建一个全新的代理实例,而Context#get()
重用现有的代理实例(如果之前已经创建过)。当上述代码在现有TestBean
实例的操作方法中执行时,这是显而易见的:
System.out.println(testBean1 == testBean2); // false
System.out.println(testBean1 == this); // false
System.out.println(testBean2 == this); // true
Context#get()
的{{3}}非常明确:
返回某个上下文类型的现有实例,或通过调用Contextual.create(CreationalContext)创建一个新实例并返回新实例。
虽然BeanManager#getReference()
的{{3}}对此不够明确:
这让我感到困惑。你什么时候使用这一个?对于需要一个获取某个bean和bean的某个bean类型的上下文引用。
Bean<T>
实例的两种方式,bean类和bean作用域都是可用的,这是另外一个参数所必需的。我无法想象为什么在这种特殊情况下他们需要外部供应。
我可以想象Context#get()
的内存效率更高,因为它不会不必要地创建引用同一底层bean实例的另一个代理实例,而只是查找并重用现有的代理实例。
这让我想到以下问题:BeanManager#getReference()
究竟何时比Context#get()
更有用?它通常以片段形式显示,并且通常被推荐为解决方案,但它只会在不存在的情况下不必要地创建新的代理。
答案 0 :(得分:35)
beanManager#getReference 为您提供客户端代理的新实例,但客户端代理会将方法调用转发到特定上下文的当前上下文实例。 获得代理并保留代理后,将在当前实例上调用方法调用(例如,当前请求)。 如果上下文实例不可序列化,它也很有用 - 客户端代理将在反序列化之后重新连接。
BeanManager#getContext 获取没有客户端代理的目标实例。您仍然可以在类名中看到Weld的代理,但这是一个增强的子类,提供拦截和修饰。如果bean没有被拦截也没有装饰,那么这将是给定bean的普通实例。
通常(1)更合适,除非您有一个特殊的用例,您需要直接访问目标实例(例如访问其字段)。
1)BeanManager#getReference 将返回一个'Contextual Reference',其中包含bean的正常范围代理。
如果bean的@SessionScoped
为
@SessionScoped User user;
然后,上下文引用用户将“指向”每个调用的当前会话的相应用户实例(“上下文实例”)。
来自两个不同网络浏览器的两个不同的user.getName()
调用将为您提供不同的答案。
2)上下文#get()将返回没有正常范围代理的内部“上下文实例”。这通常不是用户应该自称的。如果以这种方式获得“{”的User user
并将其存储在@ApplicationScoped
bean或静态变量中,
那么它将始终是用户“Bob” - 即使是来自其他浏览器的Web请求!您将获得一个直接的,非代理的实例。
答案 1 :(得分:1)
我有一个Singleton,我使用getReference()方法来获取引用。即使单例已经初始化,每次使用getReference()时,通过getReference()创建的代理称为@PostConstruct。
@Startup
@ApplicationScoped
@Singleton
@PostConstruct
private void initialize() {}
通过切换到getContext()。get()方法,不再进行不必要的@PostConstruct代理调用。
答案 2 :(得分:0)
当将CDI与javafx集成时,这非常有用,我需要引用正确的作用域对象原因,而不是依赖范围的代理......
我使用了一个生成器方法来获取一个注入到控制器中的javaFX节点,如下所示:
@Inject
@ApplicationScoped
@FXMLFile("javafx/wares.fxml")
@FXMLController(WaresController.class)
Parent wares;
但是当使用BeanManager#getReference()代理时,我回来“吃掉”FXMLLoader设置的所有值,getContext.get()方式解决了它。
Thnx for this