简体   繁体   English

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

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

Problem: I need to run one java function every 24 h. 问题:我需要每24小时运行一个Java函数。 It get some data from one site and it push that data to database. 它从一个站点获取一些数据,并将该数据推送到数据库。 No i wonder how to create timer which will run successfully on Tom Cat server. 不,我不知道如何创建将在Tom Cat服务器上成功运行的计时器。 I have maven/Vaadin project. 我有Maven / Vaadin项目。 So now i wonder how to start Timer function that will run on server not on site. 因此,现在我想知道如何启动将在不在站点上的服务器上运行的Timer函数。

Whit quartz: 惠特石英:

构架

timer: 计时器:

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: 依赖关系:

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

Using Quartz is, indeed, one of the most straightforward ways of doing this programmatically, since you will already have a server/app running. 实际上,使用Quartz是以编程方式执行此操作最直接的方法之一,因为您已经在运行服务器/应用程序。

Having said that, employing it in any Java web application is, obviously, independent of the UI technology you might use (Vaadin included) and IMHO, it's better to reason about it separately. 话虽如此,在任何Java Web应用程序中使用它显然都与您可能使用的UI技术(包括Vaadin)和IMHO无关,因此最好单独进行推理。

For the sake of completeness, I will go through all the steps involved in adding Quartz to a Maven-managed, Java web application below. 为了完整起见,我将在下面介绍将Quartz添加到Maven管理的Java Web应用程序中涉及的所有步骤。

Adding Quartz as a Maven Dependency 将Quartz添加为Maven依赖项

Adding one dependency in your pom.xml should suffice: pom.xml中添加一个依赖项就足够了:

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

Initializing a Quartz Scheduler in a Servlet Container 在Servlet容器中初始化Quartz Scheduler

A default Quartz scheduler is automatically created and initialized upon Servlet Context initialization (as illustrated at http://www.quartz-scheduler.org/documentation/quartz-2.x/cookbook/ServletInitScheduler.html ) by declaring a servlet context listener and several context parameters to the web.xml descriptor: 通过声明一个Servlet上下文侦听器和一个Servlet上下文初始化(如http://www.quartz-scheduler.org/documentation/quartz-2.x/cookbook/ServletInitScheduler.html所示 ),将自动创建并初始化一个默认的Quartz调度程序。 web.xml描述符的几个上下文参数:

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

You should also configure the scheduler by providing a basic quartz.properties file: 您还应该通过提供基本的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

At this point, after the application has been deployed/started, a Quartz scheduler instance can be obtained from a "standard" scheduler factory available to you under a default key in the web application's ServletContext object: 此时,在部署/启动应用程序之后,可以在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...
}

Note that we've used the scheduler name ( LenartScheduler ) specified in the quartz.properties file above. 请注意,我们使用在quartz.properties指定调度名称(LenartScheduler)上面的文件。 As well, note that at this point, nothing is scheduled yet – all we have is a scheduler ready to be used. 同样,请注意,在这一点上,尚未计划任何内容–我们所拥有的只是一个准备使用的计划程序。

Creating the Job Class 创建工作类别

Easily done by implementing org.quartz.Job : 通过实现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();
        }
    }
}

Scheduling the Job 安排工作

Given the available Scheduler, we need to define: 给定可用的调度程序,我们需要定义:

  1. the so-called "details" of a Job 所谓的工作“细节”

AND

  1. a trigger for those details 触发这些细节

and use them both to finally schedule the job: 并同时使用它们来最终安排工作:

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);
}

Note the simple way of specifying when to trigger the job (no cron expression involved for your simple case, at least not yet). 请注意指定何时触发作业的简单方法(对于您的简单情况,至少不涉及cron表达式)。 For the sake of the example, I am triggering the job every 15 seconds and let it run for 5 -- if you want to trigger it every 24 hours (ie one a day) you can use simpleSchedule().withIntervalInHours(24).repeatForever() . 就本例而言,我每15秒触发一次作业,并让它运行5次-如果您想每24小时(即一天一次)触发一次,则可以使用simpleSchedule()。withIntervalInHours(24)。 repeatForever()

