序:
這次的場景是關於自動任務,希望跟業務平臺解耦,同時可以支持動態修改任務執行時間,可以暫停、恢復、修改、刪除等,另外還想帶管理頁面,避免繁瑣的配置文件,可靈活交互,對接多項目支持。這些就是自動任務平臺的特徵,那麼怎麼實現呢?畫流程圖,想清楚場景,同時分清平臺與業務系統的邊界。
- 邏輯時序圖
- 自動任務技術選型
SpringBoot + quartz + mysql + redis + web
- 計劃實現的功能
- 業務數據轉任務數據存庫
- 防復調機制
- 異步通知執行結果
- 多公司項目共用權限機制(暫不實現,後面有時間再增加)
- quartz擁有的實時操作功能,如暫停、恢復、修改、刪除
- 日誌記錄:任務執行記錄、任務操作記錄(修改、暫停、刪除記錄)
- 實現邏輯簡述
第一步:
業務系統:業務系統按照自動任務平臺要求傳參(主要參數,任務執行時間週期、任務回調業務地址)。
任務平臺:創建註冊自動任務,反饋創建結果。
第二步:
任務平臺:創建成功後任務平臺開始循環任務,到時間點做邏輯判斷,查看上次任務調用是否完成,執行回調,調用業務地址,業務系統異步返回調用成功,記錄執行記錄。
第三步:
(業務系統)業務系統執行相關業務,調用任務平臺,反饋執行批次的執行結果(防止復調,使用redis實現)
第四步:
任務平臺:清除執行批次緩存,更新執行記錄。等待下次執行時刻
- 任務平臺計劃提供的接口與頁面
- 登錄頁面、公司、項目權限(雙鑑權,授權信息校驗、sign加密串校驗)
- 任務管理界面
- 創建任務接口
- 任務執行時刻表查詢接口
- 任務執行結果查詢接口
- 業務系統反饋執行結果接口
- quartz擁有的實時操作功能:暫停、恢復、刪除
其中、236優先處理。
- 技術預研搭建的界面
界面要根據我們的平臺要求修改,但是美化肯定不擅長,先實現功能。
- 風險點
- 網絡風險,任務平臺調用業務平臺失敗
- 由1導致的任務執行失敗,怎麼補償
- 由1導致的任務執行失敗,是否要像設備解析平臺一樣提供重調(如果是高密度自動任務,重調有時間重合怎麼處理?)
任務平臺的性能瓶頸(接入項目多了,自動任務多,執行密度大,是否能抗住?)
上面說的是大致方案,詳細方案,我也不會在這裏寫出來。但是呢,技術實現還是可以大致講下。
靜態頁面訪問
springBoot + web的框架,這裏就不多說了。唯一提下靜態頁面文件允許訪問,避免攔截的實現。
關鍵代碼:
@Configuration
public class WebAppConfigurer extends WebMvcConfigurationSupport {
@Autowired
private ApiAuthMapper apiAuthMapper;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//將url帶static訪問靜態資源的映射到static文件目錄
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
super.addResourceHandlers(registry);
}
}
其實就是配置類,繼承WebMvcConfigurationSupport,重寫資源攔截方法addResourceHandlers,裏面主要是設置映射關係。注意這個不能又多個,否則可能失效,具體哪個先執行後執行跟加載機制有關,有的說繼承WebMvcConfigurerAdapter。這個方法貌似已經過時,但是我覺得會有加載順序問題導致失效,後面研究。
quartz的job裏不能註解service、mapper
任務工廠
@Component
public class CustomJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//調用父類的方法
Object jobInstance = super.createJobInstance(bundle);
//進行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
自定義一個job工廠,繼承AdaptableJobFactory,同時使用spring的註解@Component交由spring管理。來裏面重寫創建任務實例方法,調用父類方法,實現自動注入。
調度器配置
@Configuration
public class SchedulerConfig {
private JobFactory jobFactory;
public SchedulerConfig(JobFactory jobFactory){
this.jobFactory = jobFactory;
}
@Bean(name="SchedulerFactory")
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setQuartzProperties(quartzProperties());
factory.setJobFactory(jobFactory);
return factory;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//在quartz.properties中的屬性被讀取並注入後再初始化對象
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
/*
* quartz初始化監聽器
*/
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
/*
* 通過SchedulerFactoryBean獲取Scheduler的實例
*/
@Bean(name="Scheduler")
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
}
做完上面的操作,你自己的job類就可以使用註解標籤了
@Slf4j
public class CronUnifyJob implements Job {
@Autowired
private ApiAuthMapper authMapper;
@Autowired
private ApiJobMapper apiJobMapper;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//your business code
}
}
解耦的執行機制
我這裏的設計思路就是在上面your business code裏做文章,這裏採取回調業務系統接口的辦法實現解耦。我想到這你懂了,至於實現防復調,也在在這裏使用redis跟任務執行結果反饋接口配合使用。
最後說明
防復調思路請放飛自我想,我不能在說了,呵呵。爲了安全起見,我這裏的鑑權一點沒說,望理解。此外,quartz的基礎表是肯定要建的。