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

时间:2017-03-20 09:02:03

标签: java maven tomcat vaadin timertask

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

Whit quartz:

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>

Contlistener:

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>

2 个答案:

答案 0 :(得分:3)

使用Quartz确实是以编程方式执行此操作的最简单方法之一,因为您已经运行了服务器/应用程序。

话虽如此,在任何Java Web应用程序中使用它显然独立于您可能使用的UI技术(包括Vaadin)和恕我直言,最好单独推断它。

为了完整起见,我将完成将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

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

<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

此时,在部署/启动应用程序之后,可以从&#34;标准&#34;获得Quartz调度程序实例。调度程序工厂可以在Web应用程序的ServletContext对象的默认键下使用:

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...
}

请注意,我们已使用上面 quartz.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();
        }
    }
}

安排作业

鉴于可用的Scheduler,我们需要定义:

  1. 所谓的&#34;细节&#34;一份工作
    1. 触发这些细节
    2. 并使用它们来最终安排工作:

      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()

      自动安排作业

      现在,精明的人会注意到我们还没有调用调度功能。我们可以 &#34;手动&#34; ,通过定义某种管理servlet / UI,并在用户交互时调用上面定义的调度方法或,如果我们可以在servlet上下文启动时使用预定义/硬编码值 自动 ,就像我们使用调度程序一样。

      假设我们想在servlet上下文启动时自动安排主要作业。我们再次至少有两个选择:

      1. 实现一个ServletContextListener ,它执行/调用上面的调度例程,并确保在我们声明的QuartzInitializerListener之后调用它以便创建调度程序
        1. 扩展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...
                  }
              }
          }
          
        2. 但是,如果我们使用(更好的,恕我直言)第二个选项,我们需要在 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作业。随意学习并提前询问!

答案 1 :(得分:2)

为此创建了一个虚拟样板项目。 看看https://github.com/dhruvpsaru/quartz-test

代替xml我使用的注释我认为是更好的方式

pom.xml是

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>web-app</groupId>
  <artifactId>app</artifactId>
  <packaging>war</packaging>
  <version>1.0</version>
  <name>app Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
    </dependency>

    <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>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.21</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.7</version>
    </dependency>

  </dependencies>
  <build>
    <finalName>app</finalName>
  </build>
</project>

创建一个servlet为

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;


    @WebServlet(
            name = "AnnotatedServlet",
            description = "A sample annotated servlet",
            urlPatterns = {"/test"}
    )
    public class AppServlet extends HttpServlet {

        private final Logger logger = LoggerFactory.getLogger(this.getClass());

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

            logger.info("------------------------in servlet-------------------");

            PrintWriter writer = resp.getWriter();
            writer.println("<html>Hello, I am a Java servlet!</html>");
            writer.flush();
        }
    }

创建一个作业类

package quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SimpleJob implements Job {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        logger.info("This is my first quartz job!!");
    }
}

并创建一个侦听器

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import static org.quartz.TriggerBuilder.newTrigger;

@WebListener
public class QuartzScheduler implements ServletContextListener {

    private Scheduler scheduler = null;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public void contextInitialized(ServletContextEvent servletContextEvent) {
        logger.info("Context Initialized");

        try {
            // Setup the Job class and the Job group
            JobDetail job = JobBuilder.newJob(SimpleJob.class).withIdentity(
                    "CronQuartzJob", "Group").build();

            // Create a Trigger that fires every 5 minutes.
            Trigger trigger = newTrigger()
                    .withIdentity("TriggerName", "Group")
                    .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
                    .build();

            // Setup the Job and Trigger with Scheduler & schedule jobs
            scheduler = new StdSchedulerFactory().getScheduler();
            scheduler.start();
            scheduler.scheduleJob(job, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        logger.info("Context Destroyed");
        try
        {
            scheduler.shutdown();
        }
        catch (SchedulerException e)
        {
            e.printStackTrace();
        }
    }
}

现在去mvn clean package并部署target/app.war