Automatically Scheduling the Job 自动安排作业

Now, the astute will notice that we still haven't called the scheduling functionality just yet. 现在,精明的人会注意到我们还没有调用调度功能。 We could either do it "manually" , by defining some sort of an admin servlet/UI and upon user interaction to call the scheduling method defined above or, if we are OK with using the predefined/hardcoded values, automatically , upon servlet context start up, like we did it with the scheduler. 我们可以通过定义某种管理servlet / UI并在用户交互时调用上述定义的调度方法来“手动”执行此操作 ,或者,如果可以使用预定义/硬编码的值,则可以在servlet上下文启动时自动进行就像我们使用调度程序一样。

Let's say we want to automatically schedule the main job, upon servlet context start up. 假设我们要在Servlet上下文启动时自动调度主作业。 We again have at least 2 options: 同样,我们至少有2个选择:

  1. implement a ServletContextListener that does/calls the scheduling routine above and make sure it is called after the QuartzInitializerListener we've declared in order to have the scheduler created 实现一个ServletContextListener ,它执行/调用上述调度例程,并确保在我们声明的QuartzInitializerListener之后调用该例程,以创建调度程序

OR 要么

  1. extend the QuartzInitializerListener class to schedule our main job just after the scheduler gets created; 在创建调度程序之后, 扩展QuartzInitializerListener类以调度我们的主要工作; this way, we don't have to worry about the order in which the context listeners get called: 这样,我们不必担心上下文侦听器的调用顺序:

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

However, if we're using the (better, IMHO) second option, we do need to specified in the web.xml file our new Quartz listener, instead if the old one: 但是,如果我们使用(更好的,恕我直言)第二个选项,则确实需要在web.xml文件中指定新的Quartz侦听器,而不是旧的:

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

At this point, never mind the UI technology used (Vaadin, etc.), a Quartz scheduler is automatically initialized and a job scheduled upon (web) application start up. 在这一点上,不用担心所使用的UI技术(Vaadin等),将自动初始化Quartz调度程序,并在(Web)应用程序启动时调度作业。

If using Vaadin 如果使用Vaadin

These days, one can initialize a Vaadin-based web application without using a web.xml descriptor. 如今,无需使用web.xml描述符就可以初始化基于Vaadin的Web应用程序。 If that's your case, note that you now need to add the web.xml file that specifies the Quartz initialization we've been talking about. 如果是这种情况,请注意,现在您需要添加web.xml文件,该文件指定我们一直在讨论的Quartz初始化。 But this does not clash with any Vaadin-specific stuff… 但这不会与任何Vaadin特定的东西冲突……

I've created a small Vaadin-based project at https://github.com/octavian-nita/so/tree/master/so-42899401-quartz-maven-tomcat to illustrate how one can manually schedule / unschedule Quartz jobs using a Vaadin UI. 我在https://github.com/octavian-nita/so/tree/master/so-42899401-quartz-maven-tomcat创建了一个基于Vaadin的小型项目,以说明如何使用以下方法手动安排/取消安排Quartz作业Vaadin UI。 Feel free to study it and ask ahead! 随时研究它,并提前询问!

Created a dummy boilerplate project for this. 为此创建了一个虚拟样板项目。 Have a look https://github.com/dhruvpsaru/quartz-test 看看https://github.com/dhruvpsaru/quartz-test

In place of xml I am using annotations that I think is better way 我使用的是我认为是更好方法的注释来代替xml

pom.xml is 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>

Create a servlet as 创建一个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();
        }
    }

Create a job class as 创建一个工作类别为

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!!");
    }
}

and create a listener as 并创建一个侦听器为

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

and now go and do mvn clean package and deploy target/app.war 现在去做mvn clean package并部署target/app.war

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM