Maven / Vaadin项目中服务器后台如何运行 java class?

How to run java class in back ground of server in Maven / Vaadin project?

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

白色石英:

计时器:

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 是以编程方式执行此操作的最直接方法之一,因为您已经有了 server/app 运行ning.

话虽如此,在任何 Java 网络应用程序中使用它显然独立于您可能使用的 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 调度器

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

<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

此时,在应用程序 deployed/started 之后,可以从 Web 应用程序的 ServletContext 对象中的默认键下可用的 "standard" 调度程序工厂获取 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...
}

请注意,我们使用了上面 quartz.properties 文件中指定的调度程序名称 (LenartScheduler)。另外,请注意,此时还没有任何计划——我们所拥有的只是一个可以使用的计划程序。

创建作业Class

通过实施 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();
        }
    }
}

正在安排作业[=​​105=]

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

  1. 所谓"details"一个Job

AND

  1. 这些细节的触发器

并使用它们来最终安排作业:

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

自动安排作业[=​​105=]

现在,精明的人会注意到我们还没有调用调度功能。我们可以通过定义某种管理员 servlet/UI 并在用户交互时调用上面定义的调度方法,或者,如果我们可以使用 predefined/hardcoded 值, 自动 ,在 servlet 上下文启动时,就像我们使用调度程序完成。

假设我们想要在 servlet 上下文启动时自动安排主作业。我们又至少有 2 个选项:

  1. 实现一个 ServletContextListener,does/calls 上面的调度例程,并确保在我们声明的 QuartzInitializerListener 之后调用它,以便创建调度程序

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

    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 调度程序会自动初始化并在(网络)应用程序启动时安排作业。

如果使用 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 作业。欢迎研究并提前提问!

为此创建了一个虚拟样板项目。 看看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();
        }
    }

创建工作 class 作为

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