问题: 我需要每24小时运行一个java函数。它从一个站点获取一些数据,并将该数据推送到数据库。不,我想知道如何创建将在Tom Cat服务器上成功运行的计时器。我有maven / Vaadin项目。所以现在我想知道如何启动将在不在现场的服务器上运行的Timer功能。
Whit quartz:
计时器:
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>
答案 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,我们需要定义:
和强>
并使用它们来最终安排工作:
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上下文启动时自动安排主要作业。我们再次至少有两个选择:
或强>
扩展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作业。随意学习并提前询问!
答案 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