Spring 定時器的使用---Xml、Annotation、自定義

平常系統開發中定時任務用的很是地廣泛,好比咱們可能想作個定時器去查詢某筆交易的狀態並進行彙總,又或者咱們想在凌晨4點清楚數據庫的相關數據、又或者咱們想在每個月月底0點定時去開啓一個事務對當月、季度的數據作統計作成報表,灰常多呀!我也說不完啦!java

有一點小編對於定時任務的理解,那就是:定時任務只是告訴系統在某個時刻執行某個任務,而至於該任務何時執行完成,這不是定時任務要關心的範圍,定時任務只須要保證某個時刻發出調用某個任務的指令便可。spring

在Java領域定時任務實現的佼佼者就是quartz了,quartz框架在spring 3.0以前用的很普遍,固然如今也是,quartz支持數據持久化以及相應的集羣方式部署,spring 3.0 以後的spring版本本身實現了一套定時任務框架,咱們能夠把看作是quartz的低配版本,它沒有提供對集羣的支持,不過其餘功能已經灰常強大啦!數據庫

跟隨spring傳統,spring本身實現的定時任務框架spring-task同時支持xml和註解方式配置定時任務,固然小編還會講解咱們如何自定義定時任務。翻開spring源碼包咱們能夠發現,其實spring除了自家的spring-task,同時還提供了quartz的集成,關於spring如何集成quartz,請閱讀小編以前寫的一篇文章簡單說說Java 定時任務框架---Quartzspring-mvc

下面我將分別從xml、註解、自定義3個方面講解如何使用spring-task.bash

1、基於xml配置實現spring定時任務

定時任務組件分爲三個:調度器、任務以及執行時間點。咱們須要引入beancontextcore三個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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:aop="http://www.springframework.org/schema/aop"   
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:jee="http://www.springframework.org/schema/jee"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 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.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">  
	<!-- 建立一個調度器 -->
	<task:scheduler id="schedualer"/>
	<!-- 配置任務類的bean -->
	<bean id="xmlTask" class="wokao666.club.spring_task.tasks.XmlTask"></bean>
	<task:scheduled-tasks scheduler="schedualer">
		<!-- 每2秒執行一次 -->
		<task:scheduled ref="xmlTask" method="say" cron="0/2 * * * * ?"/>
	</task:scheduled-tasks>
</beans>
複製代碼

XmlTask.javamvc

package wokao666.club.spring_task.tasks;

import java.text.SimpleDateFormat;

import wokao666.club.spring_task.util.DateFormatter;

/**
 * 基於XML的spring定時任務
 */
public class XmlTask {
    public void say() {
        SimpleDateFormat format = DateFormatter.getDateFormatter();
        System.err.println(format.format(System.currentTimeMillis()) + " I am spring xml-based task!");
    }
}
複製代碼

DateFormatter.javaapp

package wokao666.club.spring_task.util;

import java.text.SimpleDateFormat;

/**
 * 日期格式
 * @author hjw
 *
 */
public class DateFormatter {
    private static volatile SimpleDateFormat formater = null;
    private DateFormatter() {}
    public static SimpleDateFormat getDateFormatter() {
        if(null == formater) {
            synchronized (DateFormatter.class) {
                if(null == formater) {
                    formater = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                }
            }
        }
    return formater;
    }
}
複製代碼

App.java框架

package wokao666.club.spring_task;

import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
 * Hello world!
 *
 */
