Java EE 7:从“非托管”上下文调用EJB方法+事务

时间:2014-12-18 14:51:49

标签: java-ee managed-bean java-ee-7

请考虑以下情况:

1)一个Singleton SchedulerService,其中包括管理/创建一堆JobQueue s

@Startup
@Singleton
public class SchedulerService
{
    @Inject
    private Instance<JobQueue> jobQueueInstance;

    ...

    public JobQueue addQueue(String name)
    {
         JobQueue q = jobQueueInstance.get();
         ....
         return q;
    }
}

2)可能有几个JobQueue人管理/启动/跟进他们的正在运行/待处理的工作:

public class JobQueue implements SchedulerListener
{
    @PersistenceContext(unitName = "...")
    private EntityManager entityManager;

    public void addJob(Job newJob)
    {
       .... entityManager.persist(newJob); ....
       newJob.addSchedulerListener(this);
    }

    ...

    public void deleteJob(Job j)
    {
        ....  entityManager.delete(j); ....
    }

    // part of SchedulerListener, invoked from Job's Thread
    @Override
    public void taskSucceeded(Job job)
    {
        deleteJob(job);
    }

    // part of SchedulerListener, invoked from Job's Thread
    @Override
    public void taskFailed(Job job)
    {
        deleteJob(job);
    }
}

一切正常,entityManager正确@Injected,从其他托管bean调用addJob()deleteJob()时,实体被正确保留/删除。

现在,对于实际的Job执行,我使用的是Cron4j,它不支持CDI。 它启动新的Threads并在该Thread中运行实际的Job。 当作业结束时,它会通过taskSucceeded / taskFailed方法通知我的JobQueue(谁听取了Job终止事件)。

因为这些taskSucceeded / taskFailed方法是从作业线程(不是&#34;容器管理&#34;)中调用的,所以我理解为得到以下例外:

4:46:27,032 ERROR [cob.scheduler.service.JobQueue] (cron4j::scheduler[DEFAULT]::task[442]) Job xxx failed: javax.persistence.TransactionRequiredException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
    at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:869) [wildfly-jpa-9.0.0.Alpha1.jar:9.0.0.Alpha1]
    at org.jboss.as.jpa.container.AbstractEntityManager.merge(AbstractEntityManager.java:567) [wildfly-jpa-9.0.0.Alpha1.jar:9.0.0.Alpha1]
    at cob.scheduler.service.JobQueue.deleteJob(JobQueue.java:287) [classes:]
    at cob.scheduler.service.JobQueue.deleteAndAdvance(JobQueue.java:241) [classes:]
    at cob.scheduler.service.JobQueue.taskSucceeded(JobQueue.java:226) [classes:]
    at it.sauronsoftware.cron4j.Scheduler.notifyTaskSucceeded(Scheduler.java:724) [classes:]
    at it.sauronsoftware.cron4j.TaskExecutor$Runner.run(TaskExecutor.java:500) [classes:]
    at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_45]

我想知道什么是好的方法。基本上我需要以某种方式返回EE容器&#34;,即从EE领域外部调用容器管理方法。

我已阅读ManagedExecutorService,但我不确定这是否适用或如何使用。

此外,我尝试@Inject private JobQueue self;并调用self.deleteJob()而不仅仅是this.deleteJob(),但这会在部署时生成以下异常:

org.jboss.weld.exceptions.DeploymentException: WELD-001443: Pseudo scoped bean has circular dependencies. Dependency path: 
  - Managed Bean [class cob.scheduler.service.JobQueue] with qualifiers [@Any @Default],
  - [BackedAnnotatedField] @Inject private cob.scheduler.service.JobQueue.self,
  - Managed Bean [class cob.scheduler.service.JobQueue] with qualifiers [@Any @Default]
    at org.jboss.weld.bootstrap.Validator.reallyValidatePseudoScopedBean(Validator.java:904)
    at org.jboss.weld.bootstrap.Validator.validatePseudoScopedInjectionPoint(Validator.java:946)
    at org.jboss.weld.bootstrap.Validator.reallyValidatePseudoScopedBean(Validator.java:913)
    at org.jboss.weld.bootstrap.Validator.validatePseudoScopedBean(Validator.java:890)
    at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:148)
    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:165)
    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:529)
    at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68)
    at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:66)
    at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:60)
    at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:53)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) [rt.jar:1.7.0_45]
    ... 3 more

注意:我已经完成了所有工作但是使用了#34;资源本地&#34;交易管理。我认为很容易将其转换为JTA,但唉。

任何指针都会受到赞赏。

1 个答案:

答案 0 :(得分:1)

原来解决方案并不那么难。我们每天都在学习。 Yey!

  1. @将SchedulerService注入JobQueue。这造成了圆形的依赖性,但是很好。
  2. SchedulerService中,制作代理方法deleteJob(JobQueue jq, Job j)。所有这一切都是调用jq.deleteJob(j)
  3. 从“非托管”事件回调中,调用代理schedulerService.deleteJob(this, j)而不是this.deleteJob(j)。通过遍历@Injected代理,Java EE再次启动,为我们和所有其他奇妙的魔法创建交易。
  4. 利润!