Spring中定時任務@Scheduled的一點小小研究

最近作一個公衆號項目,微信公衆號會要求服務端找微信請求一個access_token,獲取的過程:java

access_token是公衆號的全局惟一接口調用憑據,公衆號調用各接口時都需使用access_token。開發者須要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前爲2個小時,需定時刷新,重複獲取將致使上次獲取的access_token失效。web

公衆平臺的API調用所需的access_token的使用及生成方式說明:spring

一、建議公衆號開發者使用中控服務器統一獲取和刷新Access_token,其餘業務邏輯服務器所使用的access_token均來自於該中控服務器,不該該各自去刷新,不然容易形成衝突,致使access_token覆蓋而影響業務;api

二、目前Access_token的有效期經過返回的expire_in來傳達,目前是7200秒以內的值。中控服務器須要根據這個有效時間提早去刷新新access_token。在刷新過程當中,中控服務器可對外繼續輸出的老access_token,此時公衆平臺後臺會保證在5分鐘內,新老access_token均可用,這保證了第三方業務的平滑過渡;tomcat

三、Access_token的有效時間可能會在將來有調整,因此中控服務器不只須要內部定時主動刷新,還須要提供被動刷新access_token的接口,這樣便於業務服務器在API調用獲知access_token已超時的狀況下,能夠觸發access_token的刷新流程。服務器

 

因此解決方案就是作一個定時任務,服務啓動的時候獲取一次token,以後每隔兩小時自動獲取一次。這用Spring的@Scheduled註解很容易實現:微信

@Override
    @Scheduled(fixedRate=1000*60*59*2)
    public void updateToken() {

        try{
            for(AppConfig appConfig : SysConfig.AppLists){
                Token token = TokenAPI.token(appConfig.wxAppId,appConfig.wxAppSecret);
                appConfig.access_token = token.getAccess_token();
                Ticket ticket = TicketAPI.ticketGetticket(token.getAccess_token());
                appConfig.ticket = ticket.getTicket();
                logger.info("access_token:" + token.getAccess_token()+",js_api_ticket:"+ticket.getTicket());
            }
        }catch (Exception e){
            logger.info("刷新access_token出錯");
        }
    }

這裏使用fixedRate來指定任務執行的時間間隔(毫秒記)。app

而後由於如今項目只有一個服務號,沒有申請測試用的服務號,本地調試也會去獲取access_token ,結果致使服務端的生產環境的token失效,必須重啓服務器的tomcat來刷新token。顯然這種作法是很是愚蠢的,目前還沒正式投入使用,投入使用後這顯然不能接受。ide

解決方案就是,統一一個接口來向服務端獲取token,當token失效時,執行一次updateToken的方法,以刷新token。spring-boot

 

===================================================================手動分割線============================================================

而後我就比較好奇一個事,那就是,當加了@Scheduled(fixedRate=1000*60*59*2)的方法被其餘方法調用的時候,定時任務會有變化嗎?好比,我調用一次,那麼任務是仍是按照之前預約的時間跑呢,仍是會在我調用以後的2小時(預定的間隔時間)纔會再跑?百度Google找了找,包括官方文檔也沒給個說法。爲這個也不想去看源代碼,仍是寫個demo驗證下算了。

首先建立一個Spring Boot的項目,引入web模塊(使用rest請求來手動調用定時任務)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

 

項目結構:

 

Service接口:

package com.xiatingfei.schedule.demo.service;

public interface TaskService {

    void SayHelloTask();

}

Service實現(每隔10秒鐘在控制檯打印一次Hello!):

package com.xiatingfei.schedule.demo.service.impl;

import com.xiatingfei.schedule.demo.service.TaskService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class TaskServiceImpl implements TaskService {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    @Override
    @Scheduled(fixedRate = 10000)
    public void SayHelloTask() {
        System.out.println("Hello! Now is "  + dateFormat.format(new Date()));
    }
}

Controller:

package com.xiatingfei.schedule.demo.controller;

import com.xiatingfei.schedule.demo.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/demo")
public class TriggerController {

    @Autowired
    TaskService taskService;

    @RequestMapping("/sayHello")
    public void TriggerTask(){
        taskService.SayHelloTask();
    }

}

而後在SpringBoot的啓動類加入定時任務的註解@EnableScheduling

package com.xiatingfei.schedule.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

啓動應用,能夠看到控制檯能夠定時打印Hello和時間:

在Postman給服務端發一個請求,手動調用定時任務:

get http://localhost:8080/demo/sayHello

結果:

能夠看到定時任務沒有受到調用的影響,仍是按照本身的節奏10秒鐘一次~~

(並且,還會發現Spring會在第一次收到Http請求的時候纔會初始化dispatcherServlet,而不是服務啓動的時候就初始化)

相關文章
相關標籤/搜索