我发现在仅有一个Bean<T>
的情况下(该Bean是基于Class<T>
创建的),通过BeanManager
获得自动创建的CDI托管bean实例通常有两种一般方法:
通过
BeanManager#getReference()
方式,这种方式在代码片段中更为常见:Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class)); TestBean testBean1 = (TestBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
通过
Context#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()
总是创建一个全新的代理实例,而 Context#get()
如果之前已经创建了代理实例,则重用现有的代理实例。当上面的代码在现有的 TestBean
实例的操作方法中执行时,这一点就很明显了:
System.out.println(testBean1 == testBean2); // false
System.out.println(testBean1 == this); // false
System.out.println(testBean2 == this); // true
Context#get()
方法的javadoc非常明确:
返回某个上下文类型的现有实例,或通过调用Contextual.create(CreationalContext)创建一个新实例并返回它。
而BeanManager#getReference()
方法的javadoc则没有具体说明:
获取某个bean和bean类型的上下文引用。
这让我感到困惑。你何时使用其中一个?无论哪种方式,你都需要一个Bean<T>
实例,从而获得所需的bean类和bean范围作为额外的参数。在这种情况下,我无法想象为什么它们需要从外部提供。
我可以想象Context#get()
更加内存高效,因为它不会不必要地创建另一个代理实例来引用同一底层的bean实例,而只是找到并重用现有的代理实例。
这使我产生了以下问题:在什么情况下BeanManager#getReference()
比Context#get()
更有用?它常常显示在代码片段中,并经常被推荐作为解决方案,但即使已经存在一个代理,它也会不必要地创建一个新的代理。
Context#get()
实际上并不返回任何代理。我相信我被增强的子类误导了。现在这确实更有意义了。如果你实际上需要一个可序列化的代理,请使用BeanManager#getReference()
。如果您不需要可序列化的代理和/或需要通过反射探索实例,则使用Context#get()
。谢谢您的答案! - BalusC