定时任务,这个刚开始接触是在定时导数据,当时要求将某个数据库中的数据,导入另一个表中,这样就写程序,写执行java程序的shell 脚本 最后在linux的crontab 中指定shell 脚本的定时执行。而之后又知道有Quartz 这个定时框架,在后台换公司发现公司有使用定时但使用的是spring 自带的,一查才知道spring3.0 后spring才有了这个功能,下面我们就看看spring 的定时功能。
下面先来看一个超级简单的实例
一、简单的实例1
1、超级简单的目录结构
2、spring 的配置文件application.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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-lazy-init="true">
<description>Spring </description>
<!-- Enables the Spring Task @Scheduled programming model -->
<task:executor id="executor" pool-size="50" />
<task:scheduler id="scheduler" pool-size="100" />
<task:annotation-driven executor="executor"
scheduler="scheduler" />
<!-- 配置自定义任务 -->
<bean name="scrapydTask" lazy-init="false" class="com.test.Test"></bean>
<!-- <bean name="salaryTask" lazy-init="false" class="com.beizhi.hrd.sys.task.SalaryTask"></bean>
<bean name="createAttenTask" lazy-init="false" class="com.beizhi.hrd.sys.task.CreateAttenTask"></bean> -->
</beans>
这个实例中最主要的和最多的东西都在这个配置文件中,
(1)、比如要引入tasx命名空间:
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
(2)、task:annotation-driven 设置:
<task:executor id="executor" pool-size="50" />
<task:scheduler id="scheduler" pool-size="100" />
<task:annotation-driven executor="executor"
scheduler="scheduler" />
task:executor 任务执行器,pool-size定义线程池大小, task:scheduler 任务调度器,pool-size 定义线程池大小!
(3)、定时任务的设置:<bean name="scrapydTask" lazy-init="false" class="com.test.Test"></bean>
其中name 是唯一的 而class 就是要执行定时任务的类
3、定时任务执行类
package com.test;
import org.springframework.scheduling.annotation.Scheduled;
public class Test {
// 这里的时间和linux crontab中写的格式是一样的
@Scheduled(cron = "0 0/1 * * * *")
void schedule(){
System.out.println("1234");
}
}
看到这个类是不是看着有点不一样哈哈,注意第一要有@ Scheduled 来注释 schedule方法,cron 中的时间定义格式和linux中的crontab 是一样的。
4、web.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>hrdTask</display-name>
<!-- Spring ApplicationContext配置文件的路径,可使用通配符,多个路径用,号分隔
此参数用于后面的Spring Context Loader -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:/config/application.xml
</param-value>
</context-param>
<!--Spring的ApplicationContext 载入 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
ok 到这里就结束了如果你把它配置到服务器上并启动服务,在cron中定义的时间就会执行 schedule 方法。
总结: 在写spring的定时任务时一定要注意第一spring的版本要在3.0 以上,第二我们在spring的配置文件中一定要引入task 命名空间,第三我们要配置task 、第四我们要写定时任务类并配置到spring的配置文件中,第五 我们写的执行类要的schedule 方法上一定要有@Scheduled 注解,其他的和平时使用时的配置没有什么区别。
二、spring +mybatis 整合使用定时向数据库中导入数据
我这里的demo 就是将controller 层相当于用定时任务程序来替代了,后面的其他的都是一样的,下面我们来看看
1、整体结构:
从整体结构可以看出,变化了的只有controller 层即消失了而多了个task 任务执行类,前端的配置文件没了,除了这些其他的什么都没有改变
2、spring配置文件ApplicationContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- 加载配置JDBC文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<!--使用自动注入的时候要 添加他来扫描bean之后才能在使用的时候 -->
<context:component-scan base-package="com.website.service ,com.website.dao" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- mybatis配置文件路径 -->
<property name="configLocation" value="" />
<!-- 实体类映射文件路径,在开发中映射文件肯定是多个所以使用mybatis/*.xml来替代 -->
<property name="mapperLocations" value="classpath:mybatis/UserMapping.xml" />
</bean>
<!--其实这里类的实例就是mybatis中SQLSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0">
<ref bean="sqlSessionFactory" />
</constructor-arg>
</bean>
<!-- 定义事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 下面使用aop切面的方式来实现 -->
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
<!--配置事务传播性,隔离级别以及超时回滚等问题 -->
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<!--配置事务切点 -->
<aop:pointcut id="services"
expression="execution(* com.website.service.*.*(..))" />
<aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
</aop:config>
<!-- 任务线程池配置 -->
<task:executor id="executor" pool-size="50" />
<task:scheduler id="scheduler" pool-size="100" />
<task:annotation-driven executor="executor" scheduler="scheduler" />
<!--定时任务类 -->
<bean name="scrapydTask" lazy-init="false" class="com.website.task.Task"></bean>
</beans>
我们发下spring 的配置文件中除了添加了定时问题相关的配置外,没有修改任何东西,所以说spring 定时任务的使用就是用定时任务类来取代controller 层,spring和mybatis的配置信息都在所以后面的spring 和mybatis的配置都不会改变的,但是要注意使用spring的定时功能时要引入xmlns:task="http://www.springframework.org/schema/task"
3、web.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>website2</display-name>
<!-- 加载spring容器配置 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 设置Spring容器加载配置文件路径 程序的入口-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/ApplicationContext.xml
</param-value>
</context-param>
</web-app>
我们发现这里变化很大,没有了springmvc 的前端控制器,没有了springmvc的配置文件路径,没有了过滤器等这些前端配置,只有一个spring 配置文件路径的配置。
4、定时任务执行类:
package com.website.task;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.website.service.UserService;
/**
* @author WHD data 2016年7月3日
*/
@Component
public class Task {
// 自动注入
@Autowired
private UserService userService;
// 设置执行时间
@Scheduled(cron = "0 0/1 * * * *")
void schedule() {
Map<String, String> map = new HashMap<String, String>();
map.put("id", "whd6");
map.put("name", "whd6");
map.put("password", "whd6");
// 调用service层的方法向数据库中插入数据
userService.saveUser(map);
System.out.println("123");
}
}
总结:
使用spring 的定时功能挺方便的,下面总结一下流程:
1、web.xml 配置文件
这个配置文件是程序的入口,其中配置了spring 配置文件的路径,同时在启动服务(tomcat……)时会加载解析这个文件
2、spring 配置文件,这个文件中配置了spring需要的东西同时可以配置mybatis 的配置以及事务,定时任务等的配置
3、如果是spring和mybatis 整合的则需要配置mybatis的映射文件
4、定时任务执行类的编写,注意这里的类名要和spring 配置文件写的那个定时任务的类名称要一致不然的话,找不到就不会执行了。
总的一句话来说,之前你不管是使用 springmvc+spring+mybatis 还是 springmvc+spring+hibernate 那些配置文件你都可以不用修改,只需要在spring 配置文件中引入xmlns:task="http://www.springframework.org/schema/task" 同时写定时任务,使用定时任务类来取代controller 来调用service 层的方法。
当然上面说的那是在刚学习的时候或不熟悉的情况下可以这样修改,当我们熟悉了后,看到多余的代码我们会很烦,这时你可以吧web.xml配置文件中除了指定spring配置文件的路径的配置外,可以吧其他所有配置都删除,具体的可以参考上面的demo,而spring+mybatis 或hibernate 的配置就不要修改了。
注意点:
1、必须是spring3.0以上版本
2、spring配置文件中一定要引入task 命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
3、spring配置文件中一定要定义定时任务
4、写的定时任务类名称要和spring配置文件中的定时任务类名称一致
5、定时任务类的方法名称以及注解要注意添加
package com.website.task;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.website.service.UserService;
/**
* @author WHD data 2016年7月3日
*/
@Component
public class Task {
// 自动注入
@Autowired
private UserService userService;
// 设置执行时间
@Scheduled(cron = "0 0/1 * * * *")
void schedule() {
Map<String, String> map = new HashMap<String, String>();
map.put("id", "whd6");
map.put("name", "whd6");
map.put("password", "whd6");
// 调用service层的方法向数据库中插入数据
userService.saveUser(map);
System.out.println("123");
}
}
这里的@Scheduled注解以及schedule 方法名称必须这样,因为spring是继承自jdk的Executor接口的,当然方法的重写也不能改变方法名了!
<task:executor id="executor" pool-size="50" />
<task:scheduler id="scheduler" pool-size="100" />
这个是配置任务线程池,也就是执行定时任务的线程数,如果定时任务很多的话,不可能一个任务创建一个线程,需要线程池来管理线程,而使用线程池中的线程来执行这些定时任务,线程池中线程数量按照业务需求来调整。
6、如果设置为每几秒钟执行一次,如果设置的时间间隔比任务执行的时间还短的话他是不会出现重复执行的,因为他的时间间隔是从任务执行结束后开始计算的。