Apex计划作业框架的实现

在本文中,我们实现一个简单的“计划作业框架”,用于实现数据的定时自动处理。

Apex相关接口

Apex中提供了一组接口用来实现数据的处理。我们主要使用以下两个:

  • Schedulable:数据的定时处理
  • Batchable:数据的批量处理

示例情景

本文以如下情景为例,实现计划作业框架。

  • 数据模型:在Salesforce中有一个银行账号对象,API名称为“BankAccount__c”。在此对象中有字段“到期日期”,API名称为“ExpireDate__c”,和字段“状态”,API名称为“Status__c”。

  • 业务流程:

  1. 每天夜里的固定时间,系统需要自动检查银行账号,并将“到期日期”和当前日期作比较
  2. 如果银行账号到期,则将“状态”字段的值更新为“过期”
  • 业务逻辑代码:在Salesforce中已经相应的业务逻辑,存放在Apex类“BankAccount_Status_Handler”中,对应的函数是“updateExpireStatus()”

框架组成部分

计划作业框架要实现的功能是定时对大批量的数据进行处理,由两个Apex类组成:

  1. BankAccount_Batch_Status_Handler:实现了Batchable接口,查询并提取批量数据,并调用Apex类“BankAccount_Status_Handler”中的函数对银行账号对象进行处理
  2. BankAccount_Batch_Status_SCH:实现了Schedulable接口,用于在Salesforce的设置界面中设置定时的任务,执行“BankAccount_Batch_Status”类的功能

代码

BankAccount_Status_Handler类:

public class BankAccount_Status_Handler {

    public static void updateExpireStatus(Set<Id> bankAccountIds) {
        // 业务逻辑
        // ...
    }

}

BankAccount_Batch_Status_Handler类:

global class BankAccount_Batch_Status_Handler implements Database.Batchable<sObject> {

    public Database.QueryLocator start(Database.BatchableContext bc) {
        // 初始化,得到需要处理的数据
        return Database.getQueryLocator([SELECT Id, ExpireDate__c FROM BankAccount__c]);
    }

    public void execute(Database.BatchableContext bc, List<SObject> scope) {
        // 得到需要处理的数据的Id集合
        Set<Id> scopeIds = new Map<Id, SObject>(scope).keySet();

        // 进行处理
        BankAccount_Status_Handler.updateExpireStatus(scopeIds);
    }
    
    public void finish(Database.BatchableContext bc) {}

}

BankAccount_Batch_Status_SCH类:

global class BankAccount_Batch_Status_SCH implements Schedulable {

    public void execute(SchedulableContext sc) {
        // 初始化 BankAccount_Batch_Status_Handler 类
        BankAccount_Batch_Status_Handler batch = new BankAccount_Batch_Status_Handler();
            
        // 执行批处理操作
        Database.executebatch( batch, 200 );
    }
    
}

设置Job的执行

“BankAccount_Batch_Status_SCH”类实现了“Schedulable”接口,所以可以被设定为自动执行。

在Salesforce的设置界面,查找“Apex”,点击“Apex 类”链接,进入Apex类的一览表。

点击“计划Apex”按钮,在其中的“Apex 类”部分选择“BankAccount_Batch_Status_SCH”类,然后设定其他的属性。

这样,计划作业框架就建立完成了。代码中的逻辑会在固定的时间自动执行。

优化

上述的代码是由两个分别实现了Schedulable和Batchable接口的类所组成,其中直接写死了调用银行账户对象相关的类和逻辑。

我们可以将它们扩展为通用的框架,增加复用性。

停用已经计划的Apex类

在重构代码之前,因为“BankAccount_Batch_Status_SCH”类已经被设定了计划执行,所以“BankAccount_Batch_Status_SCH”类和其调用的类都不能被修改。

要想进行代码重构,必须先停止已经计划的Apex类。

在设置界面搜索“计划的作业”,点击“计划的作业”链接,进入“所有计划的作业”一览表。在表中可以直接删除“BankAccount_Batch_Status_SCH”类的计划。

对Batchable相关的类进行扩展

新建一个Apex类,名叫“Job_Batch_Handler_Abstract”,代码如下:

public abstract class Job_Batch_Handler_Abstract implements Database.Batchable<sObject> {
    
    protected abstract Database.QueryLocator getQueryLocator(); // 抽象函数,用于得到需要处理的数据
    protected abstract void executeLogic(Set<Id> scopeIds); // 抽象函数,用于执行具体的逻辑
    
    public Database.QueryLocator start(Database.BatchableContext bc) {
        return getQueryLocator(); // 动态得到需要处理的数据
    }
    
    public void execute(Database.BatchableContext bc, List<SObject> scope) {
        // 得到需要处理的数据的Id集合
        Set<Id> scopeIds = new Map<Id, SObject>(scope).keySet();
        
        // 进行处理,具体的逻辑需要具体实现
        executeLogic(scopeIds);
    }
    
    public void finish(Database.BatchableContext bc) {}

}

将之前的“BankAccount_Batch_Status_Handler”类改为继承了“Job_Batch_Handler_Abstract”类:

global class BankAccount_Batch_Status_Handler extends Job_Batch_Handler_Abstract {
    
    protected override Database.QueryLocator getQueryLocator() {
        // 初始化,得到需要处理的数据
        return Database.getQueryLocator([SELECT Id, ExpireDate__c FROM BankAccount__c]);
    }
    
    protected override void executeLogic(Set<Id> scopeIds) {
        // 具体的处理逻辑
        BankAccount_Status_Handler.updateExpireStatus(scopeIds);
    }

}

这样,“Job_Batch_Handler_Abstract”类就可以作为通用的类,被其他的类所继承和使用。

对Schedulable相关的类进行扩展

新建一个Apex类,名叫“Job_Batch_SCH_Abstract”,代码如下:

public abstract class Job_Batch_SCH_Abstract implements Schedulable {

    protected abstract String getHandlerName(); // 抽象函数,用于得到具体的类名字

    public void execute(SchedulableContext sc) {
        // 根据开发者定义的类名,新建相应类的实例
        Object o = Type.forName( getHandlerName() ).newInstance();
        
        Job_Batch_Handler_Abstract batch;
        
        // 检查新的实例是否是Job_Batch_Handler_Abstract抽象类的子类。如果是,则执行批量处理
        if ( o != null && o instanceof Job_Batch_Handler_Abstract) {
            batch = (Job_Batch_Handler_Abstract) o;
            
            Database.executebatch( batch, 200 );
        }
    }

}

将之前的“BankAccount_Batch_Status_SCH”类改为继承了“Job_Batch_SCH_Abstract”类:

global class BankAccount_Batch_Status_SCH extends Job_Batch_SCH_Abstract {
    
    protected override String getHandlerName(){
        return 'BankAccount_Batch_Status_Handler';
    }
    
}

这样,“Job_Batch_SCH_Abstract”类就可以作为通用的类,被其他的类所继承和使用。

完成了这两个通用类的实现,就可以在Salesforce的设置界面为“BankAccount_Batch_Status_SCH”类重新设定自动执行。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容