JavaEE - EJB/CDI 方法持续时间机制

JavaEE - EJB/CDI Method Duration Mechanism

不确定如何给这个问题起标题,但希望描述能给出更好的解释。我正在寻找一种方法来使用自定义注释(如“@Duration”或 aa 等)来注释 ejb 方法或 cdi 方法,以便在给定持续时间后花费太长时间来终止方法执行。我想一些伪代码会让一切变得清晰:

public class myEJBorCdiBean {

@Duration(seconds = 5)
public List<Data> complexTask(..., ...)
{
  while(..)
  // this takes more time than the given 5 seconds so throw execption
}

总而言之,一个方法需要非常长的时间,它会抛出一个给定的持续时间过期错误或类似的错误

有点超时机制,不知道有没有类似的,我是javaEE新手

提前谢谢大家

您不应该在 EJB/CDI 容器中使用线程 API。 EJB 规范明确指出:

The enterprise bean must not attempt to manage threads. The enterprise bean must not attempt to start, stop, suspend, or resume a thread, or to change a thread’s priority or name. The enterprise bean must not attempt to manage thread groups.

托管 bean 及其业务方法的调用必须由容器完全控制,以避免损坏其状态。根据您的用例,将此操作卸载到专用服务(javaee 之外),或者您可以使用 EJB @SingletonSchedule 提出一些半黑客解决方案 - 这样您可以定期检查一些控制标志。如果您在 Wildfly/JBoss 上 运行ning,您可能会为此滥用 @TransactionTimeout 注释 - 因为 EJB 方法默认情况下是事务感知的,在事务上设置超时将有效地控制调用超时豆的方法。我不确定其他应用程序服务器如何支持它。

如果异步处理是一个选项,那么 EJB @Asynchronous 可能会有一些帮助:参见 Asynchronous tutorial - Cancelling and asynchronous operation

作为一般建议:不要 运行 在 EJB/CDI 中长时间执行 运行ning 操作。每个请求都会产生一个新线程,线程是有限的资源,你的应用程序将更难扩展和维护(long 运行ning op ~= state),如果你的服务器在方法调用期间崩溃会发生什么,将如何集群环境中的用例工作。再次很难说,在不了解您的用例的情况下,什么是更好的方法,但是研究 java EE 批处理 api、带有消息驱动 bean 的 JMS 或带有 @Asynchronous [= 的异步处理17=]

这是一个非常有意义的想法——将一个复杂的任务限制在一定的执行时间内。在实际的网络计算中,当复杂的搜索任务的持续时间超过最大可接受的时间量时,许多用户将不愿意等待完成。

企业容器控制着线程池,以及CPU-资源在活动线程中的分配。它这样做还考虑了耗时 I/O-tasks(通常是磁盘访问)期间的保留时间。

尽管如此,对开始任务变量进行编程是有意义的,因此在复杂任务期间不时地验证该特定任务的持续时间。我建议你编写一个本地的、可运行的任务,它从作业队列中挑选预定的任务。我在 Glassfish 下的 Java 企业后端应用程序 运行 中有这方面的经验。

首先是接口定义Duration.java

// Duration.java 
@Qualifier 
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Documented 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Duration {
    public int minutes() default 0; // Default, extended from class, within path 
}

现在遵循作业的定义TimelyJob.java

// TimelyJob.java    
@Duration(minutes = 5)
public class TimelyJob {

    private LocalDateTime localDateTime = LocalDateTime.now();
    private UUID uniqueTaskIdentifier;
    private String uniqueOwnerId;

    public TimelyJob(UUID uniqueTaskIdentifier, String uniqueOwnerId) {
        this.uniqueTaskIdentifier = uniqueTaskIdentifier;
        this.uniqueOwnerId = uniqueOwnerId;
    }

    public void processUntilMins() {
        final int minutes = this.getClass().getAnnotation(Duration.class).minutes();
        while (true) {
            // do some heavy Java-task for a time unit, then pause, and check total time
            // break - when finished
            if (minutes > 0 && localDateTime.plusMinutes(minutes).isAfter(LocalDateTime.now())) {
                break;
            }
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                System.err.print(e);
            }
        }
        // store result data in result class, 'synchronized'  access
    }

    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

    public UUID getUniqueTaskIdentifier() {
        return uniqueTaskIdentifier;
    }

    public String getUniqueOwnerId() {
        return uniqueOwnerId;
    }        
}

执行定时作业的Runnable任务-TimedTask.java-实现如下:

// TimedTask.java
public class TimedTask implements Runnable {

    private LinkedBlockingQueue<TimelyJob> jobQueue = new LinkedBlockingQueue<TimelyJob>();

    public void setJobQueue(TimelyJob job) {
        this.jobQueue.add(job);
    }

    @Override
    public void run() {
        while (true) {
            try {
                TimelyJob nextJob = jobQueue.take();
                nextJob.processUntilMins();
                Thread.sleep(100);
            } catch (InterruptedException e) {
                System.err.print(e);
            }
         }
      } 
   }

并且在单独的代码中, TimedTask

的凝视
   public void initJobQueue() {
       new Thread(new TimedTask()).start();
   }

此功能实际上在 Java 中实现了批处理作业调度程序,使用注释来控制结束任务时间限制。