談談個人網站的建立(三)—— 定時任務


歡迎訪問我的網站http://www.wenzhihuai.com/ 。謝謝啊,如果可以,希望能在GitHub上給個star,GitHub地址https://github.com/Zephery/newblog

Quartz

先看一下Quartz的架構圖:

一.特點:

  1. 強大的調度功能,例如支持豐富多樣的調度方法,可以滿足各種常規及特殊需求;
  2. 靈活的應用方式,例如支持任務和調度的多種組合方式,支持調度數據的多種存儲方式;
  3. 分布式和集群能力。

二.主要組成部分

  1. JobDetail:需實現該接口定義的人物,其中JobExecutionContext提供了上下文的各種信息。
  2. JobDetail:QUartz的執行任務的類,通過newInstance的反射機制實例化Job。
  3. Trigger: Job的時間觸發規則。主要有SimpleTriggerImpl和CronTriggerImpl兩個實現類。
  4. Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日歷特定時間點的集合(可以簡單地將org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一個日歷時間點,無特殊說明后面的Calendar即指org.quartz.Calendar)。
  5. Scheduler:由上圖可以看出,Scheduler是Quartz獨立運行的容器。其中,Trigger和JobDetail可以注冊到Scheduler中。
  6. ThreadPool:Scheduler使用一個線程池作為任務運行的基礎設施,任務通過共享線程池中的線程提高運行效率。

三、Quartz設計

  1. properties file
    官網中表明:quartz中使用了quartz.properties來對quartz進行配置,並保留在其jar包中,如果沒有定義則默認使用改文件。
    2.Trigger的實現類
    (1)SimpleTrigger
    指某一個時間開始,或者從現在開始以一定的間隔執行任務。
    其屬性有
private Date startTime;
private Date endTime;
private Date nextFireTime;
private Date previousFireTime;
private int repeatCount;  //重復次數
private long repeatInterval;//重復間隔
private int timesTriggered;
private boolean complete;

(2)CronTrigger
類似於linux cron中的語法,能夠設置任何時間,重復次數等運行。
詳情請使用cron表達式來查詢。
3. Job並發

  1. JobListener
    先看一下JobListener的源碼:
public interface JobListener {
    String getName();//某個joblistener的名字
    void jobToBeExecuted(JobExecutionContext var1);//即將運行
    void jobExecutionVetoed(JobExecutionContext var1);//運行后
    void jobWasExecuted(JobExecutionContext var1, JobExecutionException var2);//取消
}

無非就是對某個任務的運行前、運行后、以及取消的偵聽。次數使用觀察者模式,對人物進行廣播偵聽。

四、使用

  1. hello world!代碼在這
    (1)定義一個job
public class HelloJob implements Job {
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Hello World! - " + new Date());
    }
}

(2)運行(來自官網修改的例子,官網那個例子需要等90秒)。。。坑

public class SimpleExample {
    public static void main(String[] args) throws Exception {
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();
        JobDetail job = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startAt(DateTime.now().plusMillis(4).toDate())//固定一個時間,現在設置為程序啟動后4秒
                .build();
        sched.start();
        sched.scheduleJob(job, trigger);
        //啟動后要sleep一下,不然立即關閉
        Thread.sleep(6);
        sched.shutdown(true);
    }
}

(3)運行結果:

Hello World! - Mon Sep 11 15:55:53 CST 2017
  1. 自定義監聽器
    (1)自定義listener
public class MyJobListener implements JobListener {
    @Override//相當於為我們的監聽器命名
    public String getName() {
        return "myJobListener";
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext context) {
        System.out.println(getName() + "觸發對" + context.getJobDetail().getJobClass() + "的開始執行的監聽工作,這里可以完成任務前的一些資源准備工作或日志記錄");
    }

    @Override//“否決JobDetail”是在Triiger被其相應的監聽器監聽時才具備的能力
    public void jobExecutionVetoed(JobExecutionContext context) {
        System.out.println("被否決執行了,可以做些日志記錄。");
    }

    @Override
    public void jobWasExecuted(JobExecutionContext context,
                               JobExecutionException jobException) {
        System.out.println(getName() + "觸發對" + context.getJobDetail().getJobClass() + "結束執行的監聽工作,這里可以進行資源銷毀工作");

    }

}