public class App 
{
    private static ClassPathXmlApplicationContext ctx;
    public static void main( String[] args ) {
            ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
}
複製代碼

程序輸出:

六月 10, 2018 10:47:11 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2328c243: startup date [Sun Jun 10 22:47:11 CST 2018]; root of context hierarchy
六月 10, 2018 10:47:11 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
六月 10, 2018 10:47:12 下午 org.springframework.scheduling.concurrent.ExecutorConfigurationSupport initialize
信息: Initializing ExecutorService  'schedualer'
2018-06-10 10:47:14 I am spring xml-based task!
2018-06-10 10:47:16 I am spring xml-based task!
2018-06-10 10:47:18 I am spring xml-based task!
複製代碼

2、基於註解的spring-task

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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:aop="http://www.springframework.org/schema/aop"   
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:jee="http://www.springframework.org/schema/jee"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 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.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">  
        <!-- 開啓註解驅動 -->
	<task:annotation-driven/>
	<!-- bean 掃描 -->
	<context:component-scan base-package="wokao666.club.spring_task.tasks"></context:component-scan>
</beans>
複製代碼

AnnotationTask.java

package wokao666.club.spring_task.tasks;

import java.text.SimpleDateFormat;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import wokao666.club.spring_task.util.DateFormatter;
/**
 * 測試基於註解的定時任務
 * @author hjw
 */
@Service
public class AnnotationTask {
    @Scheduled(cron="0/2 * * * * ?")
    public void say() {
        SimpleDateFormat format = DateFormatter.getDateFormatter();
        System.err.println(format.format(System.currentTimeMillis()) + " good morning");
    }
}
複製代碼

App.javaDateFormatter.java和上面同樣,程序輸出以下:

六月 10, 2018 10:53:45 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2328c243: startup date [Sun Jun 10 22:53:45 CST 2018]; root of context hierarchy
六月 10, 2018 10:53:45 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
六月 10, 2018 10:53:46 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
信息: Overriding bean definition for bean 'org.springframework.context.annotation.internalScheduledAnnotationProcessor' with a different definition: replacing [Generic bean: class [org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.scheduling.annotation.SchedulingConfiguration; factoryMethodName=scheduledAnnotationProcessor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/scheduling/annotation/SchedulingConfiguration.class]]
六月 10, 2018 10:53:46 下午 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor finishRegistration
信息: No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2018-06-10 10:53:48 good morning
2018-06-10 10:53:50 good morning
2018-06-10 10:53:52 good morning
2018-06-10 10:53:54 good morning
複製代碼

注意到上面輸出No TaskScheduler/ScheduledExecutorService bean found for scheduled processing這句話,由於你能夠傳入一個java.util.Executor線程池對象來實現對異步任務的調用,若是你指定了executor屬性,則spring會默認建立一個SimpleAsyncTaskExecutor對象去執行,executor屬性指定定時任務執行的線程池,強調執行,而scheduler屬性表示任務調度的線程池,由於spring默認是單線程串行調度,若是想容許多線程併發調度,則須要配置scheduler屬性,配置示例以下:

<!-- 調度線程池 -->
<task:scheduler id="scheduler" pool-size="10" />
<!-- 任務執行線程池 -->
<task:executor id="executor" pool-size="10" />
<task:annotation-driven executor="executor" scheduler="scheduler"/>
<context:component-scan base-package="wokao666.club.spring_task.tasks"></context:component-scan>
複製代碼

(此處還需另行深刻學習spring異步任務相關知識原理,異步執行使用@Async標註方法)

3、自定義定時任務

實現自定義定時任務,或者說咱們能夠更改相關的cron表達式,這看起來是很難以想象的,但確實能夠作到,小編推薦一篇例文Spring @Scheduled定時任務動態修改cron參數

CustomSchedual.java

package wokao666.club.spring_task.tasks;

import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import wokao666.club.spring_task.util.DateFormatter;

/**
 * 演示自定義定時器
 */
@EnableScheduling
@Component
public class CustomSchedual implements SchedulingConfigurer{
    
    private static String cron = "0/2 * * * * ?";
    
    private CustomSchedual() {
        new Thread(()->{
            try {
                Thread.sleep(16000);
            } catch (InterruptedException e) {}
            cron = "0/10 * * * * ?";
            System.err.println("change")
        }).start();
    }
    public void configureTasks(ScheduledTaskRegistrar arg0) {
        arg0.addTriggerTask(()->{
            System.err.println(DateFormatter.getDateFormatter().format(System.currentTimeMillis()) + " good night!");
        },(triggerContext)->{
        CronTrigger trigger = new CronTrigger(cron);
        return trigger.nextExecutionTime(triggerContext);
        });
    }
}
複製代碼

程序輸出以下,能夠看到,程序過來16秒以後,執行頻率從2秒/次變爲10秒/次:

六月 10, 2018 11:49:13 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2328c243: startup date [Sun Jun 10 23:49:13 CST 2018]; root of context hierarchy
六月 10, 2018 11:49:13 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
六月 10, 2018 11:49:14 下午 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor finishRegistration
信息: No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2018-06-10 11:49:16 good night!
2018-06-10 11:49:18 good night!
2018-06-10 11:49:20 good night!
2018-06-10 11:49:22 good night!
2018-06-10 11:49:24 good night!
2018-06-10 11:49:26 good night!
2018-06-10 11:49:28 good night!
2018-06-10 11:49:30 good night!
change
2018-06-10 11:49:32 good night!
2018-06-10 11:49:40 good night!
2018-06-10 11:49:50 good night!
2018-06-10 11:50:00 good night!
2018-06-10 11:50:10 good night!
2018-06-10 11:50:20 good night!
複製代碼

最後,單純會使用還不行,咱們不只要知其然,還要知其因此然,後期有時間多學學原理,其實底層無非就是java線程池的使用,加油,騷年們,晚安!

相關文章
相關標籤/搜索