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

时间:2017-06-12 06:32:35

标签: java java-ee ejb cdi

不确定如何标题这个问题,但让希望描述可以给出更好的解释。我正在寻找一种方法来注释ejb方法或cdi方法与自定义注释,如“@Duration”或某些aaand,以便在给定的持续时间后花费太长时间来杀死方法执行。我猜一些伪代码会让一切都清楚:

public class myEJBorCdiBean {

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

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

有点超时机制,我不知道是否已经有类似这样的东西,我是javaEE世界的新手。

先谢谢你们

2 个答案:

答案 0 :(得分:3)

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

  

企业bean不得尝试管理线程。企业   bean不得尝试启动,停止,暂停或恢复线程,或者   更改线程的优先级或名称。企业bean一定不能   尝试管理线程组。

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

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

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

答案 1 :(得分:0)

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

Enterprise容器控制线程池,以及活动线程之间的CPU资源分配。它会在耗时的I / O任务(通常是磁盘访问)期间考虑保留时间。

尽管如此,编程一个启动任务变量是有意义的,因此在复杂任务期间不时地验证该特定任务的持续时间。我建议你编写一个本地的,可运行的任务,从任务队列中选择计划任务。我在Glassfish下运行的Java Enterprise后端应用程序中有这方面的经验。

首先是界面定义 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中实现批处理作业调度程序,使用注释来控制结束任务时间限制。