java - 如何在Maven/Vaadin项目的服务器后台运行Java类?

标签 java maven tomcat vaadin timertask

问题:
我需要每24小时运行一个Java函数。它从一个站点获取一些数据,并将该数据推送到数据库。不,我不知道如何创建将在Tom Cat服务器上成功运行的计时器。我有Maven / Vaadin项目。因此,现在我想知道如何启动将在不在站点上的服务器上运行的Timer函数。

惠特石英:

arhucture

计时器:

public class TimerData implements org.quartz.Job {


    SchedulerFactory sf = new StdSchedulerFactory();
    Scheduler sched = sf.getScheduler();


    public TimerData() throws SchedulerException, InterruptedException {
        sched.scheduleJob(job, trigger);
        sched.start();
        Thread.sleep(90L * 1000L);
        sched.shutdown(true);
    }
    // define the job and tie it to our HelloJob class
    JobDetail job = newJob(TimerData.class)
            .withIdentity("job1", "group1")
            .build();
    // compute a time that is on the next round minute
    Date runTime = evenMinuteDate(new Date());

    // Trigger the job to run on the next round minute
    Trigger trigger = newTrigger()
            .withIdentity("trigger1", "group1")
            .startAt(runTime)
            .build();

    // Tell quartz to schedule the job using our trigger


    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // Say Hello to the World and display the date/time
        System.out.println("Hello World! - " + new Date());