(2)跟上例一樣,只需在Scheduler上增加監聽器即可。

JobListener myJobListener = new MyJobListener();
KeyMatcher<JobKey> keyMatcher = KeyMatcher.keyEquals(job.getKey());
sched.getListenerManager().addJobListener(myJobListener, keyMatcher);

(3)結果:

myJobListener觸發對class com.quartz.hello.HelloJob的開始執行的監聽工作,這里可以完成任務前的一些資源准備工作或日志記錄
Hello World! - Mon Sep 11 16:57:56 CST 2017
myJobListener觸發對class com.quartz.hello.HelloJob結束執行的監聽工作,這里可以進行資源銷毀工作或做一些新聞扒取結果的統計工作
  1. 本網站中使用quartz來對數據庫進行備份,與Spring結合
    (1)導入spring的拓展包,其協助spring集成第三方庫:郵件服務、定時任務、緩存等。。。
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.2.6.RELEASE</version>
</dependency>

(2)導入quartz包

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

(3)mysql遠程備份
使用命令行工具僅僅需要一行:

mysqldump -u [username] -p[password] -h [hostip] database > file

但是java不能直接執行linux的命令,仍舊需要依賴第三方庫ganymed

<dependency>
    <groupId>ch.ethz.ganymed</groupId>
    <artifactId>ganymed-ssh2</artifactId>
    <version>262</version>
</dependency>

完整代碼如下:

@Component("mysqlService")//在spring中注冊一個mysqlService的Bean
public class MysqlUtil {
    ...
    StringBuffer sb = new StringBuffer();
    sb.append("mysqldump -u " + username + " -p" + password + " -h " + host + " " +
            database + " >" + file);
    String sql = sb.toString();
    Connection connection = new Connection(s_host);
    connection.connect();
    boolean isAuth = connection.authenticateWithPassword(s_username, s_password);//進行遠程服務器登陸認證
    if (!isAuth) {
        logger.error("server login error");
    }
    Session session = connection.openSession();
    session.execCommand(sql);//執行linux語句
    InputStream stdout = new StreamGobbler(session.getStdout());
    BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
}

(4)spring中配置quartz

<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="mysqlService"/>
    <property name="targetMethod" value="exportDataBase"/>
</bean>
<!--定義觸發時間  -->
<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="jobDetail"/>
    <!-- cron表達式,每周五2點59分運行-->
    <property name="cronExpression" value="0 59 2 ? * FRI"/>
</bean>
<!-- 總管理類 如果將lazy-init='false'那么容器啟動就會執行調度程序 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="myTrigger"/>
        </list>
    </property>
</bean>

(5)java完整文件在這

Spring的高級特性之定時任務

java ee項目的定時任務中除了運行quartz之外,spring3+還提供了task,可以看做是一個輕量級的Quartz,而且使用起來比Quartz簡單的多。

  1. spring配置文件中配置:
<task:annotation-driven/>
  1. 最簡單的例子,在所需要的函數上添加定時任務即可運行
    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() {
        System.out.println("每隔5秒運行一次" + sdf.format(new Date()));
    }
  1. 運行的時候會報錯:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:372)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:192)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:171)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:86)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:163)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:136)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:380)

Spring的定時任務調度器會嘗試獲取一個注冊過的 task scheduler來做任務調度,它會嘗試通過BeanFactory.getBean的方法來獲取一個注冊過的scheduler bean,獲取的步驟如下:
(1) 嘗試從配置中找到一個TaskScheduler Bean
(2) 尋找ScheduledExecutorService Bean
(3) 使用默認的scheduler
修改log4j.properties即可:
log4j.logger.org.springframework.scheduling=INFO
其實這個功能不影響定時器的功能。
(4)結果:

每隔5秒運行一次14:44:34
每隔5秒運行一次14:44:39
每隔5秒運行一次14:44:44

參考:
(1) http://blog.csdn.net/oarsman/article/details/52801877
(2) http://stackoverflow.com/questions/31199888/spring-task-scheduler-no-qualifying-bean-of-type-org-springframework-scheduli
(3)http://blog.csdn.net/qwe6112071/article/details/50991531

希望能在GitHub上給個star,https://github.com/Zephery/newblog,謝謝么么噠(づ ̄ 3 ̄)づ


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM