文章目录
异步作业的配置
1. 初始化时钟
public void initClock() {
if (this.clock == null) {
this.clock = new DefaultClockImpl();
}
}
2. 初始化作业处理器
Activiti7采用HashMap : <type -> JobHandler>
维护全局的作业处理器集合jobHandlers
,作业处理器会实现JobHandler
接口。 在initJobHandlers
中添加6
个默认的作业处理器,如下:
public interface JobHandler {
String getType();
void execute(JobEntity var1, String var2, ExecutionEntity var3, CommandContext var4);
}
public void initJobHandlers() {
this.jobHandlers = new HashMap();
AsyncContinuationJobHandler asyncContinuationJobHandler = new AsyncContinuationJobHandler();
this.jobHandlers.put(asyncContinuationJobHandler.getType(), asyncContinuationJobHandler);
TriggerTimerEventJobHandler triggerTimerEventJobHandler = new TriggerTimerEventJobHandler();
this.jobHandlers.put(triggerTimerEventJobHandler.getType(), triggerTimerEventJobHandler);
TimerStartEventJobHandler timerStartEvent = new TimerStartEventJobHandler();
this.jobHandlers.put(timerStartEvent.getType(), timerStartEvent);
TimerSuspendProcessDefinitionHandler suspendProcessDefinitionHandler = new TimerSuspendProcessDefinitionHandler();
this.jobHandlers.put(suspendProcessDefinitionHandler.getType(), suspendProcessDefinitionHandler);
TimerActivateProcessDefinitionHandler activateProcessDefinitionHandler = new TimerActivateProcessDefinitionHandler();
this.jobHandlers.put(activateProcessDefinitionHandler.getType(), activateProcessDefinitionHandler);
ProcessEventJobHandler processEventJobHandler = new ProcessEventJobHandler();
this.jobHandlers.put(processEventJobHandler.getType(), processEventJobHandler);
if (this.getCustomJobHandlers() != null) {
Iterator var7 = this.getCustomJobHandlers().iterator();
while(var7.hasNext()) {
JobHandler customJobHandler = (JobHandler)var7.next();
this.jobHandlers.put(customJobHandler.getType(), customJobHandler);
}
}
}
- 默认作业处理器 :
AsyncContinuationJobHandler
: 异步节点作业处理器TriggerTimerEventJobHandler
: 触发时间事件作业处理器TimerStartEventJobHandler
: 定时启动流程实例作业处理器TimerSuspendProcessDefinitionHandler
: 定时挂起流程定义处理器TimerActivateProcessDefinitionHandler
: 定时激活流程定义处理器ProcessEventJobHandler
: 流程事件作业处理器
- 自定义作业处理器
customJobHandlers
: 这是引擎配置留的扩展点,可以添加自定义作业处理器,如果类型和默认的作业处理器相同,则默认作业处理器将被替换。
3. 初始化作业管理器
public void initJobManager() {
if (this.jobManager == null) {
this.jobManager = new DefaultJobManager(this);
}
this.jobManager.setProcessEngineConfiguration(this);
}
DefaultJobManager
持有引擎配置实例ProcessEngineConfigurationImpl
,它可以很方便获取配置中的异步作业执行器AsyncExecutor
, 执行流管理器ExecutionEntityManager
, 其他的就是对JobManager
接口的实现.
public interface JobManager {
void execute(Job var1);
void unacquire(Job var1);
JobEntity createAsyncJob(ExecutionEntity var1, boolean var2);
void scheduleAsyncJob(JobEntity var1);
TimerJobEntity createTimerJob(TimerEventDefinition var1, boolean var2, ExecutionEntity var3, String var4, String var5);
void scheduleTimerJob(TimerJobEntity var1);
JobEntity moveTimerJobToExecutableJob(TimerJobEntity var1);
TimerJobEntity moveJobToTimerJob(AbstractJobEntity var1);
SuspendedJobEntity moveJobToSuspendedJob(AbstractJobEntity var1);
AbstractJobEntity activateSuspendedJob(SuspendedJobEntity var1);
DeadLetterJobEntity moveJobToDeadLetterJob(AbstractJobEntity var1);
JobEntity moveDeadLetterJobToExecutableJob(DeadLetterJobEntity var1, int var2);
void setProcessEngineConfiguration(ProcessEngineConfigurationImpl var1);
}
public class DefaultJobManager implements JobManager {
private static Logger logger = LoggerFactory.getLogger(DefaultJobManager.class);
protected ProcessEngineConfigurationImpl processEngineConfiguration;
//for simplicity, some method codes are omitted here.
......
}
4. 初始化异步作业执行器
-
这里设为初始化为默认的异步作业执行器
DefaultAsyncJobExecutor
,可以看到initAsyncExecutor
中很多setXooo()
, 在DefaultAsyncJobExecutor
中的确很多属性需要初始化。 -
我们可以看到在引擎配置类中有很多属性和
DefaultAsyncJobExecutor
中的属性相对应,比如ProcessEngineConfigurationImpl
中的asyncExecutorThreadPoolQueue
与DefaultAsyncJobExecutor
中的threadPoolQueue
对应,前者可以看做引擎留给开发者的开关属性
, 如果在引擎配置中配置了asyncExecutorThreadPoolQueue
,即不为空,就会设置到异步作业执行器中。public void initAsyncExecutor() { if (this.asyncExecutor == null) { DefaultAsyncJobExecutor defaultAsyncExecutor = new DefaultAsyncJobExecutor(); defaultAsyncExecutor.setMessageQueueMode(this.asyncExecutorMessageQueueMode); defaultAsyncExecutor.setCorePoolSize(this.asyncExecutorCorePoolSize); defaultAsyncExecutor.setMaxPoolSize(this.asyncExecutorMaxPoolSize); defaultAsyncExecutor.setKeepAliveTime(this.asyncExecutorThreadKeepAliveTime); if (this.asyncExecutorThreadPoolQueue != null) { defaultAsyncExecutor.setThreadPoolQueue(this.asyncExecutorThreadPoolQueue); } defaultAsyncExecutor.setQueueSize(this.asyncExecutorThreadPoolQueueSize); defaultAsyncExecutor.setDefaultTimerJobAcquireWaitTimeInMillis(this.asyncExecutorDefaultTimerJobAcquireWaitTime); defaultAsyncExecutor.setDefaultAsyncJobAcquireWaitTimeInMillis(this.asyncExecutorDefaultAsyncJobAcquireWaitTime); defaultAsyncExecutor.setDefaultQueueSizeFullWaitTimeInMillis(this.asyncExecutorDefaultQueueSizeFullWaitTime); defaultAsyncExecutor.setTimerLockTimeInMillis(this.asyncExecutorTimerLockTimeInMillis); defaultAsyncExecutor.setAsyncJobLockTimeInMillis(this.asyncExecutorAsyncJobLockTimeInMillis); if (this.asyncExecutorLockOwner != null) { defaultAsyncExecutor.setLockOwner(this.asyncExecutorLockOwner); } defaultAsyncExecutor.setResetExpiredJobsInterval(this.asyncExecutorResetExpiredJobsInterval); defaultAsyncExecutor.setResetExpiredJobsPageSize(this.asyncExecutorResetExpiredJobsPageSize); defaultAsyncExecutor.setSecondsToWaitOnShutdown(this.asyncExecutorSecondsToWaitOnShutdown); this.asyncExecutor = defaultAsyncExecutor; } this.asyncExecutor.setProcessEngineConfiguration(this); this.asyncExecutor.setAutoActivate(this.asyncExecutorActivate); }
解释下 重要的属性含义:
补充下
BlockingQueue
的介绍 :- http://www.cnblogs.com/WangHaiMing/p/8798709.html
- http://www.importnew.com/28053.html
- https://javadoop.com/post/AbstractQueuedSynchronizer-2
补充下
线程池
的介绍 :- https://blog.csdn.net/u010723709/article/details/50377543
- https://blog.csdn.net/siobhan/article/details/51282570
- https://www.jianshu.com/p/ae67972d1156
public class DefaultAsyncJobExecutor implements AsyncExecutor { private static Logger log = LoggerFactory.getLogger(DefaultAsyncJobExecutor.class); // corePoolSize : the recommended size of the number of threads in the thread pool. // If the actual number of threads in the thread pool is less than `corePoolSize`, create a new core thread first protected int corePoolSize = 2; // If all queues of non-running or working state in the thread pool are full, // but the current number of threads is less than the maximum number of allowed `maxPoolSize` threads, continue creating non-core threads to perform tasks. protected int maxPoolSize = 10; // Idle timeout for non-core threads: thread will be recycled when timeout. protected long keepAliveTime = 5000L; protected int queueSize = 100; // task queue : by default, use `ArrayBlockingQueue` for saving tasks waiting to be performed. // passed to `ThreadPoolExecutor` as parameters. protected BlockingQueue<Runnable> threadPoolQueue; // Thread pool protected ExecutorService executorService; protected long secondsToWaitOnShutdown = 60L; protected Thread timerJobAcquisitionThread; protected Thread asyncJobAcquisitionThread; protected Thread resetExpiredJobThread; protected AcquireTimerJobsRunnable timerJobRunnable; protected AcquireAsyncJobsDueRunnable asyncJobsDueRunnable; protected ResetExpiredJobsRunnable resetExpiredJobsRunnable; protected ExecuteAsyncRunnableFactory executeAsyncRunnableFactory; protected boolean isAutoActivate; //Indicates whether the job executor is activated protected boolean isActive; protected boolean isMessageQueueMode; //The maximum number of timer jobs acquired from database each time protected int maxTimerJobsPerAcquisition = 1; //The maximum number of asynchronous jobs acquired from database each time protected int maxAsyncJobsDuePerAcquisition = 1; protected int defaultTimerJobAcquireWaitTimeInMillis = 10000; protected int defaultAsyncJobAcquireWaitTimeInMillis = 10000; protected int defaultQueueSizeFullWaitTime = 0; protected String lockOwner = UUID.randomUUID().toString(); protected int timerLockTimeInMillis = 300000; protected int asyncJobLockTimeInMillis = 300000; protected int retryWaitTimeInMillis = 500; protected int resetExpiredJobsInterval = 60000; protected int resetExpiredJobsPageSize = 3; protected LinkedList<Job> temporaryJobQueue = new LinkedList(); protected ProcessEngineConfigurationImpl processEngineConfiguration; protected void initAsyncJobExecutionThreadPool() { if (this.threadPoolQueue == null) { log.info("Creating thread pool queue of size {}", this.queueSize); // if `threadPoolQueue` is not specified in `ProcessEngineCofiguration` , the `ArrayBlockingQueue` is as its default value. this.threadPoolQueue = new ArrayBlockingQueue(this.queueSize); } if (this.executorService == null) { log.info("Creating executor service with corePoolSize {}, maxPoolSize {} and keepAliveTime {}", new Object[]{this.corePoolSize, this.maxPoolSize, this.keepAliveTime}); // Factory for creating theads and add them to thread pool; BasicThreadFactory threadFactory = (new Builder()).namingPattern("activiti-async-job-executor-thread-%d").build(); // Thread pool : it implements the `Executor` interface. this.executorService = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, this.keepAliveTime, TimeUnit.MILLISECONDS, this.threadPoolQueue, threadFactory); } } // skip some methods ..... }
从默认的异步任务执行器可知,它维护了一个线程池,并且负责一些
Runnable
任务执行,
流程定时启动作业的调度时机
Activiti7中多个流程定义以捆绑式自动部署到流程引擎运行,向外提供
Runtime Bundle Service
,这里帮大家扒扒流程定时启动事件是怎么以作业的形式添加到数据库中,以待执行。
public void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings) {
log.debug("Processing deployment {}", deployment.getName());
// Parse the process document element and convert it to BpmnModel
ParsedDeployment parsedDeployment = this.parsedDeploymentBuilderFactory.getBuilderForDeploymentAndSettings(deployment, deploymentSettings).build();
// Irrelevant codes ...
// If the deployed process documentation is updated,...
if (deployment.isNew()) {
Map<ProcessDefinitionEntity, ProcessDefinitionEntity> mapOfNewProcessDefinitionToPreviousVersion =TimerJobEntityManager this.getPreviousVersionsOfProcessDefinitions(parsedDeployment);
this.setProcessDefinitionVersionsAndIds(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
this.persistProcessDefinitionsAndAuthorizations(parsedDeployment);
// The scheduled jobs and event subscriptions is updated here, if necessary
this.updateTimersAndEvents(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
}
// Irrelevant codes ...
}
- 框架Bpmn文档处理的分两阶段:
文档解析
+对象解析
。通过文档解析器BpmnParse
将文档解析成BpmnModel
,并持久化,在ParsedDeploymentBuilder.build()
中会调用BpmnParse
的execute()
, 这里就是文档解析的入口。 - 注意
updateTimersAndEvents
的调用,这里就会检查并更新事件订阅和定时任务。
public void updateTimersAndEvents(ProcessDefinitionEntity processDefinition, ProcessDefinitionEntity previousProcessDefinition, ParsedDeployment parsedDeployment) {
Process process = parsedDeployment.getProcessModelForProcessDefinition(processDefinition);
BpmnModel bpmnModel = parsedDeployment.getBpmnModelForProcessDefinition(processDefinition);
this.eventSubscriptionManager.removeObsoleteMessageEventSubscriptions(previousProcessDefinition);
this.eventSubscriptionManager.addMessageEventSubscriptions(processDefinition, process, bpmnModel);
this.eventSubscriptionManager.removeObsoleteSignalEventSubScription(previousProcessDefinition);
this.eventSubscriptionManager.addSignalEventSubscriptions(Context.getCommandContext(), processDefinition, process, bpmnModel);
this.timerManager.removeObsoleteTimers(processDefinition);
this.timerManager.scheduleTimers(processDefinition, process);
}
- 这里
BpmnDeployer
的helper类来帮忙了,在框架中Helper
很常见,可以看做现实世界中的助理吧,在这里应该算是委托类了。这里会依赖事件订阅管理器EventSubscriptionManager
和TimerManager
定时作业管理器来更新事件订阅或者定时作业。
protected void scheduleTimers(ProcessDefinitionEntity processDefinition, Process process) {
JobManager jobManager = Context.getCommandContext().getJobManager();
// Acquire the timer jobs declared on the start element
List<TimerJobEntity> timers = this.getTimerDeclarations(processDefinition, process);
Iterator var5 = timers.iterator();
while(var5.hasNext()) {
TimerJobEntity timer = (TimerJobEntity)var5.next();
// The default job manager schedules scheduled jobs to the database
jobManager.scheduleTimerJob(timer);
}
}
protected List<TimerJobEntity> getTimerDeclarations(ProcessDefinitionEntity processDefinition, Process process) {
JobManager jobManager = Context.getCommandContext().getJobManager();
List<TimerJobEntity> timers = new ArrayList();
if (CollectionUtil.isNotEmpty(process.getFlowElements())) {
Iterator var5 = process.getFlowElements().iterator();
while(var5.hasNext()) {
FlowElement element = (FlowElement)var5.next();
// If the current element is the start node, ...
if (element instanceof StartEvent) {
StartEvent startEvent = (StartEvent)element;
// irrelevant codes...
// add timer to timer jobs.
timers.add(timerJob);
}
}
}
添加作业到数据库
return timers;
}
}
- 在流程部署的过程中,会将声明在开始节点的定时事件,封装为定时作业,然后调度作业到数据库。【注意这里只是对流程启动相关的定时启动事件做调度】
边界定时作业On UserTask
的调度时机
前面介绍的
元素解析
阶段可能需要建立的定时作业,接下来介绍对象解析
阶段可能需要建立的的定时作业,这里以加在UserTask 上的边界定时事件为例。
- 在启动流程的过程中,会进行对象解析,这里我们关注定时事件对应的解析器
TimerEventDefinitionParseHandler
的核心方法executePasrse
方法。
protected void executeParse(BpmnParse bpmnParse, TimerEventDefinition timerEventDefinition) {
if (bpmnParse.getCurrentFlowElement() instanceof IntermediateCatchEvent) {
IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent)bpmnParse.getCurrentFlowElement();
intermediateCatchEvent.setBehavior(bpmnParse.getActivityBehaviorFactory().createIntermediateCatchTimerEventActivityBehavior(intermediateCatchEvent, timerEventDefinition));
} else if (bpmnParse.getCurrentFlowElement() instanceof BoundaryEvent) {
BoundaryEvent boundaryEvent = (BoundaryEvent)bpmnParse.getCurrentFlowElement();
boundaryEvent.setBehavior(bpmnParse.getActivityBehaviorFactory().createBoundaryTimerEventActivityBehavior(boundaryEvent, timerEventDefinition, boundaryEvent.isCancelActivity()));
}
}
- 大致逻辑给边界事件设置
行为对象
,在流程运转过程中执行到UserTask
节点,会执行Boundary Event
的行为对象
的execute
方法。
public void execute(DelegateExecution execution) {
ExecutionEntity executionEntity = (ExecutionEntity)execution;
if (!(execution.getCurrentFlowElement() instanceof BoundaryEvent)) {
throw new ActivitiException("Programmatic error: " + this.getClass() + " should not be used for anything else than a boundary event");
} else {
JobManager jobManager = Context.getCommandContext().getJobManager();
TimerJobEntity timerJob = jobManager.createTimerJob(this.timerEventDefinition, this.interrupting, executionEntity, "trigger-timer", TimerEventHandler.createConfiguration(execution.getCurrentActivityId(), this.timerEventDefinition.getEndDate(), this.timerEventDefinition.getCalendarName()));
if (timerJob != null) {
// The default job manager schedules scheduled jobs to the database
jobManager.scheduleTimerJob(timerJob);
}
}
}
jobManager.scheduleTimerJob(timerJob)
似曾相识, 这里和之前一样就是添加作业到数据库并加入缓存。
调度作业的过程
上文介绍了创建的作业和调度作业的时机,下面展开一下
DefaultJobManager
调度新作业到数据库的过程。
public void scheduleTimerJob(TimerJobEntity timerJob) {
if (timerJob == null) {
throw new ActivitiException("Empty timer job can not be scheduled");
} else {
this.processEngineConfiguration.getTimerJobEntityManager().insert(timerJob);
CommandContext commandContext = Context.getCommandContext();
ActivitiEventDispatcher eventDispatcher = commandContext.getEventDispatcher();
if (eventDispatcher.isEnabled()) {
eventDispatcher.dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.TIMER_SCHEDULED, timerJob));
}
}
}
- 这里会调用
TimerJobEntityManagerImpl
来将作业加入缓存并加到数据库,同时在引擎中dispatch
相关的事件。 - 以定时作业为例,定时作业
TimerJobEntity
的CRUD
由TimerJobEntityManager
管理:
public void insert(TimerJobEntity jobEntity, boolean fireCreateEvent) {
this.doInsert(jobEntity, fireCreateEvent);
}
protected boolean doInsert(TimerJobEntity jobEntity, boolean fireCreateEvent) {
if (jobEntity.getExecutionId() != null) {
ExecutionEntity execution = (ExecutionEntity)this.getExecutionEntityManager().findById(jobEntity.getExecutionId());
if (execution == null) {
return false;
}
// add `jobEntity` to `EntityCache`
execution.getTimerJobs().add(jobEntity);
if (execution.getTenantId() != null) {
jobEntity.setTenantId(execution.getTenantId());
}
if (this.isExecutionRelatedEntityCountEnabled(execution)) {
CountingExecutionEntity countingExecutionEntity = (CountingExecutionEntity)execution;
countingExecutionEntity.setTimerJobCount(countingExecutionEntity.getTimerJobCount() + 1);
}
}
super.insert(jobEntity, fireCreateEvent);
return true;
}
public void insert(EntityImpl entity, boolean fireCreateEvent) {
this.getDataManager().insert(entity);
ActivitiEventDispatcher eventDispatcher = this.getEventDispatcher();
//broadcast `ENTITY_CREATED` event in engine.
if (fireCreateEvent && eventDispatcher.isEnabled()) {
eventDispatcher.dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, entity));
eventDispatcher.dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_INITIALIZED, entity));
}
}
定时作业的触发时机
异步执行器的启动
流程引擎配置中默认是不开启异步作业执行器,需要在配置中激活它,设置asyncExecutorActivate
为true
即可。
public ProcessEngine buildProcessEngine() {
this.init();
ProcessEngineImpl processEngine = new ProcessEngineImpl(this);
this.postProcessEngineInitialisation();
return processEngine;
}
public ProcessEngineImpl(ProcessEngineConfigurationImpl processEngineConfiguration) {
// ignore some irrelevant codes ...
if (processEngineConfiguration.isUsingRelationalDatabase() && processEngineConfiguration.getDatabaseSchemaUpdate() != null) {
this.commandExecutor.execute(processEngineConfiguration.getSchemaCommandConfig(), new SchemaOperationsProcessEngineBuild());
}
if (this.name == null) {
log.info("default activiti ProcessEngine created");
} else {
log.info("ProcessEngine {} created", this.name);
}
ProcessEngines.registerProcessEngine(this);
if (this.asyncExecutor != null && this.asyncExecutor.isAutoActivate()) {
//start the the asynchronous executor , if the asynchronous executor is not `null` and is automatically activated
this.asyncExecutor.start();
}
if (processEngineConfiguration.getProcessEngineLifecycleListener() != null) {
processEngineConfiguration.getProcessEngineLifecycleListener().onProcessEngineBuilt(this);
}
processEngineConfiguration.getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createGlobalEvent(ActivitiEventType.ENGINE_CREATED));
}
- 如果以
ProcessEngineFactoryBean
或者其他方式new
流程引擎实例,需要调用buildProcessEngine
来构造, 在构造器中会启动异步执行器。
public void start() {
if (!this.isActive) {
log.info("Starting up the default async job executor [{}].", this.getClass().getName());
if (this.timerJobRunnable == null) {
this.timerJobRunnable = new AcquireTimerJobsRunnable(this, this.processEngineConfiguration.getJobManager());
}
if (this.resetExpiredJobsRunnable == null) {
this.resetExpiredJobsRunnable = new ResetExpiredJobsRunnable(this);
}
//If the message queuing mode is adopted, the thread polling mode is discarded.
if (!this.isMessageQueueMode && this.asyncJobsDueRunnable == null) {
this.asyncJobsDueRunnable = new AcquireAsyncJobsDueRunnable(this);
}
if (!this.isMessageQueueMode) {
this.initAsyncJobExecutionThreadPool();
this.startJobAcquisitionThread();
}
this.startTimerAcquisitionThread();
this.startResetExpiredJobsThread();
this.isActive = true;
this.executeTemporaryJobs();
}
}
在启动方法,会开启是三个线程分别执行三个Runnable
的Job, asyncJobAcquisitionThread
与 timerJobAcquisitionThread
采用轮询数据库查询新的作业。
asyncJobAcquisitionThread -> AcquireAsyncJobsDueRunnable
: 监听新的需要执行的异步作业,交给JobManager处理;timerJobAcquisitionThread -> AcquireTimerJobsRunnable
: 监听新的需要执行的定时作业,交给JobManager处理;resetExpiredJobThread -> ResetExpiredJobsRunnable
: 监听过期作业,重置过期作业;
protected void executeTemporaryJobs() {
while(!this.temporaryJobQueue.isEmpty()) {
Job job = (Job)this.temporaryJobQueue.pop();
this.executeAsyncJob(job);
}
}
public boolean executeAsyncJob(final Job job) {
if (this.isMessageQueueMode) {
return true;
} else {
Runnable runnable = null;
if (this.isActive) {
//wrap the job as `Runnable` instance.
runnable = this.createRunnableForJob(job);
try {
//submit the job to thread pool.
this.executorService.execute(runnable);
} catch (RejectedExecutionException var5) {
CommandContext commandContext = Context.getCommandContext();
if (commandContext != null) {
commandContext.getJobManager().unacquire(job);
} else {
this.processEngineConfiguration.getCommandExecutor().execute(new Command<Void>() {
public Void execute(CommandContext commandContext) {
commandContext.getJobManager().unacquire(job);
return null;
}
});
}
return false;
}
} else {
//if 'AsyncExecutor` is not activated, add job to the queue of temporary jobs.
this.temporaryJobQueue.add(job);
}
return true;
}
}
- 遍历临时作业队列
temporaryJobQueue
中的作业,如果此时异步执行器已经激活,直接封装Runnable
对象,提交给线程池executorService
执行,否则先暂存在临时作业队列中。
定时作业轮询线程
这里我们需要关注的是执行
AcquireTimerJobsRunnable
对象线程,它负责不断轮询数据库(在不考虑MessageQueue
的模式中)中需要当前时间以前执行的作业。
public class AcquireTimerJobsRunnable implements Runnable {
private static Logger log = LoggerFactory.getLogger(AcquireTimerJobsRunnable.class);
protected final AsyncExecutor asyncExecutor;
protected final JobManager jobManager;
protected volatile boolean isInterrupted;
protected final Object MONITOR = new Object();
protected final AtomicBoolean isWaiting = new AtomicBoolean(false);
protected long millisToWait;
public AcquireTimerJobsRunnable(AsyncExecutor asyncExecutor, JobManager jobManager) {
this.asyncExecutor = asyncExecutor;
this.jobManager = jobManager;
}
public synchronized void run() {
log.info("{} starting to acquire async jobs due");
Thread.currentThread().setName("activiti-acquire-timer-jobs");
CommandExecutor commandExecutor = this.asyncExecutor.getProcessEngineConfiguration().getCommandExecutor();
while(true) {
do {
if (this.isInterrupted) {
log.info("{} stopped async job due acquisition");
return;
}
try {
// Query the current jobs that need to be executed against the database
final AcquiredTimerJobEntities acquiredJobs = (AcquiredTimerJobEntities)commandExecutor.execute(new AcquireTimerJobsCmd(this.asyncExecutor));
commandExecutor.execute(new Command<Void>() {
public Void execute(CommandContext commandContext) {
Iterator var2 = acquiredJobs.getJobs().iterator();
while(var2.hasNext()) {
TimerJobEntity job = (TimerJobEntity)var2.next();
// Adds the the result set to the executable job set.
AcquireTimerJobsRunnable.this.jobManager.moveTimerJobToExecutableJob(job);
}
return null;
}
});
this.millisToWait = (long)this.asyncExecutor.getDefaultTimerJobAcquireWaitTimeInMillis();
int jobsAcquired = acquiredJobs.size();
if (jobsAcquired >= this.asyncExecutor.getMaxTimerJobsPerAcquisition()) {
this.millisToWait = 0L;
}
} catch (ActivitiOptimisticLockingException var11) {
if (log.isDebugEnabled()) {
log.debug("Optimistic locking exception during timer job acquisition. If you have multiple timer executors running against the same database, this exception means that this thread tried to acquire a timer job, which already was acquired by another timer executor acquisition thread.This is expected behavior in a clustered environment. You can ignore this message if you indeed have multiple timer executor acquisition threads running against the same database. Exception message: {}", var11.getMessage());
}
} catch (Throwable var12) {
log.error("exception during timer job acquisition: {}", var12.getMessage(), var12);
this.millisToWait = (long)this.asyncExecutor.getDefaultTimerJobAcquireWaitTimeInMillis();
}
} while(this.millisToWait <= 0L);
try {
if (log.isDebugEnabled()) {
log.debug("timer job acquisition thread sleeping for {} millis", this.millisToWait);
}
Object var16 = this.MONITOR;
// When the thread sleeps, release the object `this.MONITOR` and sleep for a while
synchronized(this.MONITOR) {
if (!this.isInterrupted) {
this.isWaiting.set(true);
this.MONITOR.wait(this.millisToWait);
}
}
if (log.isDebugEnabled()) {
log.debug("timer job acquisition thread woke up");
}
} catch (InterruptedException var14) {
if (log.isDebugEnabled()) {
log.debug("timer job acquisition wait interrupted");
}
} finally {
//Wake up the thread after timeout and re-hold the lock.
this.isWaiting.set(false);
}
}
}
// omit some irrelevant codes.
}
- 轮询时间间隔
defaultTimerJobAcquireWaitTimeInMillis
可以自己配置,这里默认是10000ms
。 - 这里用到java多线程中的监视器锁
monitor
(intrinsic lock
)进行同步,传送门? - 线程休眠时使用了释放某个特定对象
this.MONITOR
,休眠指定时间,超时唤醒线程重新获得该锁,这里也对run
方法的引用对象this
上了锁,每次只有一个线程进入,好像这里暂时只开启了一个轮询线程。。。。 - 轮询的时候会执行
AcquireTimerJobsCmd
命令,去查询数据库需要执行的定时作业。 jobManager.moveTimerJobToExecutableJob(job)
将查询到的作业加入需要加入到可执行作业集合。
public JobEntity moveTimerJobToExecutableJob(TimerJobEntity timerJob) {
if (timerJob == null) {
throw new ActivitiException("Empty timer job can not be scheduled");
} else {
JobEntity executableJob = this.createExecutableJobFromOtherJob(timerJob);
//update the job entity and re-insert into the database and cache.
boolean insertSuccesful = this.processEngineConfiguration.getJobEntityManager().insertJobEntity(executableJob);
if (insertSuccesful) {
// delete the timer job
this.processEngineConfiguration.getTimerJobEntityManager().delete(timerJob);
// trigger the job execution.
this.triggerExecutorIfNeeded(executableJob);
return executableJob;
} else {
return null;
}
}
}
protected void triggerExecutorIfNeeded(JobEntity jobEntity) {
if (this.isAsyncExecutorActive()) {
this.hintAsyncExecutor(jobEntity);
}
}
protected void hintAsyncExecutor(JobEntity job) {
AsyncJobAddedNotification jobAddedNotification = new AsyncJobAddedNotification(job, this.getAsyncExecutor());
this.getCommandContext().addCloseListener(jobAddedNotification);
}
- 这里显示
JobEntityManagerImpl
重新插入数据库和缓存,我这里暂时理解为更新,如果插入成功,TimerJobEntityManager
就删除作业实体,这里前面刚更新后面就删除,这里应该有区别,我可能这里说的不对,存疑! triggerExecutorIfNeeded(executableJob)
这里就是触发作业执行的时机,跟踪到hintAsyncExecutor
, 最后一直到AsyncJobAddedNotification
, 他是实现了CommandContextCloseListener
, 在执行执行命令拦截器调用链结束时,最后会关闭命令上下文这是会执行命令上下问关闭监听器的closed
方法。
public void closed(CommandContext commandContext) {
CommandExecutor commandExecutor = commandContext.getProcessEngineConfiguration().getCommandExecutor();
CommandConfig commandConfig = new CommandConfig(false, TransactionPropagation.REQUIRES_NEW);
commandExecutor.execute(commandConfig, new Command<Void>() {
public Void execute(CommandContext commandContext) {
if (AsyncJobAddedNotification.log.isTraceEnabled()) {
AsyncJobAddedNotification.log.trace("notifying job executor of new job");
}
// Submit the timed job to thread pool for execution
AsyncJobAddedNotification.this.asyncExecutor.executeAsyncJob(AsyncJobAddedNotification.this.job);
return null;
}
});
}
protected Runnable createRunnableForJob(Job job) {
return (Runnable)(this.executeAsyncRunnableFactory == null ? new ExecuteAsyncRunnable(job, this.processEngineConfiguration) : this.executeAsyncRunnableFactory.createExecuteAsyncRunnable(job, this.processEngineConfiguration));
}
this.asyncExecutor.executeAsyncJob()
: 最后兜了一圈,发现它最后还是把作业交给了线程池执行。。。- 而线程池执行作业是调用封装作业的
Runnable
对象ExecuteAsyncRunnable
的run
方法
线程池执行定时作业
反正最后作业都还是要走
Thread Pool
这一遭,接下来从Runanble
对象开始扒。
public void run() {
// make sure that job is not null. If null, query once again.
if (this.job == null) {
this.job = (Job)this.processEngineConfiguration.getCommandExecutor().execute(new Command<JobEntity>() {
public JobEntity execute(CommandContext commandContext) {
return (JobEntity)commandContext.getJobEntityManager().findById(ExecuteAsyncRunnable.this.jobId);
}
});
}
// if not handed over to the Activiti5 Engine for handling.
if (!this.isHandledByActiviti5Engine()) {
boolean lockNotNeededOrSuccess = this.lockJobIfNeeded();
if (lockNotNeededOrSuccess) {
// execute job
this.executeJob();
this.unlockJobIfNeeded();
}
}
}
protected void executeJob() {
try {
// Execute the commands to process asynchronous jobs.
this.processEngineConfiguration.getCommandExecutor().execute(new ExecuteAsyncJobCmd(this.jobId));
}
// ignore some clause catching exception ...
}
- 在
run
方法中,首先确保提交过来的作业不是空作业,如果是空的得继续再通过作业实体管理器查查。正常情况下不为空,就直接提交给executeJob
函数处理。 - 在
executeJob
函数中,一行代码是核心,其他是捕获异常,这主要是执行处理异步作业的命令,这就又得去看看这个ExecuteAsyncJobCmd
命令的核心函数execute
干了什么活。
public Object execute(CommandContext commandContext) {
if (this.jobId == null) {
throw new ActivitiIllegalArgumentException("jobId is null");
} else {
Job job = (Job)commandContext.getJobEntityManager().findById(this.jobId);
if (job == null) {
log.debug("Job does not exist anymore and will not be executed. It has most likely been deleted as part of another concurrent part of the process instance.");
return null;
} else {
if (log.isDebugEnabled()) {
log.debug("Executing async job {}", job.getId());
}
// Execute the async job by DefaultJobManager
commandContext.getJobManager().execute(job);
if (commandContext.getEventDispatcher().isEnabled()) {
commandContext.getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.JOB_EXECUTION_SUCCESS, job));
}
return null;
}
}
}
- 这里又是先检查作业是否为空,为空就重新查查,不为空就提交给
DefaultJobManager
的execute
来处理,和前面ExecuteAsyncRunnable
的run
方法的如出一辙,还是没有真正干点实际的活,都是一层层嵌套调用,处理一些附带的任务,核心业务还没出来。。。 - 这里还干了一点活,就是在引擎中广播作业执行成功的时间
JOB_EXECUTION_SUCCESS
,不过实在作业管理器把作业处理完之后的事。
定时作业的执行
作业管理器
引擎的默认作业管理器是
DefaultJobManager
累,作业的调度添加由其门下的scheduleTimerJob
处理,作业调度待执行由其门下的moveXooJobToExecutableJob
处理,作业的执行由其门下的execute
执行。虽然分析过程一层层嵌套,但类的职责分的还是十分清楚的,分层职责分明,但是调用栈很深。
public void execute(Job job) {
// judge the type of the job
if (job instanceof JobEntity) {
if ("message".equals(job.getJobType())) {
this.executeMessageJob((JobEntity)job);
} else if ("timer".equals(job.getJobType())) {
// hand over to executeTimerJob function
this.executeTimerJob((JobEntity)job);
}
} else {
throw new ActivitiException("Only jobs with type JobEntity are supported to be executed");
}
}
protected void executeTimerJob(JobEntity timerEntity) {
TimerJobEntityManager timerJobEntityManager = this.processEngineConfiguration.getTimerJobEntityManager();
VariableScope variableScope = null;
// get the associated variables, if the execution to which the job currently belongs is not null.
if (timerEntity.getExecutionId() != null) {
variableScope = (VariableScope)this.getExecutionEntityManager().findById(timerEntity.getExecutionId());
}
if (variableScope == null) {
variableScope = NoExecutionVariableScope.getSharedInstance();
}
// resolve and fill the `endDate` filed of the timer entity.
this.restoreExtraData(timerEntity, (VariableScope)variableScope);
if (timerEntity.getDuedate() != null && !this.isValidTime(timerEntity, timerEntity.getDuedate(), (VariableScope)variableScope)) {
if (logger.isDebugEnabled()) {
logger.debug("Timer {} fired. but the dueDate is after the endDate. Deleting timer.", timerEntity.getId());
}
this.processEngineConfiguration.getJobEntityManager().delete(timerEntity);
} else {
// hand over to the `executeJobHandler` for the further handling
this.executeJobHandler(timerEntity);
this.processEngineConfiguration.getJobEntityManager().delete(timerEntity);
if (logger.isDebugEnabled()) {
logger.debug("Timer {} fired. Deleting timer.", timerEntity.getId());
}
if (timerEntity.getRepeat() != null) {
TimerJobEntity newTimerJobEntity = timerJobEntityManager.createAndCalculateNextTimer(timerEntity, (VariableScope)variableScope);
if (newTimerJobEntity != null) {
this.scheduleTimerJob(newTimerJobEntity);
}
}
}
}
protected void executeJobHandler(JobEntity jobEntity) {
ExecutionEntity execution = null;
if (jobEntity.getExecutionId() != null) {
execution = (ExecutionEntity)this.getExecutionEntityManager().findById(jobEntity.getExecutionId());
}
Map<String, JobHandler> jobHandlers = this.processEngineConfiguration.getJobHandlers();
JobHandler jobHandler = (JobHandler)jobHandlers.get(jobEntity.getJobHandlerType());
jobHandler.execute(jobEntity, jobEntity.getJobHandlerConfiguration(), execution, this.getCommandContext());
}
execute
根据作业的类型进行分流处理,定时作业交由executeTimerJob
处理。executeTimerJob
中会先检查作业中关联的执行流Id
是否null
,如果不为null
则获取VariableScope
实例,这里应该是从数据库中读取和TimerEntity
相关的流程变量,这里是主要是通过restoreExtraData
函数设置定时器实体中的EndDate
, 如果fire
定时作业的时间即dueDate
晚于EndDate
,就需要是删除定时作业。比如我启动一个循环的定时作业,每隔一段时间执行一个定时作业,但是也指定了一个失效时间EndDate
,那么如果在EndDate
之后,就不需要产生新的定时作业,需要删除掉定时器。【注:粗浅理解,存疑,望大神指正】- 如果这个定时作业是合法的,即合乎上面说的定时器失效时间限制,不过我这里不是循环定时作业,也未指定
EndDate
,当然没问题,接着就将作业递交给`executeJobHandler`处理。处理完成之后,就删除定时器。 executeJobHandler
中获取引擎中配置的作业处理器,我这里测试的作业类型是trigger-timer
, 对应是TriggerTimerEventJobHandler
, 接下来终于到了压轴。
作业处理器
在引擎配置和初始化阶段,陪住了许多
JobHandlers
, 默认或者自定义,接下来就排上用场了!
public void execute(JobEntity job, String configuration, ExecutionEntity execution, CommandContext commandContext) {
//submit `trigger-execution-operation` to the agenda of the activiti engine.
Context.getAgenda().planTriggerExecutionOperation(execution);
if (commandContext.getEventDispatcher().isEnabled()) {
commandContext.getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.TIMER_FIRED, job));
}
// omit some irrelevant codes.
}
- 这里就基本水落石出了,将触发执行的操作
TriggerExecutionOperation
提交DefaultActivitiEngineAgenda
, 这里的默认流程引擎代理替代了以前的流程虚拟机(PVM) , 给发出定时触发事件TIMER_FIRED
。这里引擎代理之流程运转机制在此就不展开了,只需知道Operation
提交给引擎代理后,Operation
中的run
方法就会排队等待执行。下面来看TriggerTimerEventJobHandler
之核心逻辑run
方法。
public void run() {
FlowElement currentFlowElement = this.getCurrentFlowElement(this.execution);
if (currentFlowElement instanceof FlowNode) {
ActivityBehavior activityBehavior = (ActivityBehavior)((FlowNode)currentFlowElement).getBehavior();
if (activityBehavior instanceof TriggerableActivityBehavior) {
if (currentFlowElement instanceof BoundaryEvent) {
this.commandContext.getHistoryManager().recordActivityStart(this.execution);
}
// Recourse to the `trigger` function of the `BoundaryEventActivityBehavior` class
((TriggerableActivityBehavior)activityBehavior).trigger(this.execution, (String)null, (Object)null);
if (currentFlowElement instanceof BoundaryEvent) {
this.commandContext.getHistoryManager().recordActivityEnd(this.execution, (String)null);
}
} else {
throw new ActivitiException("Invalid behavior: " + activityBehavior + " should implement " + TriggerableActivityBehavior.class.getName());
}
} else {
throw new ActivitiException("Programmatic error: no current flow element found or invalid type: " + currentFlowElement + ". Halting.");
}
}
BoundaryTimerEventActivityBehavior
继承了父类是BoundaryEventActivityBehavior
的trigger
方法。- 最终触发操作会求助与边界事件的行为
BoundaryTimerEventActivityBehavior
对象的trigger
方法,从而推动到流程的运转。
活动行为类
不管是作业处理器,还是其他什么处理器,想对流程的运转做点实质性的干预小动作
Operation
,最终还是要求助于活动行为类的对象。比如这里的BoundaryTimerEventActivityBehavior
.
public void trigger(DelegateExecution execution, String triggerName, Object triggerData) {
ExecutionEntity executionEntity = (ExecutionEntity)execution;
CommandContext commandContext = Context.getCommandContext();
if (this.interrupting) {
this.executeInterruptingBehavior(executionEntity, commandContext);
} else {
this.executeNonInterruptingBehavior(executionEntity, commandContext);
}
}
- 如果边界事件是中断式的(即:如果附加在用户任务上,就是用户任务当前执行流及其子执行流都将
cancelled
),就交给executeInterruptingBehavior
, 反之就交给executeNonInterruptingBehavior
进一步处理。
总结
- 贴的代码有点多,但是我都附了代码的类名(在IDEA中双击
shift
,键如类名,就能找到类所在),跟着上述流程走一遍应该能顺清定时作业的生生死死? - 此处应该差一张架构图?