        try {
            FillData.povni();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


依赖关系:

 <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
  </dependency>
  <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz-jobs</artifactId>
        <version>2.2.1</version>
  </dependency>


竞争者:

public class ContListener implements ServletContextListener,
        HttpSessionListener, HttpSessionAttributeListener {
    private ServletContext context = null;
    // Public constructor is required by servlet spec
    public ContListener() {
    }

    // -------------------------------------------------------
    // ServletContextListener implementation
    // -------------------------------------------------------
    public void contextInitialized(ServletContextEvent sce) {
      /* This method is called when the servlet context is
         initialized(when the Web application is deployed). 
         You can initialize servlet context related data here.
      */
        context = sce.getServletContext();
    }

    public void contextDestroyed(ServletContextEvent sce) {
      /* This method is invoked when the Servlet Context 
         (the Web application) is undeployed or 
         Application Server shuts down.
      */
    }

    // -------------------------------------------------------
    // HttpSessionListener implementation
    // -------------------------------------------------------
    public void sessionCreated(HttpSessionEvent se) {
      /* Session is created. */
    }

    public void sessionDestroyed(HttpSessionEvent se) {
      /* Session is destroyed. */
    }

    // -------------------------------------------------------
    // HttpSessionAttributeListener implementation
    // -------------------------------------------------------

    public void attributeAdded(HttpSessionBindingEvent sbe) {
      /* This method is called when an attribute 
         is added to a session.
      */
    }

    public void attributeRemoved(HttpSessionBindingEvent sbe) {
      /* This method is called when an attribute
         is removed from a session.
      */
    }

    public void attributeReplaced(HttpSessionBindingEvent sbe) {
      /* This method is invoked when an attibute
         is replaced in a session.
      */
    }
}


Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <context-param>
        <param-name>quartz:config-file</param-name>
        <param-value>quartz.properties</param-value>
    </context-param>

    <context-param>
        <param-name>quartz:shutdown-on-unload</param-name>
        <param-value>true</param-value>
    </context-param>

    <context-param>
        <param-name>quartz:wait-on-shutdown</param-name>
        <param-value>true</param-value>
    </context-param>

    <context-param>
        <param-name>quartz:start-on-load</param-name>
        <param-value>true</param-value>
    </context-param>

    <listener>
        <listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class>
    </listener>
    <listener>
        <listener-class>ContListener</listener-class>
    </listener>
</web-app>

最佳答案

实际上,使用Quartz是以编程方式执行此操作最直接的方法之一,因为您已经在运行服务器/应用程序。

话虽如此,在任何Java Web应用程序中使用它显然都与您可能使用的UI技术(包括Vaadin)和IMHO无关,因此最好单独进行推理。

为了完整起见,我将在下面介绍将Quartz添加到Maven管理的Java Web应用程序中涉及的所有步骤。

将Quartz添加为Maven依赖项

在pom.xml中添加一个依赖项就足够了:

<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz</artifactId>
  <version>2.2.3</version>
</dependency>


在Servlet容器中初始化Quartz Scheduler

通过声明Servlet上下文侦听器和web.xml描述符的几个上下文参数,自动创建默认的Quartz调度程序并在Servlet上下文初始化时初始化(如http://www.quartz-scheduler.org/documentation/quartz-2.x/cookbook/ServletInitScheduler.html所示):

<context-param>
  <param-name>quartz:config-file</param-name>
  <param-value>/quartz.properties</param-value>
</context-param>
<context-param>
  <param-name>quartz:shutdown-on-unload</param-name>
  <param-value>true</param-value>
</context-param>
<context-param>
  <param-name>quartz:wait-on-shutdown</param-name>
  <param-value>false</param-value>
</context-param>
<context-param>
  <param-name>quartz:start-scheduler-on-load</param-name>
  <param-value>true</param-value>
</context-param>
<listener>
  <listener-class>
    org.quartz.ee.servlet.QuartzInitializerListener
  </listener-class>
</listener>


您还应该通过提供基本的quartz.properties文件来配置调度程序:

org.quartz.scheduler.instanceName = LenartScheduler
org.quartz.scheduler.instanceId = LenartScheduler.ID
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore


此时,在部署/启动应用程序之后,可以在Web应用程序的ServletContext对象中的默认键下从“标准”调度程序工厂获得Quartz调度程序实例,该工厂可供您使用:

StdSchedulerFactory schedFact = (StdSchedulerFactory)
  ctx.getAttribute("org.quartz.impl.StdSchedulerFactory.KEY");
try {
    Scheduler scheduler = schedFact.getScheduler("LenartScheduler");
    // schedule Jobs here...
} catch (SchedulerException e) {
    // properly handle the exception...
}


请注意,我们已经使用了上面的crystal.properties文件中指定的调度程序名称(LenartScheduler)。同样,请注意,在这一点上,尚未计划任何内容–我们所拥有的只是一个准备使用的计划程序。

创建工作类别

通过实现org.quartz.Job可以轻松完成:

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class MainJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext)
      throws JobExecutionException {

        // Simulate job execution for 5 seconds...
        try {
            System.out.println("Executing job in background...");
            Thread.sleep(1000 * 5 /* secs */);
            System.out.println("Done executing job.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


安排工作

给定可用的调度程序,我们需要定义:


所谓的工作“细节”





触发这些细节


并同时使用它们来最终安排工作:

private void scheduleMainJob(Scheduler scheduler) throws SchedulerException {
    requireNonNull(scheduler);

    JobDetail jobDetail = newJob(MainJob.class).storeDurably()
                                               .withIdentity("MAIN_JOB")
                                               .withDescription("Main Job to Perform")
                                               .build();
    Trigger trigger = newTrigger().forJob(jobDetail)
                                  .withIdentity("MAIN_JOB_TRIGG")
                                  .withDescription("Trigger for Main Job")
                 .withSchedule(simpleSchedule().withIntervalInSeconds(15).repeatForever())
                 .startNow().build();

    scheduler.scheduleJob(jobDetail, trigger);
}


请注意指定何时触发作业的简单方法(对于您的简单情况,至少不涉及cron表达式)。为了举例说明,我每15秒触发一次作业,然后让它运行5次-如果您想每24小时(即一天一次)触发一次,则可以使用simpleSchedule()。withIntervalInHours(24)。 repeatForever()。

自动安排作业

现在,精明的人会注意到我们还没有调用调度功能。我们可以通过定义某种管理servlet / UI并在用户交互时调用上述定义的调度方法来“手动”执行此操作,或者,如果可以使用预定义/硬编码的值,则可以在servlet上下文启动时自动进行就像我们使用调度程序一样。

假设我们要在Servlet上下文启动时自动调度主作业。同样,我们至少有2个选择:


实现一个ServletContextListener,它执行/调用上述调度例程,并确保在我们声明的QuartzInitializerListener之后调用该例程,以创建调度程序


要么


在创建调度程序之后,扩展QuartzInitializerListener类以调度我们的主要工作;这样,我们不必担心上下文侦听器的调用顺序:

public class LenartQuartzListener extends QuartzInitializerListener {

    @Override
    public void contextInitialized(ServletContextEvent evt) {
        super.contextInitialized(evt);
        // At this point, the default functionality
        // has been executed hence the scheduler has been created!
        ServletContext ctx = evt.getServletContext();
        StdSchedulerFactory factory = (StdSchedulerFactory)
          ctx.getAttribute("org.quartz.impl.StdSchedulerFactory.KEY");
        try {
            scheduleMainJob(factory.getScheduler("LenartScheduler"));
        } catch (SchedulerException e) {
            // properly handle the exception...
        }
    }
}



但是,如果我们使用(更好的,恕我直言)第二个选项,则确实需要在web.xml文件中指定新的Quartz侦听器,而不是旧的:

<listener>
  <listener-class>com.lenard.web.LenartQuartzListener</listener-class>
</listener>


在这一点上,不用担心所使用的UI技术(Vaadin等),将自动初始化Quartz调度程序,并在(Web)应用程序启动时调度作业。

如果使用Vaadin

如今,无需使用web.xml描述符就可以初始化基于Vaadin的Web应用程序。如果是这种情况,请注意,现在您需要添加web.xml文件,该文件指定我们一直在讨论的Quartz初始化。但这不会与任何Vaadin特定的东西冲突……

我在https://github.com/octavian-nita/so/tree/master/so-42899401-quartz-maven-tomcat创建了一个基于Vaadin的小型项目,以说明如何使用Vaadin UI手动调度/取消调度Quartz作业。随时研究它,并提前询问!

关于java - 如何在Maven/Vaadin项目的服务器后台运行Java类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42899401/

相关文章:

maven - Maven/Gradle方法来计算包括所有传递依赖项的依赖项总大小

java - 如何使用 maven/travis 将二进制文件打包、压缩并部署为 zip/tar.gz 从 github 存储库到 bintray.com 通用存储库

tomcat - 如何修改带有阀的Tomcat的响应头?

java - Android:如何显示带有回调的相机预览?

java - 如何在 Netbeans 平台上获取项目类型?

java - Builder Design Pattern 为具有大量参数的方法创建通用方法

macos - IntelliJ IDEA 未选取 Maven 主目录 (M2_HOME)

java - Tomcat 6 : Importing utility class from WEB-INF/classes

tomcat - 使用 Shibboleth IdP 和 Tomcat 进行单点登录

使用阻塞 I/O 的 Java 线程池服务器