定时器服务空

TimerService null

老实说,我在这里遗漏了一些东西。我不知道如何创建 TimerService 对象的实例。它始终为空。我没有构造函数,因为它是一个接口。我不能使用创建方法。 @Resource 好像没有给它分配任何东西。

我正在尝试设置一个简单的编程计时器,它每 X 分钟执行一次任务。超时持续时间可能因配置而异,配置可能会在整个运行时发生变化。我正在使用 WebLogic 12 Web 应用程序。

我目前拥有的:

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

@Singleton
public class TimerBean {
    @Resource
    protected TimerService timerService;

    public TimerBean(){
        System.out.println("TimerBean constructor " + timerService);
    }

    @Timeout
    public void timeoutHandler(Timer timer){
        String name = timer.getInfo().toString();
        System.out.println("Timer ticked. Name=" + name);
    }


    public void startOrModifyTimer(long initialExpiration, long interval, String name) {
        System.out.println("Start or modify " + timerService);
    }
}

这输出:

TimerBean constructor null

& 然后在服务器之后 运行 如果我调用开始或修改:

Start or modify null


编辑: 我通过制作 TimerBean @Singleton & @Startup 并用 @PostConstruct 方法替换构造函数来让它工作。

然而,当我尝试使用它的方法时它为 TimerService 实例化了一个对象,它给我 java.lang.IllegalArgumentException: Unknown bean state 0 没有任何信息...

如果您尝试使用字段注入,那么您将依赖框架在对象已经被实例化并设置字段后出现,因此它将始终 在构造函数中为 null。您可以在 @PostConstruct 方法中执行您需要的任何逻辑,或者,我的强烈偏好,将 TimerService 作为构造函数参数而不是直接注入字段。

为此我最终使用了 Timer & TimerTask。想不通 TimerService。那好吧。似乎工作正常。

任何好奇的人:

    long interval = minutes*60*1000;
    long delay = interval;

    if(prevTask != null){
        delay = System.currentTimeMillis() - prevTask.scheduledExecutionTime(); //time left of previous setting
        prevTask.cancel();
        delay = interval - delay; //difference in time left & new interval
        if(delay <=0) //if by new setting should've already ran, so run it ASAP...
            delay = 2000;

        logger.info(String.format("DB dump was already scheduled before. Set dump delay to %s minutes & setting new schedule to every %s minutes.", delay/60/1000, minutes));
    }

    TimerTask task = new TimerTask(){
        private SimpleDateFormat ft = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss SSS");
        private int minutes;
        public TimerTask initialize(int minutes){
            this.minutes = minutes;
            return this;
        }
        public void run() {
            try {
                logger.info(String.format("Doing scheduled %s dump to DB. (Configured to occur every %s minutes.)", ft.format(new Date(this.scheduledExecutionTime())), minutes));
                dumpToDB();
            } catch (NamingException | SQLException e) {
                e.printStackTrace();
            }
        }
    }.initialize(minutes);

    timer.schedule(task, delay, interval);
    prevTask = task;

@PostConstruct is never called. @Inject is not either (and Im unsure if I did it right)

I got it to work by making the TimerBean @Singleton & @Startup & replacing constructor with @PostConstruct method.

chrylis 是对的。根据您的描述,您似乎是通过构造函数实例化了 TimerBean

结果是您自己管理生命周期,容器无法再处理此实例并注入。

将您的 TimerBean 注入到您要使用它的 class 中(例如 Session),或者像您一样使用它:

@Singleton
@Startup
public class TimerBean { .. } 

这些注释的组合基本上在应用程序服务器启动序列期间创建一个 TimerBean 实例。

顺便说一句。 @PostConstruct 的构造函数是错误的想法,它在 运行 时间内的行为可能真的不可预测(不确定是否可能,但您使用此组合创建了循环实例化)。