我们开始尝试使用CDI实现我们的后端服务.场景是这样的:
部署EAR时启动带有@Startup的EJB.将ApplicationScoped bean注入到此:
@ApplicationScoped
public class JobPlatform {
private PooledExecutor threadHolder;
@Inject @Any
private Instance<Worker> workerSource;
...
Run Code Online (Sandbox Code Playgroud)
bean还有一个Observer方法,当观察到一个事件时,它从Instance workerSource获取一个工作bean并将它放在threadPool上,最终运行完成.
一切都很好.但是......我们已经开始看到垃圾收集问题了.JMAP堆直方图显示,这些工作人员中有许多人闲逛,没有收集垃圾.
我们认为这归结于CDI范围的结合.@Dependant的API页面(http://docs.jboss.org/cdi/api/1.0-SP1/javax/enterprise/context/Dependent.html)更清楚地强化了文档中的内容:
- 将范围@Dependent注入字段,bean构造函数或初始化方法的bean的实例是注入它的bean或Java EE组件类实例的依赖对象.
- 将@Dependent注入到producer方法中的bean的实例是正在生成的生成器方法bean实例的依赖对象.
- 通过直接调用实例获得的具有范围@Dependent的bean实例是Instance实例的依赖对象.
所以,遵循这个:
有没有人使用CDI同意这个?你是否经历过这种垃圾收集的缺乏,如果是这样,你能建议任何解决方法吗?
工作人员不能是ApplicationScoped,但平台必须是.如果我们要创建一个自定义的WorkerScope(嗯哦......)并使用它来注释每个工作类,那么这是否足以分离工作者和实例源之间的依赖关系?
还有一些建议是否有可能破坏CDI范围?我会看一下,但是想要确定范围看起来是否合理.
希望你能帮忙,谢谢.
我正在将2个EAR部署到JBoss AS 7.1.0.Alpha1-SNAPSHOT(后7.0.1.Final版本)上.两者部署都很好.
我在其中一个EAR中的JAR中打包了一个EJB Singleton类:
@Startup
@Singleton
// one of @Local(Store.class), @Remote(Store.class), @LocalBean
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@Transactional(TransactionPropagation.SUPPORTS)
public class StoreFront implements Store {
...
public interface Store {
...
Run Code Online (Sandbox Code Playgroud)
在部署时,它表示EJB绑定到:
"java:app/store-core-2011.1.2-SNAPSHOT/StoreFront"
"java:app/store-core-2011.1.2-SNAPSHOT/StoreFront!uk.co.magus.jam.store.core.Store"
"java:module/StoreFront"
"java:module/StoreFront!uk.co.magus.jam.store.core.Store"
"java:global/store-ear-2011.1.2-SNAPSHOT/store-core-2011.1.2-SNAPSHOT/StoreFront!uk.co.magus.jam.store.core.Store"
"java:global/store-ear-2011.1.2-SNAPSHOT/store-core-2011.1.2-SNAPSHOT/StoreFront"
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.当我尝试通过JNDI从OTHER部署的EAR中的JAR内的非CDI非EJB类查找它时,它只能在'global'下的JNDI名称上找到 - 再次,预期.
但是,当我尝试将结果对象强制转换为实际的接口类时:
Object lookupObject = new InitialContext().lookup(jndiName);
Store store = (StoreFront)lookupObject;
Run Code Online (Sandbox Code Playgroud)
我得到以下异常:
11:17:52,402 ERROR [jam.core.link.LinkListener] (Thread-45) Exception when casting to Store after lookup with [java:global/store-ear-2011.1.2-SNAPSHOT/store-core-2011.1.2-SNAPSHOT/StoreFront]: java.lang.ClassCastException: jam.store.core.Store$$$view1 cannot be cast to jam.store.core.Store
at jam.core.link.LinkListener.getStore(LinkListener.java:108) [core-jar-2011.1.2-SNAPSHOT.jar:]
at jam.core.link.LinkListener.postLoad(LinkListener.java:27) [core-jar-2011.1.2-SNAPSHOT.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_07]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用BeanManager而不是Instance .select().get()创建CDI托管bean的实例.
这被建议作为我已经使用ApplicationScoped bean和他们的家属的垃圾收集的问题的解决方法 - 请参阅CDI应用程序和依赖范围可以合谋影响垃圾收集?对于背景和建议的解决方法.
如果在ApplicationScoped bean上使用Instance编程查找方法,Instance对象和从中获取的任何bean最终都依赖于ApplicationScoped bean,因此共享它的生命周期.但是,如果使用BeanManager创建bean,则会在Bean实例本身上设置句柄,并且显然可以明确地销毁它,我理解这意味着它将被GCed.
我目前的方法是在BeanManagerUtil类中创建bean,并返回Bean,实例和CreationalContext的复合对象:
public class BeanManagerUtil {
@Inject private BeanManager beanManager;
@SuppressWarnings("unchecked")
public <T> DestructibleBeanInstance<T> getDestructibleBeanInstance(final Class<T> type,
final Annotation... qualifiers) {
DestructibleBeanInstance<T> result = null;
Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(type, qualifiers));
if (bean != null) {
CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean);
if (creationalContext != null) {
T instance = bean.create(creationalContext);
result = new DestructibleBeanInstance<T>(instance, bean, creationalContext);
}
}
return result;
}
}
public class DestructibleBeanInstance<T> {
private T instance;
private Bean<T> …Run Code Online (Sandbox Code Playgroud) 我正在尝试在JBoss AS6上的后端服务中使用CDI事件 - 理想情况下是最大程度地重用代码.
我可以从文档中看到我可以通过使用带有成员的限定符来减少必须创建的限定符注释类.
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Type {
TypeEnum value();
}
Run Code Online (Sandbox Code Playgroud)
我可以观察到这一点
public void onTypeAEvent(@Observes @Type(TypeEnum.TYPEA) String eventMsg) {...}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但是,为了进一步减少所需类的数量,我希望有一个EventFirer类,其中抛出的事件的限定符是动态的.没有成员的限定符没有问题:
public class DynamicEventFirer {
@Inject @Any private Event<String> event;
public void fireEvent(AnnotationLiteral<?> eventQualifier){
event.select(eventQualifier).fire("FIRED");
}
}
Run Code Online (Sandbox Code Playgroud)
然后叫做喜欢
dynamicEventFirer.fireEvent(new AnnotationLiteral<Type>() {});
Run Code Online (Sandbox Code Playgroud)
但是,当资格赛成员应该有成员时呢?查看AnnotationLiteral的代码,它肯定是为成员设置的,而class元素注释具有以下示例:
new PayByQualifier() { public PaymentMethod value() { return CHEQUE; } }
Run Code Online (Sandbox Code Playgroud)
这对我来说很有意义 - 你要覆盖注释界面的value()方法.但是,当我自己尝试这个时:
dynamicEventFirer.fireEvent(new AnnotationLiteral<Type>() {
public TypeEnum value() {
return TypeEnum.TYPEA;
}
});
Run Code Online (Sandbox Code Playgroud)
我收到了例外
java.lang.RuntimeException: class uk.co.jam.concept.events.MemberQualifierEventManager$1 does not implement …Run Code Online (Sandbox Code Playgroud) 我正在运行JBoss AS 7.1.0.CR1b.我在standalone.xml中定义了几个数据源,例如
<subsystem xmlns="urn:jboss:domain:datasources:1.0">
<datasources>
<datasource jndi-name="java:/MyDS" pool-name="MyDS_Pool" enabled="true" use-java-context="true" use-ccm="true">
<connection-url>some-url</connection-url>
<driver>the-driver</driver>
[etc]
Run Code Online (Sandbox Code Playgroud)
一切正常.
我正在尝试访问我的代码中包含的信息 - 特别是connection-url和driver属性.
我尝试从JNDI获取数据源,正常情况下,但它似乎不提供对这些属性的访问:
// catches removed
InitialContext context;
DataSource dataSource = null;
context = new InitialContext();
dataSource = (DataSource) context.lookup(jndi);
Run Code Online (Sandbox Code Playgroud)
来自此数据源的Connection对象的ClientInfo和DatabaseMetadata也不包含这些粒度的JBoss属性.
我的代码将在容器中运行,并且数据源已经指定,因此所有代码都应该可用.我已经查看了IronJacamar接口org.jboss.jca.common.api.metadata.ds.DataSource及其实现类,这些接口似乎可以访问我需要的信息,但是我找不到有关如何使用容器内已部署的资源创建此类对象的任何信息(只有impl上的构造函数涉及手动输入所有属性).
JBoss AS 7的命令行界面允许您将数据源导航并列为目录系统.http://www.paykin.info/java/add-datasource-programaticaly-cli-jboss-7/提供了一篇关于如何使用我认为的Java Management API与子系统交互的优秀文章,但这似乎是涉及连接到目标JBoss服务器.我的代码已经在该服务器中运行,所以肯定必须有一个更简单的方法吗?
希望有人可以提供帮助.非常感谢.
我使用普通的旧Java 1.6,并对这两个库感兴趣.
阅读完文档后,我不确定是否存在差异.任何人都可以解释它,或指出一些相关的信息?提前致谢!
cdi ×3
jboss-weld ×3
java ×2
jboss7.x ×2
datasource ×1
ejb ×1
events ×1
guava ×1
jndi ×1
managed-bean ×1
rx-java ×1
scope ×1