EJB 3计时器问题

时间:2010-11-27 00:13:51

标签: java jboss ejb

我正在使用JBoss 4.2.3和JDK 1.5。我创建了一个无状态EJB,其目的是在指定的时间段(以毫秒为单位)后删除文件。

EJB代码是:

import java.io.File;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;

import org.jboss.annotation.ejb.LocalBinding;

@Stateless
@LocalBinding(jndiBinding = "TimedFileDeletion")
public class TimedFileDeletionBean implements TimedFileDeletionBeanLocal {

    @Resource
    TimerService timerService;

    File fileToDelete;

    public void setRequiredInfo(long intervalDuration, File fileToDelete) {
        timerService.createTimer(intervalDuration, "Created new timer");
        this.fileToDelete = fileToDelete;
    }

    @Timeout
    public void timeout(Timer timer) {
        System.out.println("Timeout occurred");

        if(fileToDelete.exists()) {
            fileToDelete.delete();
        }
    }
}

本地界面是:

import java.io.File;

public interface TimedFileDeletionBeanLocal {

    public void setRequiredInfo(long intervalDuration, File fileToDelete);
}

当我通过Web容器(我使用Stripes框架)调用bean时,在指定的时间之后调用timeout方法,但它只打印“Timeout occurred”,它不会删除文件并引发异常。这是控制台输出:

INFO  [STDOUT] Timeout occurred
ERROR [TimerImpl] Error invoking ejbTimeout: javax.ejb.EJBException: java.lang.NullPointerException

任何建议都将受到赞赏。

2 个答案:

答案 0 :(得分:0)

可能存在问题的一件事是您将setRequiredInfo方法传递给File的引用。然后使用调试器在本地存储该引用,我将在计时器触发时验证引用值是否相同。我怀疑它可能不再是引用的文件相同,或者File对象可能是瞬态的。

此外,只是对EJBTimers和JBoss的一点警告。这个版本的JBoss为每个带有计时器的EJB都会旋转一个线程。因此,如果您要使用这些EJB删除500个文件,JBoss将启动500个线程。这种行为虽然不受欢迎,但确实符合EJB规范(在实现上不明确)。如果容器重新启动并且计时器仍在等待触发,则将重新创建这些线程。

答案 1 :(得分:0)

在无状态会话bean中,不维护会话状态。无状态bean实例变量在调用之间共享,因此它们可能重叠。

因此,即使您使用setRequiredInfo()设置文件,在超时时它会将fileToDelete设为null。

在执行操作之前尝试检查null。 以下是一些代码段可能会对您有所帮助。

class FileUtility {

// Make singleton class to store list of files to delete

public static List<File> files;

//-- get/set accessing methods

}

// ---------------------

public void setRequiredInfo(long intervalDuration, File fileToDelete) {
        timerService.createTimer(intervalDuration, fileToDelete.getName()+Math.random());
        FileUtility.files.add(fileToDelete);
}

// ---------------------

@Timeout
    public void timeout(Timer timer) {
        System.out.println("Timeout occurred");

    for(File fileToDelete : Fileutility.files){

        if(fileToDelete.exists()) {
            fileToDelete.delete();
        }
    }
}