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