




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、后臺事務開發文檔目 錄1.簡單后臺事務示例32.后臺事務執行過程及原理132.1.后臺事務定義132.2.后臺事務發布142.3.后臺事務執行153.代碼實現后臺事務定義223.1.非持久化后臺事務223.2.錯過策略253.3.人工干預(撤銷,掛起,喚醒)283.4.調度計劃時間331. 簡單后臺事務示例在進行后臺事務示例測試之前,我們需要做一些準備工作,首先,我們要在BOS Studio的BIM視圖下新建幾個元數據,如圖1所示:如上圖所示,新建了四個元數據(其中T_BO_BandOffice.table是根據實體右鍵導出表直接導出得到的),其實這四個元數據很簡單,FileLogFacade
2、.facade只有一個方法logWriter(String str);該方法實現了向服務器上的C:/file.log輸入日志。BandOffice.entity上新建了一個方法,該方法和FileLogFacade.facade的方法logWriter(String str)作用一樣,名字為testLog(String str),只是為了示范兩個不同的調用。實體BandOffice.entity還新建了一個TestLogEvent的事件,該事件可以引用實體本身的方法logWriter,也可以引用功能FileLogFacade的testLog方法。再定義了一個業務功能FileLogFunction
3、,在這個業務功能中定義了一個操作fileLog;通過應用,與實體上的事件關聯起來。在定義好這些元數據后,我們需要把這些元數據進行發布,使服務器端在運行時能夠加載這些元數據。上面是我們對解決方案的發布方案設置,如紅框標識的,我把元數據發布后生成的代碼放在W:workspacebs_jobdevtest目錄中,如下圖所示,元數據發布后在這個目錄下生成的代碼,這是實體和功能(facade)發布時生成的代碼,其他元數據發布時不生成代碼。在FileLogFacadeControllerBean中會生成功能定義的_logWriter方法,通過在這個方法中寫邏輯即可實現,而實體定義的方法會在BandOffi
4、ceControllerBean中生成_testLog方法。元數據發布后,我們需要重新生成系統子樹,這樣我們在重啟服務器后可以在事務任務選擇樹中看到我們定義的功能。具體生成系統子樹的方法,請參照生成系統子樹的兩種方法.doc。登陸EAS后,我們選擇系統平臺>后臺事務定義,進入后臺事務定義界面:接著我們就按要求進行定義,下面我們定義調度計劃設置:定義好后,我們進行保存,這個時候我們可以進行發布了,如下圖:我們再進入:系統平臺>后臺事務定義表,我們可以看到我們剛才定義的那個事務了我們設置好了調度計劃,當時間到達時,觸發該事務,就會執行一個事務實例,我們可以查看該事務實例,我們也可以直接
5、點擊工具欄中的啟動,這樣會立刻啟動一個事務實例。從上面可以看出,事務執行成功。我們再來看看我們實現的功能,就是在服務器目錄下寫入一條時間信息記錄:2. 后臺事務執行過程及原理首先我們要弄清楚,在EAS系統的后臺事務管理平臺中定義一個后臺事務的過程是怎樣的,你可以通過對代碼的跟蹤進行了解,2.1. 后臺事務定義首先我們在后臺事務定義界面上新建一個后臺事務(如下圖所示),這些后臺事務定義信息會被保存在T_WFD_PROCESSDEF中,可以在這個界面對已經定義好的后臺事務定義進行修改和刪除,當我們選擇左邊系統子樹的某個后臺事務定義節點,它對應的信息就會從該表中獲得并顯示在右邊的界面上?,F在我想描述
6、一下右邊這顆系統子樹的生成過程。這可系統子樹是在該界面的構造函數的initializeUI()方法中進行初始化的final BusinessTreeUtil tempPTU = new BusinessTreeUtil(BusinessTreeUtil.PROCESS);(KingdeeTreeModel) this.packagekDTree.getModel().setRoot(null);JobUtils.resetStartTimeMillis();tempPTU.initialBusinessTreeView(this.packagekDTree,true);JobUtils.pri
7、ntTimeMillis("initialBusinessTreeView");this.packagekDTree.addTreeSelectionListener(new InnerTreeSelectionListener();BusinessTreeUtil中有三個靜態變量,分別為PROCESS,FUNCTION,ENTITY,分別用來生成不同的系統子樹,在對系統子樹進行初始化調用了兩個方法,第一個是initialPackageTree(tree ,flag);這個方法是獲得標準包結構的樹,第二個是initalFunctionOrJobProcessTree(tre
8、e,flag);這個是獲得客戶化的樹形結構,通過該方法可以在標準化得包結構下添加功能節點或后臺事務定義節點。如果是生成功能(function)子樹或實體(entity)子樹,這就得獲取這些元數據的集合,而它們對應的集合類:FunctionObjectCollection和EntityObjectCollection,獲取這些集合的方法為:IMetaDataLoader loader = MetaDataLoaderFactory. getRemoteMetaDataLoader()FunctionObjectCollection funcol = loader.getFunctions()En
9、tityObjectCollection entcol = loader.getEntityCollection();2.2. 后臺事務發布后臺事務定義完成以后,通過發布,我們就可以在后臺事務定義報表看到我們定義的后臺事務了,已發布的后臺事務不允許進行刪除。public void release(ProcessDef process) throws BOSException JobDef def=JobServiceUtil.toJobDef(ctx, process); Trigger trigger=JobServiceUtil.toTrigger(def, process); IJobS
10、ervice svc=JobServiceFactory.getLocalInstance(ctx); svc.createJobDef(def, trigger, true);后臺事務定義被發布以后,產生了一個新的對象JobDef,對用在數據庫中的表是T_JOB_DEF。后臺事務實例(Job)就是根據這個定義來產生的。由上面的代碼可知,后臺事務定義(JobDef)和觸發器(Trigger)是由流程定義(ProcessDef)轉換過來的,這是因為在以前的后臺事務是按照工作流的方式進行處理的,每一個后臺事務定義都會生成一個流程定義保存在數據庫表(T_WFD_PROCESSDEF)的一個字段中,我
11、們用代碼實現后臺事務定義就不必通過這樣獲取流程定義(JobDef)。有上面代碼可知,通過調用JobService的createJobDef(JobDef def, Trigger trigger, boolean enable);方法創建后臺事務定義(實際上是通過反射調用了JobManager的createJobDef(JobDef def, Trigger trigger, boolean enable)方法),通過該方法將JobDef,Trigger對象保存到數據庫中的T_JOB_DEF和T_TRIGGER表中。從而完成了后臺事務定義的發布功能。2.3. 后臺事務執行后臺事務每執行一次就會
12、產出一個后臺事務實例(Job),持久化后臺事務會將后臺事務實例信息保存在T_JOB_INST表中。 我們可以通過兩種方式來觸發后臺事務執行,第一種是通過后臺事務界面上的“啟動”按鈕直接觸發產生一個后臺事務實例,第二種是通過定義一個觸發器(Trigger)來與該后臺事務定義關聯起來,用觸發器來觸發產生一個后臺事務實例。下面我們分別來討論通過這兩種方法是怎樣觸發產生后臺事務實例的?!皢印卑粹o觸發后臺事務。當我們點擊“啟動”按鈕會觸發該按鈕的事件,會調用到該界面JobProcessDefineListUI的actionStart_actionPerformed方法,通過方法調用,我們可以知道它調用
13、了JobServiceUIFacade的createJobInstance(jobDefId, null, null),在這個類中,通過獲取到了IjobService接口,調用了jobservice的createJobInstance方法;public String createJobInstance(String jobDefId, Object param, Timestamp scheduledTime) throws BOSException JobDef def=JobDefCache.getJobDef(ctx.getAIS(), jobDefId); if(def=null)th
14、row new BOSException("job def doesn't exist, its id is "+jobDefId+", datacenter: "+ctx.getAIS();if(scheduledTime=null)scheduledTime=new Timestamp(System.currentTimeMillis()+1000); Job job=def.newInstance(ctx, param, scheduledTime); manager.add(job); return job.getTitle();從上面這
15、個方法可以看出,首先由jobDefId獲取到JobDef對象def,在設置這個產生的任務實例的計劃執行時間為當前時間的下一秒。然后由后臺事務定義對象def的newInstance(ctx, param, scheduledTime)產生一個后臺事務實例對象job,再由后臺事務管理器JobManager(單子模式)調用add(job)方法把這個任務實例加載到等待隊列或者就需隊列中去;觸發器觸發后臺事務。如果我們在后臺事務定義的時候對其關聯了相應的觸發器,則當下一次觸發時間到達時,觸發器就會觸發與之關聯的后臺事務定義(JobDef)產生一個后臺事務實例(Job)。觸發器觸發后臺事務的過程是怎樣的呢
16、?首先:服務器啟動時會初始化觸發器加載類(TriggerLoader),該類實現了IJobHandler, IcoreJobHandler兩個接口,本身就是一個任務處理器,這個類的作用是:觸發器加載者,定期從數據庫加載新增的觸發器。其load()方法會定期被調用執行/*加載觸發器*/private int load()throws ExceptionStringBuffer sql=new StringBuffer();sql.append("select * from T_JOB_TRIGGER where fisvalid='Y' AND fisAutoLoad=
17、'Y' AND "); sql.append("(").append(TriggerIsolationLevel.sqlWhere(dc) .append(")");/符合隔離邊界sql.append(" and fholderid is null");/無持有者/只加載已生效的觸發器sql.append(" and fvalidateTime<=?");int types=new intTypes.TIMESTAMP;Timestamp now=new Timestamp(Syst
18、em.currentTimeMillis();Object values=new Objectnow;ArrayList items=SQL.executeQuery(dc, sql.toString(), types, values);Trigger tr;for(int i=0; i<items.size();i+)tr=null;trytr=Trigger.from(dc, (HashMap)items.get(i);PulseSource ps=tr.getPulseSource();if(ps=null)throw new BOSException("couldn
19、39;t find pulse source for this trigger!");ps.addTrigger(tr);catch(Throwable t) 。(省略) 。(省略)/觸發器加載間隔為任務加載間隔的5倍return Configuration.persistantJobCheckInterval()*5;這個方法實現了從數據庫表T_JOB_TRIGGER中加載新添加的觸發器,并返回觸發器加載時間間隔(上面設置的是為持久化任務加載間隔的5倍)protected synchronized void addTrigger(Trigger tr) throws Excepti
20、onTimerPulse pulse=new TimerPulse(tr);if(pulse.nextFireTime()=null)tr.inValid();/禁用TRIGGERthrow new java.lang.IllegalArgumentException("trigger "+tr.getKey()+" has no fire time!");if(pulse.setLoaded()add(pulse);TimerPulseSource的protected synchronized void addTrigger(Trigger tr)方法
21、是通過一個觸發器新建一個時間觸發發生器(TimerPulse),如果獲取不到這個TimerPulse下一次觸發時間,就禁用這個觸發器(Trigger),否則設置這個TimerPulse對應的觸發器(Trigger)的狀態是被加載的,如果設置成功,則把這個時間觸發發生器(TimerPulse)加入到觸發源(TimerPulseSource)中用來放置TimerPulse的堆結構(Heap)中去。當時間出發發生器(TimerPulse)放到Heap中去以后(會根據下一次觸發事件進行排序),當下一次觸發時間快到的時候,我們就需要把它從Heap中取出來,去生成其對應的觸發器關聯的后臺事務實例(Job)
22、。這是通過TimerHandler類來實現的,這個類也實現IJobHandler, IcoreJobHandler接口,是專門用來處理時間觸發發生器的,在服務器啟動初始化TimerPulseSource的時候,就新建了一個后臺事務實例,并添加到了就緒隊列或等待隊列中去了。JobInstanceConfig cfg=new JobInstanceConfig(new TimerHandler(this), false, true, 0);Job job=new Job(null,"Timer pulse source!", cfg, Boolean.TRUE);JobMana
23、ger.instance().add(job);而且這個任務每隔一秒會被執行一次,因為execute方法返回值為Delay(1)。而且在execute方法中調用的是schedule()方法。private void schedule()Date now=new Timestamp(System.currentTimeMillis()+Configuration.persistantJobCheckInterval()*1000);while(true)TimerPulse pulse=pulseSource.top();if(pulse=null)return;if(pulse.nextFir
24、eTime().after(now)return;pulse=pulseSource.pop();if(pulse.fire()pulseSource.add(pulse);該方法的作用是:首先設定一個時間,該時間是距離現在還有一個持久化任務加載間隔時間的未來時間,先讀取堆中的堆頂元素,看下一次觸發時間是否晚于設定的那個時間,如果是,就直接返回,如果不是,就把堆頂元素pop出來,并觸發時間觸發發生器(TimerPulse),即調用了fire()方法。public boolean fire() if(!trigger.triggered(nextFireTime)return false;/觸發
25、失敗,觸發發生器應失效 lastTriggeredTime=nextFireTime; nextFireTime=quartzTrigger.getFireTimeAfter(lastTriggeredTime); boolean b=nextFireTime!=null; if(!b)trigger.inValid();/以后不需觸發,觸發發生器應失效return b;public boolean triggered(Date lastTriggeredTime)tryJob job=newJob(lastTriggeredTime);if(!modifyState(lastTriggere
26、dTime)return false;JobManager.instance().add(job);return true;catch(Throwable t) 。(省略)從上面兩個方法知,TimerPulse雷 中的fire()方法調用了Trigger類中triggered(Date lastTriggeredTime)方法,在triggered方法中,由下一次觸發時間得到了這個觸發器關聯的后臺事務實例對象(Job),modifyState()方法是同步數據庫,更新該觸發器的觸發次數和最后一次觸發時間等信息。如果更新成功則把得到的后臺事務實例加入到等待或就緒隊列中去。fire()在執行完tr
27、iggered方法后,會更新一下自身(TimerPulse)的最后一次觸發時間和下一次觸發時間。如果fire()方法返回值為true,則把這個更新好的TimerPulse又放入到堆(Heap)結構中去,等待下一次調度。注意:在使用任務管理器JobManage提交后臺事務實例(Job)中,會調用job.setState(JobState.Created)語句,該語句會根據后臺事務實例是否是可持久化事物進行判斷,如果是持久化任務就把它保存到數據庫中去,并設置為“創建”的狀態,如果是非持久化任務就直接設置其狀態為“創建”,不做其他任何操作。接著再一次進行判斷,如果是持久化任務則返回,因為持久化任務實
28、例已經保存到數據庫中去了,此時需要通過任務加載器(JobLoader)從數據庫進行加載。非持久化任務就可以被加入到等待或就緒隊列中去了。if(!job.setState(JobState.Created) 。(省略)/持久化任務由任務加載器從數據庫加載if(job.isPersistent()return;if(job.getScheduledTime().after(new Date()b=WaitingJobs.in(job);elseb=ReadyJobs.in(job);持久化任務加載器(JobLoader)實現了IJobHandler,IcoreJobHandler接口,該類在啟動服
29、務器的時候就被初始化了,開啟了一個加載后臺事務實例加載事務,該事務會不行地執行,因為該任務處理器對應的execuse()方法返回值為new Delay(t);在execuse()方法中調用了load()方法,該方法就是從數據庫表T_JOB_INST中取得計劃執行時間快到得后臺事務實例(Job)。并直接放到等待隊列或就緒隊列中去。到現在為止,后臺事務實例(Job)已經都已經放到后臺事務等待隊列或就緒隊列中去了,還要完成的工作就是按照后臺事務實例的計劃執行時間(scheduledTime)來從就緒隊列中取出,并執行這個后臺事務實例(Job)了。處理這項工作的是負責后臺事務執行的工作線程類Threa
30、dWorker,在服務器啟動的時候會進行初始化,新建配置文件上指定個數的工作線程,然后調用start方法啟動這些線程。下面是線程對象的run()方法。public void run() Job job;boolean executed;while(true)/服務停止則退出線程if(!BOSSchedulerService.isRunning()break;job=null;executed=false;try/獲取下一個任務job=ReadyJobs.out();if(!RunningJobs.put(job)job=null;continue;/檢查是否錯過最后執行期限Date e=job
31、.getExpiredTime();if(e!=null)if(System.currentTimeMillis()>e.getTime()job.setState(JobState.Missed);continue;/執行executed=execute(job);catch(Throwable t)log.error("execute job "+job+" failed!",t);finally/釋放任務RunningJobs.dispose(job);if(executed)/如果任務被成功執行try/調整任務定義屬性adjustJobDe
32、f(job);/執行后處理handleReturns(job);catch(Throwable t)log.error("handler job "+job+"'s returns failed!",t);從這個方法可以看出,首先從就緒隊列中取出一個任務,然后放入到放到運行時任務中,檢查是否錯過最后期限,這個值跟錯過策略設置有關,如果設置為錯過“立刻執行”,則這個值為null,如果為“忽略不計”則是在程序中設置的一個時間。如果設置為“忽略不計”,且執行最后期限已過,則設置為“已錯過”的狀態。接著就執行這個任務,在這個過程中要完成設置任務執行狀態,
33、觸發一些事件,以及調用該任務的任務處理器對該任務進行處理。任務執行完以后,需要釋放這個任務,并且調整任務定義的屬性和執行一些后續處理。這樣,就整個任務就執行完畢了。對持久化后臺事務會產生一個后臺事務實例,我們可以通過“后臺事務實例”按鈕進行查看,執行失敗的后臺事務實例會產生日志信息,我們通過日志信息可以很快定位到執行后臺事務失敗的原因。3. 代碼實現后臺事務定義3.1. 非持久化后臺事務在登陸EAS系統后,進入后臺事務管理,在臺事務定義的界面上我們是不能選擇是定義持久化事務和非持久化事務的,通過在EAS系統中定義的后臺事務默認都是持久化事務的。如果我們要定義非持久化后臺事務,就必須通過代碼來實
34、現。通過對前一章的學習,我們已經熟悉后臺事務執行的過程,我們可以在服務器端程序代碼中新建一個后臺事務定義(JobDef)的對象,再調用JobService的createJobDef(JobDef def)方法就可以創建一個后臺事務定義了。下面是我在后臺事務客戶端Façade的JobServiceUIFacade類中定義的一個方法。其中TestJob是一個任務處理類,實現了IJobHandler接口,可以通過在這個類中的execute()方法中實現自己的測試業務邏輯。public void createLogJobDef() throws BOSExceptionString pack
35、ageName = null;String title= "后臺事務日志記錄測試"String description = "測試要求"String proxyUserID=null;String proxyOrgID=null;boolean isPersistent=false;Wrapper wrapper=new InterfaceWrapper(new TestJob();JobDef def=new JobDef(ctx,packageName, title, description,proxyUserID, proxyOrgID, isPe
36、rsistent, wrapper);JobServiceFactory.getLocalInstance(ctx).createJobDef(def);通過設置其isPersistent屬性為false,這樣創建的后臺事務定義是一個非持久化后臺事務定義。調用了JobService的createJobDef(def)方法,而這個方法又是通過反射調用了JobManager的createJobDef(JobDef def, Trigger trigger, boolean enable)方法,在這個方法會調用def.save(),即對我定義的后臺事務定義JobDef進行數據庫保存。這里面的trig
37、ger為空,即該后臺事務沒有關聯觸發器。我們需要執行這個方法,使之產生的后臺事務定義可以在后臺事務定義報表中顯示出來,在這里,我是放在這個類的testJobDef方法中讓它執行的。public String testJobDef(ProcessDef process) throws BOSException JobDef def=JobServiceUtil.toJobDef(ctx, process);createLogJobDef();/測試日志記錄后臺事務return JobServiceFactory.getLocalInstance(ctx).testJobDef(def, null
38、);這個方法關聯到后臺事務定義界面上的“測試”按鈕,所以只要點擊那個按鈕,就會執行我這個方法,從而產生一個后臺事務定義對象并保存到數據庫中,我們就可以在后臺事務定義報表中看到我們定義的這條記錄。由于這個后臺事務沒有關聯觸發器,所以要通過點擊“啟動”按鈕觸發后臺事務,提示后臺事務啟動成功后,點“后臺事務實例”按鈕,可以看到不會產生任務實例。這個后臺事務完成的工作仍然是向D盤目錄下的fileLog.txt文件中寫時間,在測試之前可以先刪除這個文件,測試后如果產生這個文件并記錄下了當前時間則說明執行成功。3.2. 錯過策略在后臺事務定義的時候,可以進行設置后臺事務的錯過策略,有兩種情況,一種是“立即
39、執行”,另一種是“忽略不計”,其中這兩種是怎樣工作的呢?在后臺事務定義的時候,后臺事務錯過策略信息是保存在T_JOB_DEF的fmissedtimeout字段中,設置后臺事務的錯過策略為立即執行,這個字段保存的值為-1,設置為忽略不計,這個字段保存的值為0;在代碼中是如何設置其錯過的策略呢?通過下面這段代碼你就可以明白系統是怎樣進行處理的。if(scheduledTime=null)scheduledTime=new Timestamp(System.currentTimeMillis();if(expiredTime=null)int timeout=this.missedTimeout;i
40、nt t=Configuration.persistantJobCheckInterval()*10;if(timeout=0)/默認錯過超時, 取任務加載間隔的10倍, 且該值不得小于180秒timeout=t;if(timeout<180)timeout=180;if(timeout>0)if(timeout<t)timeout=t;expiredTime=new Timestamp(scheduledTime.getTime()+timeout*1000);從上面可以看出,如果計劃執行時間為空,則設置計劃執行時間為當前時間,如果過期時間為空,則首先判斷JobDef的mi
41、ssedTimeout是否為0,如果為零,表示忽略不計,對忽略不計這種情況,系統會默認設置它的過期時間,如果超過這個過期時間,就設置這個后臺事務實例的狀態為“已錯過”,對于立即執行這種情況,就不會去設置它的過期時間,expiredTime這個值為null,表示永不過期。在后臺事務執行的時候,會檢查后臺事務實例的expiredTime值,如果不為空且現在時間已經過了這個時間就會設置其狀態為“已錯過”。其判斷代碼如下(在ThreadWorker的run()方法中):Date e=job.getExpiredTime();if(e!=null)if(System.currentTimeMillis(
42、)>e.getTime()job.setState(JobState.Missed);continue;通常在多個線程同時運行的情況下,我們運行的后臺事務實例不會因為阻塞而產生“已錯過的情況”,如果我們需要對這種情況進行測試,這就需要我們在程序代碼中進行控制,我們可以在后臺任務管理器JobManager中的if(job.getScheduledTime().after(new Date()語句上設置一個斷點,阻塞其運行,待產生的后臺事務實例的最后期限已經過去,再去掉斷點,讓它們繼續運行,這樣我們就可以看到我們產生的后臺實例出現“已錯過”的情況。同樣,我們可以進行錯過策略為“立刻執行”的測
43、試,不管我們的斷點阻塞線程運行多久,只要我們一讓它運行,后臺事務仍然會執行,如下圖所示,開始執行時間比計劃執行時間晚了3分多種,總而言之,選擇“立刻執行”的后臺事務實例,只要讓它獲得執行的機會就會直接執行。3.3. 人工干預(撤銷,掛起,喚醒)對已接收,重新調度,已就緒,等待中的后臺事務實例可進行撤銷和掛起操作,對已掛起的后臺事務實例可以進行喚醒操作,已錯過的后臺事務可以進行修復操作(其實質也就是重新調度),對運行中的后臺事務不能夠做任何操作,這些情況在實際運行中可能不是很好把握,因為從一個轉臺轉換到另一個狀態轉換的時間間隔很少,所以要出現下面這些情況,最好還是通過設置斷點,在不同的時機進行阻
44、塞操作。3.4. 調度計劃時間后臺事務觸發器的調度計劃時間表達式是保存在數據庫表T_JOB_TRIGGER的fschedulePlan字段中,String schedulePlan=schedule.getType().toString()+":"+schedule.getDefine();由這條語句可知,其值由兩部分組成。分別為調度類別和調度的定義,其中調度定義是Quartz的cron 表達式的格式,后臺事務獲取下一次觸發時間就是根據這個表達式來得到的,首先根據這個表達式可以新建一個CronTrigger對象,通過這個對象及上一次的觸發時間就可以得到下一次觸發時間了:qu
45、artzTrigger.getFireTimeAfter(lastTriggeredTime)。下面是對Quartz的cron 表達式的格式的說明:Quartz 用 cron 表達式存放執行計劃。引用了 cron 表達式的 CronTrigger 在計劃的時間里會與 job 關聯上。Quartz 提供七個域。下表列出了 Quartz cron 表達式支持的七個域。名稱是否必須允許值特殊字符秒是0-59, - * /分是0-59, - * /時是0-23, - * /日是1-31, - * ? / L W C月是1-12 或 JAN-DEC, - * /周是1-7 或 SUN-SAT, - *
46、? / L C #年否空 或 1970-2099, - * /月份和星期的名稱是不區分大小寫的。FRI 和 fri 是一樣的。域之間有空格分隔,這和 UNIX cron 一樣。無可爭辯的,我們能寫的最簡單的表達式看起來就是這個了:* * * ? * *,這個表達會每秒鐘(每分種的、每小時的、每天的)激發一個部署的 job。Quartz cron 表達式支持用特殊字符來創建更為復雜的執行計劃:*星號:使用星號(*) 指示著你想在這個域上包含所有合法的值。例如,在月份域上使用星號意味著每個月都會觸發這個 trigger。表達式樣例:0 * 17 * * ?意義:每天從下午5點到下午5:59中的每分鐘激發一次 trigger。它停在下午 5:59 是因為值 17 在小時域上,在下午 6 點時,小時變為 18 了,也就不再理會這個 trigger,直到下一天的下午5點,在你希望 trigger 在該域的所有有效值上被激發時使用 * 字符。? 問號:? 號只能用在日和周域上,但是不能在這兩個域上同時使用。你可以認為 ? 字符是 "我并不關心在該域上是什么值。" 這不同于星號,星號是指示著該域上的每一個值。? 是說不為該域指定值。不能同時這兩個域上指定值的理由是難以解釋甚至是難以理解的?;旧?,假定同時指定值的話,意義就會變得含混不清了:考慮一下,如果一個表達式在日域上
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025如何強化合同監管功能促進企業信用體系建設
- 《2025年個人租賃企業汽車合同》
- 2025投資者應警惕合同中的隱含風險
- 2024年復合管道項目資金申請報告代可行性研究報告
- 2025臨時勞動合同模板
- 2025景觀設計與施工承包合同
- 2025全面汽車租賃合同范本
- 2025房屋租賃拆遷合同模板
- 2025年履行合同勞動的基本原則
- 2025的勞動合同范本
- (二模)2025年深圳市高三年級第二次調研考試歷史試卷(含標準答案)
- 婦產科課件-早產臨床防治指南(2024)解讀
- 2024年湖北省中考地理生物試卷(含答案)
- 2024年無錫市錫山環保能源集團招聘筆試參考題庫附帶答案詳解
- 輸液泵/微量注射泵使用技術操作考核評分標準
- 文體學eecummings詩歌分析
- 針織毛衫實例
- 安全生產知識匯總——五一勞動節前安全教育培訓(176頁)
- 套絲機簡介ppt課件
- 副詞講義 Adverbs
- 貴州省各縣風向玫瑰圖
評論
0/150
提交評論