Spring 调度系统简介
一说到调度,Java 程序员马上就会想到 Quartz,但 Quartz 学习使用起来相对比较复杂。其实spring 3.0版本后,自带了一个定时任务工具,而且使用简单方便,不用配置文件,可以动态改变执行状态。也可以使用cron表达式设置定时任务,但被执行的类要实现Runnable接口。
第一个调度系统
- POM.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.suoron.springmvc</groupId>
<artifactId>myShop-jobs</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
</dependencies>
</project>
- 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">
<!-- 字符集过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring mvc 前端控制器 -->
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
- spring-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:annotation-config />
<context:component-scan base-package="com.suoron.springmvc.service.impl"/>
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler" init-method="initialize">
<property name="poolSize" value="2"/>
</bean>
</beans>
代码说明:
ThreadPoolTaskScheduler 是一个专门用于调度任务的类,实际上也实现了Spring的TaskExecutor接口,因此单个实例可以尽快用于异步执行,也可以用于计划和可能重复执行。
- 4.spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<description>Spring MVC Configuration</description>
<!-- 加载配置属性文件 -->
<!-- <context:property-placeholder ignore-unresolvable="true" location="classpath:config.properties"/> -->
<!-- 使用 Annotation 自动注册 Bean,只扫描 @Controller -->
<context:component-scan base-package="com.suoron.springmvc.controller"/>
<!-- 配置注解驱动 可以将request参数与绑定到controller参数上 -->
<mvc:annotation-driven />
<!-- html视图解析器 必须先配置freemarkerConfig,注意html是没有prefix前缀属性的-->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath">
<value>/WEB-INF/views/html</value>
</property>
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="htmlviewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="suffix" value=".html" />
<property name="order" value="0"></property>
<property name="contentType" value="text/html;charset=UTF-8"></property>
</bean>
<!-- 定义视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
<property name="prefix" value="/WEB-INF/views/jsp/" />
<property name="suffix" value=".jsp" />
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/> <!-- 不能用jstl的那个 -->
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="order" value="1"></property>
</bean>
<!-- 静态资源映射 -->
<mvc:resources mapping="/static/**" location="/static/" cache-period="31536000"/>
<mvc:resources mapping="/json/**" location="/json/" cache-period="31536000"/>
</beans>
- 任务类
package com.suoron.springmvc.utils;
public class ScheduleTask implements Runnable {
private String id;
public String getId(){
return id;
}
public ScheduleTask(String id){
this.id = id;
}
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() +":" + id+ " 开始执行!");
}
}
- 调度接口实现类
package com.suoron.springmvc.service.impl;
import com.suoron.springmvc.service.JobService;
import com.suoron.springmvc.utils.ScheduleTask;
import org.springframework.scheduling.concurrent.ScheduledExecutorTask;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
@Service
public class JobServiceImpl implements JobService {
@Resource
ThreadPoolTaskScheduler taskExecutor;
private static Map<String, ScheduledFuture<?>> scheduledFutureMap = new HashMap<String, ScheduledFuture<?>>();
public void startJob(ScheduleTask scheduledTask, Date startTime) {
ScheduledFuture<?> scheduledFuture = taskExecutor.schedule(scheduledTask, startTime);
scheduledFutureMap.put(scheduledTask.getId(), scheduledFuture);
System.out.println(startTime.getTime() + " 定时任务:" + scheduledTask.getId() + " 添加成功!!");
}
public void cancelJob(ScheduleTask scheduledTask) {
ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(scheduledTask.getId());
if(scheduledFuture != null && !scheduledFuture.isCancelled()){
scheduledFuture.cancel(false);
System.out.println(System.currentTimeMillis() + " 定时任务:" + scheduledTask.getId() + " 取消成功!!");
}
scheduledFutureMap.remove(scheduledTask.getId());
}
}
代码说明:
TaskScheduler接口下定义了6个方法
- schedule(Runnable task, Trigger trigger);
指定一个触发器执行定时任务。可以使用CronTrigger来指定Cron表达式,执行定时任务
CronTrigger t = new CronTrigger("0 0 10,14,16 * * ?");
taskScheduler.schedule(this, t);
- schedule(Runnable task, Date startTime);
指定一个具体时间点执行定时任务,可以动态的指定时间,开启任务。只执行一次。(比Timer好用多了。早发现这接口就好了。。。)- scheduleAtFixedRate(Runnable task, long period);
立即执行,循环任务,指定一个执行周期(毫秒计时)
PS:不管上一个周期是否执行完,到时间下个周期就开始执行- scheduleAtFixedRate(Runnable task, Date startTime, long period);
指定时间开始执行,循环任务,指定一个间隔周期(毫秒计时)
PS:不管上一个周期是否执行完,到时间下个周期就开始执行- scheduleWithFixedDelay(Runnable task, long delay);
立即执行,循环任务,指定一个间隔周期(毫秒计时)
PS:上一个周期执行完,等待delay时间,下个周期开始执行- scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
指定时间开始执行,循环任务,指定一个间隔周期(毫秒计时)
PS:上一个周期执行完,等待delay时间,下个周期开始执行
- 动态添加任务WEB接口
@Controller
public class JobController {
@Resource
JobService jobService;
@RequestMapping(value = "/job/start",method = RequestMethod.GET)
@ResponseBody
public String startJob(String id,long second){
ScheduleTask scheduleTask = new ScheduleTask(id);
jobService.startJob(scheduleTask,new Date(System.currentTimeMillis()+(second*1000)));
return "success";
}
@RequestMapping(value = "/job/cancel",method = RequestMethod.GET)
@ResponseBody
public String testPage(String id){
ScheduleTask scheduleTask = new ScheduleTask(id);
jobService.cancelJob(scheduleTask);
return "success";
}
}
网友评论