我目前正在将库升级到JavaEE 7,我对如何查找和创建(非托管)bean实例有一些疑问。我在这里和互联网上查看了其他一些问题,发现了完全不同的解决方案。我在我的例子中忽略了限定符。
在库的旧实现(对于CDI 1.0)中,我只使用 Lookup#1 - 即使是@Dependent。
查找#1 :使用BeanManager的旧方式#getBeans()
public static <T> T getBean(Class<T> clazz) {
Bean<T> bean = (Bean<T>) _beanManager.resolve(_beanManager.getBeans(clazz));
if(bean.getScope().equals(Dependent.class)) {
throw new IllegalArgumentException("Cdi#getBean(Class) should only be invoked for classes that do not belong to the "
+ "@Dependent scope");
}
CreationalContext<T> ctx = _beanManager.createCreationalContext(bean);
return (T) _beanManager.getReference(bean, clazz, ctx);
}
我添加了if语句,因为我在其他地方读过,不应该以这种方式创建@Dependent范围的bean(没有明确定义的生命周期)。
查找#2 :CDI-1.1-way
public static <T> T getBean(Class<T> clazz) {
return CDI.current().select(clazz).get();
}
Q1 :在CDI 1.1中应首选哪一个(#1或#2)来执行托管bean的编程查找?有什么优点和缺点?还有其他解决方案吗?
依赖/创建#1 :使用Unmanged和UnmanangedInstance
public static <T> UnmanagedInstance<T> getDependentBean(Class<T> clazz) {
return new Unmanaged<>(clazz).newInstance();
}
UnmanagedInstance可以包含在DependentProvider类中,该类在构造函数中调用produce()
,inject()
,postConstruct()
,在destroy方法中调用preDestroy()
,dispose()
(为了进一步简化使用)。
依赖/创造#2 :受DeltaSpike的启发
public static <T> DependentProvider<T> getDependentBean(Class<T> clazz) {
Bean<T> bean = (Bean<T>) _beanManager.resolve(_beanManager.getBeans(clazz));
CreationalContext<T> ctx = _beanManager.createCreationalContext(bean);
T instance = (T) _beanManager.getReference(bean, clazz, ctx);
return new DependentProvider<T>(bean, ctx, instance);
}
返回的提供程序使用destroy()
方法删除创建的实例。
public void destroy() {
bean.destroy(instance, creationalContext);
}
我在DeltaSpike的实现中缺少的是对creationalContext.release()
的调用。这不是必需的吗?
创建#3 :Instance =&gt;只能在托管bean中使用
@ViewScoped
class X implements Serializable {
@Inject Instance<MyObject> _myObjectProvider;
public void doSomething() {
MyObject obj = _myObjectProvider.get();
// ... work with obj
// call _myObjectProvider.destroy(obj) as soon as we're done with the instance of MyObject.
}
}
Q2 :同样,对于非托管“bean”的编程创建,应该首选哪一个(#1或#2,#3)?有什么优点和缺点?还有其他解决方案吗?
最后,我有一个关于如何检查bean是否已经实例化(例如会话范围的bean)的问题。我提出了以下方法(仅适用于非@Dependent):
public <T> boolean existsBeanInstance(String name) {
Bean<T> bean = (Bean<T>) _beanManager.resolve(_beanManager.getBeans(name));
Context beanScopeContext = _beanManager.getContext(bean.getScope());
return beanScopeContext.get(bean) != null;
}
Q3 :这可靠吗?