EJB 3.1. Синглтон-сессионный компонент @PreDestroy, метод не вызван
У меня есть компонент Singleton Session Bean, выполняющий фоновые задачи:
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@TransactionManagement(TransactionManagementType.BEAN)
@Startup
public class TaskQueue {
private static final Logger LOGGER = Logger.getLogger("TaskQueue");
@Resource
private SessionContext sessionContext;
private final ArrayList<Runnable> tasks = new ArrayList<Runnable>();
private boolean running = false;
@PostConstruct
public void postConstruct() {
LOGGER.info("postConstruct");
running = true;
sessionContext.getBusinessObject(TaskQueue.class).taskLoop();
}
@PreDestroy
public void preDestroy() {
LOGGER.info("preDestroy");
running = false;
synchronized (tasks) {
tasks.notifyAll();
}
}
public void addTask(Runnable r) {
synchronized (tasks) {
tasks.add(r);
tasks.notifyAll();
}
}
@Asynchronous
public void taskLoop() {
while (running) {
Runnable task;
synchronized (tasks) {
LOGGER.info("Fetching next task...");
if (tasks.isEmpty()) {
try {
LOGGER.info("Task queue is empty. Waiting...");
tasks.wait();
LOGGER.info("Resumed");
continue;
} catch (InterruptedException e) {
break;
}
}
task = tasks.remove(0);
}
LOGGER.info("Executing task...");
task.run();
}
running = false;
LOGGER.info("Task queue exited");
}
}
Когда я попытался остановить модуль, отменить его или остановить сервер, preDestroy()
метод не был вызван, и процесс остановки / отмены развертывания не будет продолжен. Единственный способ остановить сервер - убить процесс Java.
Я использую Jboss EAP 6.0.
Что не так с моим кодом? Как это исправить, или как можно альтернативно выполнить обработку очереди фоновых задач в EJB 3.1?
1 ответ
Во-первых, управление собственными потоками запрещено спецификацией EE. Вы можете сделать это, но вы должны знать, что вы нарушаете спецификацию, и понимать все присущие им последствия. Вместо этого вы должны изучить использование службы Managed Executor [1].
С учетом вышесказанного, я подозреваю, что здесь происходит то, что ваш taskLoop блокирует доступ к остальным методам Singletons (включая pre-destroy). По умолчанию все методы @Singleton являются @Lock LockType.Write. Поскольку ваша синхронизация уже выполняется вручную, попробуйте аннотировать класс @Singleton с помощью @Lock(LockType.Read) [2].
[1] https://docs.oracle.com/javaee/7/api/javax/enterprise/concurrent/ManagedExecutorService.html
[2] https://docs.oracle.com/javaee/6/api/javax/ejb/LockType.html