未调用 EJB 3.1 单例会话 Bean @PreDestroy 方法

Posted

技术标签:

【中文标题】未调用 EJB 3.1 单例会话 Bean @PreDestroy 方法【英文标题】:EJB 3.1 Singleton Session Bean @PreDestroy method not called 【发布时间】:2015-01-21 17:25:38 【问题描述】:

我有一个单例会话 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 正在锁定对其余单例(包括预销毁)方法的访问。默认情况下,@Singleton 上的所有方法都是@Lock LockType.Write。由于您已经在手动同步,您应该尝试使用 @Lock(LockType.Read) [2]

注释您的 @Singleton 类

[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

【讨论】:

不幸的是,我正在使用 Java EE 6,其中 ManagedExecutorService 不可用。任何想法?顺便说一句,这里不需要@Lock,因为我一直在做 Bean Managed Concurrency。 我的问题的最终解决方案是升级到 Java EE 7,并使用 单线程 ExecutorServiceManagedThreadFactory。 @NBW 的建议将我带到了那里,我将其标记为已接受的答案。

以上是关于未调用 EJB 3.1 单例会话 Bean @PreDestroy 方法的主要内容,如果未能解决你的问题,请参考以下文章

一篇博客带你拿下吉林大学JAVAEE期末(七:会话Bean)

一篇博客带你拿下吉林大学JAVAEE期末(七:会话Bean)

一篇博客带你拿下吉林大学JAVAEE期末(七:会话Bean)

sessionscoped 托管 bean 与有状态 ejb

雷林鹏分享:EJB有状态会话Bean

雷林鹏分享:EJB有状态会话Bean