Сделайте метод внутри EJB @Schedule так, чтобы он вызывался только один раз - PullRequest
1 голос
/ 23 апреля 2020

Итак, у меня относительно простой EJB. Я хочу каждые десять секунд проверять наличие pdf-файла в указанном c месте и при обнаружении его отправлять письмо. Работают нормально и, как и ожидалось, но я всегда получаю два одинаковых электронных письма вместо одного. Код выглядит так:

@Stateless
public class TimerBean {

    private EmailService emailService ;
    private boolean fileNotFound;

    public TimerBean(){
       this.fileNotFound= true;
       emailService = new EmailService();
    }

    @Schedule(second = "*/10", minute = "*", hour = "*")
    public void searchForPdf(){
       PDFChecker pdfChecker = new PDFChecker("directoryPath");
       String pdf =  pdfChecker.getPdfFile();
       processSendMail(pdf);
    }

    private void processSendMail(String pdf){
        if (!pdf.equals("") & this.fileNotFound){
            GlassfishLogger.log("Inside processSendMail. The fileNotFound variable is " + this.fileNotFound);
            this.fileNotFound= false;
            emailService.sendMail("dummyMail", "Dummy", "Pdf Found "+pdf);
        } 
    }
}

Метод processSendMail выполняется дважды и как-то this.fileNotFound остается true. Я получаю 2 электронных письма, а затем this.fileNotFound устанавливается на false. Я попытался использовать AtomicBoolean, а также сделать бин @Singleton (или @Lock (LockType.Write) как sugested здесь ). Что я делаю не так и как заставить этот код отправлять только одно письмо?

Обновление

Я добавил журнал внутри метода processSendMail и это результаты:

enter image description here


enter image description here

1 Ответ

1 голос
/ 23 апреля 2020

Вы делаете 2 ошибки здесь, вы должны сначала внимательно прочитать руководство по EJB и их жизненному циклу. Первая ошибка: EJB - @Stateless, поэтому он не сохраняет свой статус при каждом запуске запланированной задачи.

Вторая ошибка - инициализация логического значения по умолчанию внутри конструктора. Вы не можете доверять конструктору, поскольку контейнер может снова использовать istance EJB. Вы должны инициализировать его в метод, помеченный @PostConstruct

. Определение бина как @Singleton сохранит статус, и в любом случае использование следующего метода инициализации является хорошей практикой:

@PostConstruct 
public void init() {

    fileNotFound = true;
}

См. Также:

Oracle S Java EE Tutorial - Enterprise Beans

...