【问题标题】:Start & Stop a ScheduledExecutorService in Java EE environment using servlet使用 servlet 在 Java EE 环境中启动和停止 ScheduledExecutorService
【发布时间】:2014-10-03 22:01:14
【问题描述】:

我们有一个需求,我们需要使用一个简单的 servlet 应用程序通过 JMX 监控远程 JVM 详细信息。所以到目前为止在独立应用程序中所做的事情是

1) 创建一个 JMX 连接器并获取内存数据 --> 完成 2)我们需要不断监控和获取记录 (2.1 > 可以被视为持续延迟的计划任务并将记录插入 DB 或 2.2> 如果是,JMX 是否提供历史记录,如果是,则访问哪个 MBean 以获取信息?)。

这里我打算用一个接口来注册域名,照着做。有来自 JSP 的启动和停止按钮。功能是当我们单击启动时,系统将运行调度程序(ScheduledExecutorService)并在后台捕获记录以提供历史记录。当用户点击停止时,调度程序必须停止后台进程。问题是我们如何控制和获取调度器的对象?

1) 换句话说,我们如何通过 servlet 启动和停止 ScheduledExecutorService ?从一个 servlet 启动一个线程并从另一个 servlet 停止一个线程以执行特定任务?

2) 如果我们有一个集群/负载平衡的环境怎么办?

目前正在考虑将每个 ScheduledExecutorService 添加到 HashMap 中,关键是任务对象和值是使用 SingleTon 设计模式的 ScheduledExecutorService。是否有任何默认方法。 SingleTon 的整个循环处于集群/负载平衡环境中,我们可能无法获取适当的更新对象。

期待您的宝贵建议。

【问题讨论】:

    标签: java jakarta-ee scheduledexecutorservice start-stop-daemon


    【解决方案1】:

    如果在 java ee 7 上,请尝试使用 javax.enterprise.concurrent.ManagedScheduledExecutorService

    然后你可以进行资源注入,并使用类似于下面的代码启动任务。

    @Resource
    ManagedScheduledExecutorService mses;
    
    public void startTask() {
        mses.scheduleAtFixedRate(runnable, 10, 10, SECONDS);
    }
    

    在 Java EE 6 中,您可以使用 timerservice API 创建/删除 servlet

    【讨论】:

    • +1,我正在使用 Java 6。很少有问题,1)Wrt 假设可运行是从 servlet A 启动的任务的上述示例,Servlet B 如何停止可运行任务本身而不是其他任务?好像我没有错 servlet 将是无状态的,我们不共享任何对象。 2)wrt to TimeService API,你建议我创建一个 EJB,保持状态并解决它?
    • 不,我会创建可以通过名称识别的计时器。我将添加一个示例,说明我认为它如何工作。但今天不支持。
    • 以上是 2)。 1)我会使用 shutdownNow() 来获取所有任务,删除应该停止的任务,然后重新安排其余的任务。我将尝试添加更完整的示例。但是今天没时间
    • +1。 TY 在您之间提出建议,同时您通过示例帮助我理解,我将根据建议尝试作业并尝试放置真实场景。如果我能够取得一些成功,将在这里分享。因此,如果他们发现类似的情况,它也可能对其他人有所帮助
    • 我正在跨多个 (ec2) 实例(在负载均衡器后面)运行应用程序。我仍然不太明白 ManagedScheduledExecutorService 将如何允许我跨实例调度任务。你能详细说明吗?还是我误会了?
    【解决方案2】:

    ServletContext

    ServletContext 表示您的整个 Web 应用程序在 Servlet 容器中运行。正如Servlet spec 所承诺的,在servlet 处理第一个HTTP 请求之前建立上下文。 HttpSession 代表每个用户的工作会话(从技术上讲,是通过您的 servlet 代码的线程),ServletContext 代表所有这些用户的范围。

    要挂钩到 servlet 上下文的设置和拆卸,请实现 ServletContextListener。提示:通过使用 @WebListener 注释标记它来自动部署您的侦听器。该接口需要一对方法,在处理第一个 Servlet 请求之前设置 Web 应用程序以及拆除 Web 应用程序时调用每个方法。

    提示:这种拆卸方法是关闭ScheduledExecutorService 的好地方。与您的执行程序服务关联的线程可能会在您的 Web 应用程序结束后继续存在。您可能不希望这种情况发生。

    看到这个问题:How to get and set a global object in Java servlet context

    另请参阅 BalusC 的 this nice summary of Servlet scope

    获取 servlet 上下文

    您可以通过首先访问其ServletConfig 来访问当前servlet 的ServletContext

    // … in your Servlet, such as its request handler methods like `doGet` …
    ServletContext sc = this.getServletConfig().getServletContext() ;
    

    那么在ServletContextListener 中,我们如何访问servlet 上下文?当调用侦听器上的两个方法中的任何一个时,都会传递一个ServletContextEvent。从那里拨打ServletContextEvent::getServletContext()

    将对象存储为 servlet 上下文中的“属性”

    那么在哪里存储您的网络应用程序的全局变量,例如您的ScheduledExecutorService? servlet 上下文有一个从StringObject 的内置映射。这些被称为“属性”。调用setAttribute( String , Object ) 存储属性映射。因此,为您的ScheduledExecutorService 起一个名称,以便在此地图中使用密钥。

    ScheduledExecutorService sec = … ; // Instantiated somewhere in your code. 
    …
    String key = "myScheduledExecutorServiceForXYZ" ;
    sc.setAttribute( key , sec );  // Storing the executor service as a generic `Object` for use later.
    

    稍后您可以以同样的方式获取您的ScheduledExecutorService。您需要从Object 转换为已知类,在本例中为ScheduledExecutorService

    Object o = sc.getAttribute( key ); // Fetch the `ScheduledExecutorService` from the servlet context’s built-in map of attributes.
    
    // Cast to known class. If in doubt, test first with [`instanceOf`][11].
    ScheduledExecutorService sec = ( ScheduledExecutorService ) o ; 
    

    您可以通过调用ServletContext::getAttributeNames 来获取所有存储属性名称的列表。

    范围图

    这是我的一个图表,用于了解 Servlet 环境中的范围层次结构。注意每一层作用域都有它的属性集,它自己的StringObject 的映射。沿着图表向下看,每组属性的生命周期都较短。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-24
      • 2013-08-01
      相关资源
      最近更新 更多