activiti用法随记

news2024/12/25 1:39:51

案例: 

摘抄于官网,假设我们有如下流程:

流程对应的bpmn文件如下: 

<definitions xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" id="definitions" targetNamespace="http://activiti.org/bpmn20">
   <process id="financialReport" name="编写月度财务报告">
       <startEvent id="theStart"/>
       <sequenceFlow id="flow1" sourceRef="theStart" targetRef="writeReportTask"/>
       <userTask id="writeReportTask" name="Write monthly financial report">
           <documentation>Write monthly financial report for publication to shareholders.</documentation>
           <potentialOwner>
               <resourceAssignmentExpression>
                   <formalExpression>accountancy</formalExpression>
               </resourceAssignmentExpression>
           </potentialOwner>
       </userTask>
       <sequenceFlow id="flow2" sourceRef="writeReportTask" targetRef="verifyReportTask"/>
       <userTask id="verifyReportTask" name="验证月度财务报告">
           <documentation>Verify monthly financial report composed by the accountancy department. This financial report is going to be sent to all the company shareholders.</documentation>
           <potentialOwner>
               <resourceAssignmentExpression>
                   <formalExpression>management</formalExpression>
               </resourceAssignmentExpression>
           </potentialOwner>
       </userTask>
       <sequenceFlow id="flow3" sourceRef="verifyReportTask" targetRef="theEnd"/>
       <endEvent id="theEnd"/>
   </process>
   <bpmndi:BPMNDiagram>
       <bpmndi:BPMNPlane bpmnElement="financialReport">
           <bpmndi:BPMNShape bpmnElement="theStart">
               <omgdc:Bounds height="30.0" width="30.0" x="75.0" y="225.0"/>
           </bpmndi:BPMNShape>
           <bpmndi:BPMNShape bpmnElement="writeReportTask">
               <omgdc:Bounds height="80.0" width="100.0" x="165.0" y="200.0"/>
           </bpmndi:BPMNShape>
           <bpmndi:BPMNShape bpmnElement="verifyReportTask">
               <omgdc:Bounds height="80.0" width="100.0" x="330.0" y="200.0"/>
           </bpmndi:BPMNShape>
           <bpmndi:BPMNShape bpmnElement="theEnd">
               <omgdc:Bounds height="28.0" width="28.0" x="480.0" y="226.0"/>
           </bpmndi:BPMNShape>
           <bpmndi:BPMNEdge bpmnElement="flow1">
               <omgdi:waypoint x="105.0" y="240.0"/>
               <omgdi:waypoint x="165.0" y="240.0"/>
           </bpmndi:BPMNEdge>
           <bpmndi:BPMNEdge bpmnElement="flow2">
               <omgdi:waypoint x="265.0" y="240.0"/>
               <omgdi:waypoint x="330.0" y="240.0"/>
           </bpmndi:BPMNEdge>
           <bpmndi:BPMNEdge bpmnElement="flow3">
               <omgdi:waypoint x="430.0" y="240.0"/>
               <omgdi:waypoint x="480.0" y="240.0"/>
           </bpmndi:BPMNEdge>
       </bpmndi:BPMNPlane>
   </bpmndi:BPMNDiagram>
</definitions>

此bpmn保存为文件,可以在如下网站中上传查看对应的流程图:bpmn-js: BPMN 2.0 rendering toolkit and web modeler | Toolkits | bpmn.io

public class TenMinuteTutorial {

  public static void main(String[] args) {

    // 创建 Activiti 流程引擎
    ProcessEngine processEngine = ProcessEngineConfiguration
      .createStandaloneProcessEngineConfiguration()
      .buildProcessEngine();

    // 创建流程定义文件管理对象
    RepositoryService repositoryService = processEngine.getRepositoryService();
    RuntimeService runtimeService = processEngine.getRuntimeService();

    // 部署流程定义文件
    repositoryService.createDeployment()
      .addClasspathResource("FinancialReportProcess.bpmn20.xml")
      .deploy();

    // 开启一个流程定义实例
    String procId = runtimeService.startProcessInstanceByKey("financialReport").getId();

    // 获取第一个任务
    TaskService taskService = processEngine.getTaskService();
    //获取accountancy候选组列表
    List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
    for (Task task : tasks) {
      System.out.println("Following task is available for accountancy group: " + task.getName());
    
      // 申领任务。申领任务意味着将任务从候选状态(可能是多个用户或组可以申领的状态)转变为由特定用户负责的状态。一旦任务被申领,它将不再对其他用户或组可见,除非它被释放或完成。
      taskService.claim(task.getId(), "fozzie");
    }

    // Fozzie 完成他所签收申领的任务
    tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
    for (Task task : tasks) {
      System.out.println("Task for fozzie: " + task.getName());
      // Complete the task
      taskService.complete(task.getId());
    }

    System.out.println("Number of tasks for fozzie: "
            + taskService.createTaskQuery().taskAssignee("fozzie").count());

    // kermit 签收第二个任务
    tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
    for (Task task : tasks) {
      System.out.println("Following task is available for management group: " + task.getName());
      taskService.claim(task.getId(), "kermit");
    }

    // 完成这个任务
    for (Task task : tasks) {
      taskService.complete(task.getId());
    }

    // 历史服务对象,可查任务历史情况
    HistoryService historyService = processEngine.getHistoryService();
    HistoricProcessInstance historicProcessInstance =
      historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
    System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
  }

}

一、Activiti 部署bpmn只需要部署一次就行了吗?

Activiti部署BPMN文件(通常是.bpmn或.bpmn20.xml文件)的过程涉及将流程定义文件加载到Activiti引擎中,使其可以被引擎解析和执行。关于Activiti部署BPMN文件是否需要只部署一次,这取决于具体的场景和需求。

  1. 一次性部署
    • 在大多数情况下,BPMN文件只需要被部署一次。一旦BPMN文件被成功部署到Activiti引擎中,引擎就会解析文件内容,并将其存储在数据库中(如参考文章2所述,通常涉及act_re_deploymentact_re_procdefact_ge_bytearray等表)。
    • 引擎会基于这些存储的信息来执行相应的流程实例。只要BPMN文件内容没有变化,并且流程定义(由BPMN文件定义)没有被修改或删除,那么就不需要再次部署该文件。
  2. 重新部署
    • 如果BPMN文件内容发生了变化(例如,流程中的某个活动被添加、删除或修改),或者需要更新流程定义的版本,那么就需要重新部署BPMN文件。重新部署会覆盖之前的流程定义,使引擎使用新的定义来执行流程实例。
    • 在Activiti中,当流程定义的key相同时,新的部署会被视为是对旧版本的升级(如参考文章2所述)。这意味着,如果重新部署一个具有相同key的BPMN文件,旧的流程定义版本将被新的版本替换。
  3. 动态部署
    • 除了通过文件系统进行部署外,Activiti还支持动态部署,即直接在代码中创建和部署BPMN模型(如参考文章4所述)。这种方式允许在运行时创建和修改流程定义,而无需预先准备BPMN文件。

Activiti部署BPMN文件通常只需要一次,但在需要更新或修改流程定义时,可能需要重新部署。此外,Activiti还支持动态部署BPMN模型,以满足更灵活的需求。

二、activiti必须需要bpmn文件吗?

Activiti 不一定需要 BPMN 文件。尽管 BPMN(Business Process Model and Notation)文件是 Activiti 中定义业务流程的一种常见方式,但 Activiti 引擎也支持其他方式来定义流程。

BPMN 是一种图形化表示业务流程的建模符号,它允许用户通过图形化的方式定义复杂的业务流程。Activiti 支持 BPMN 2.0 规范,这使得用户可以使用 BPMN 编辑器(如 Activiti Modeler)创建 BPMN 文件,并将其部署到 Activiti 引擎中。

然而,除了 BPMN 文件之外,Activiti 还支持其他方式来定义流程:

  1. Java API:Activiti 提供了 Java API,允许开发人员通过编程方式定义流程。这通常适用于那些需要动态创建或修改流程的场景。

  2. XML 配置文件:虽然 BPMN 文件本质上也是 XML 文件,但 Activiti 还支持更通用的 XML 配置方式,用于定义流程属性、表单属性等。

  3. 流程定义语言(BPEL):虽然 Activiti 主要支持 BPMN,但它也可能通过扩展或插件支持其他流程定义语言,如 BPEL(Business Process Execution Language)。

  4. 数据库直接操作:理论上,用户也可以直接操作 Activiti 使用的数据库表来定义流程,但这通常是不推荐的,因为这需要深入了解 Activiti 的内部实现,并且容易出错。

尽管 BPMN 文件不是 Activiti 的必需条件,但它提供了一种直观、易于理解的流程定义方式,对于大多数业务流程管理(BPM)场景来说是非常有用的。因此,在大多数情况下,建议使用 BPMN 文件来定义和部署流程到 Activiti 引擎中。

三、.bpmn文件和.bpmn20.xml有什么区别呢?

.bpmn文件和.bpmn20.xml文件在本质上都是为了描述业务流程模型与符号(BPMN)而使用的文件格式,但它们在实际使用中可能存在一些细微的差别,以下是对这两种文件格式的详细解释和比较:

  1. 文件格式标准
    • .bpmn文件:这是一种通常用于描述BPMN模型的通用文件格式。然而,在实际应用中,具体的文件扩展名可能因不同的工具或系统而有所不同。有时,人们可能会直接使用.bpmn作为扩展名来表示BPMN模型文件,但这并不是BPMN标准所规定的特定格式。
    • .bpmn20.xml文件:这种文件格式明确指出了它遵循的是BPMN 2.0规范,并使用XML(可扩展标记语言)来具体描述业务流程。BPMN 2.0是一套由对象管理组织(OMG)定义的标准,旨在提供一种图形化表示业务流程的方法,并允许使用XML进行精确的技术细节描述和元素执行语法的制定(如参考文章2和4所述)。
  2. 内容表示
    • 两种文件格式在内容上都是用来表示BPMN模型的,包括流程的开始和结束、任务、网关、子流程等。然而,.bpmn20.xml文件通过XML语言明确规定了这些元素的可执行语法,使得文件可以被任何兼容BPMN 2.0的流程引擎解析和执行。
  3. 使用场景
    • .bpmn文件:由于它是一种通用的文件格式,因此可能在不同的工具或系统中具有不同的解释和处理方式。在某些情况下,它可能仅仅是一个用于编辑和查看的图形文件,而不包含完整的可执行语法。
    • .bpmn20.xml文件:由于它明确遵循BPMN 2.0规范和XML语法,因此它可以在任何支持该标准的流程引擎中执行。这使得.bpmn20.xml文件成为在Activiti等BPM系统中定义和部署业务流程的首选格式。
  4. 示例
    • 假设我们有一个简单的业务流程,包括一个开始事件、一个任务和一个结束事件。在.bpmn文件中,这个流程可能以图形化的方式表示出来,但具体的执行语法可能不明确。而在.bpmn20.xml文件中,这个流程会被描述为一系列XML元素,包括<startEvent><task><endEvent>等,并且每个元素都会包含详细的属性和子元素来定义其执行语义。

总结来说,.bpmn文件和.bpmn20.xml文件都是用于描述BPMN模型的文件格式,但.bpmn20.xml文件明确遵循BPMN 2.0规范和XML语法,因此具有更强的可执行性和通用性。在Activiti等BPM系统中,通常推荐使用.bpmn20.xml文件来定义和部署业务流程。

四、bpmn文件重新部署会影响前面未走完的流程吗?

当BPMN文件重新部署时,是否会影响前面未走完的流程,这主要取决于Activiti的流程定义版本控制和部署策略。以下是对此问题的详细分析:

  1. 版本控制
    • Activiti支持流程定义的版本控制。当同一个流程定义(由BPMN文件中的key属性标识)被重新部署时,新的部署被视为该流程定义的一个新版本。旧的版本仍然存在,直到所有基于该版本的流程实例都完成执行。
    • 在Activiti中,流程实例总是按照它们启动时所使用的流程定义版本来执行的。因此,重新部署BPMN文件(即引入新版本)不会影响已经启动的流程实例。这些实例将继续按照它们启动时的版本执行。
  2. 部署策略
    • 当你重新部署BPMN文件时,Activiti会创建一个新的流程定义版本,并将新的BPMN文件内容存储到数据库中。但请注意,这并不会自动更新或修改已经存在的流程实例。
    • 对于新的流程实例(即在重新部署后启动的流程实例),它们将使用新的流程定义版本。而对于旧的流程实例,它们将继续使用它们启动时所使用的版本。
  3. 影响分析
    • 如果重新部署的BPMN文件与旧版本有显著的差异(例如,某个任务被删除或修改),那么这可能会影响那些尚未完成但即将执行到该差异部分的流程实例。但由于Activiti的版本控制机制,这些实例将不会受到直接影响,它们仍然会按照旧版本的定义执行。
    • 在某些情况下,你可能需要手动干预来处理这种差异。例如,你可以考虑使用Activiti的API来暂停、迁移或终止那些受到影响的流程实例。
  4. 总结
    • 重新部署BPMN文件不会直接影响已经启动的流程实例。这些实例将继续按照它们启动时所使用的流程定义版本来执行。
    • 新的流程实例将使用重新部署后的BPMN文件所定义的新版本。
    • 如果新旧版本之间存在显著差异,可能需要手动干预来处理那些受到影响的流程实例。

五、activiti启动时需要指定启动流程的版本吗?

在Activiti中启动流程时,通常不需要直接指定启动流程的版本。Activiti通过流程定义的key来识别和启动相应的流程实例,而不是通过版本号。以下是对此问题的详细解释:

  1. 流程定义与版本
    • 在Activiti中,BPMN文件被部署到引擎中后,会生成一个或多个流程定义(ProcessDefinition)。每个流程定义都有一个唯一的key和可能的一个或多个版本。这些版本是根据BPMN文件的修改和重新部署来自动管理的。
    • 当BPMN文件被重新部署时,如果流程定义的key没有变化,那么会创建一个新的版本。旧的版本仍然存在于系统中,直到所有基于该版本的流程实例都完成执行。
  2. 启动流程实例
    • 当你想要启动一个新的流程实例时,你通常会使用流程定义的key来引用它。例如,在Activiti的API中,你可以使用RuntimeService.startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables)方法来启动流程实例。这里,processDefinitionKey是你要启动的流程的key,而不是版本号。
    • Activiti会根据你提供的key找到最新的活动(即未被标记为暂停的)流程定义版本来启动流程实例。如果有多个版本都是活动的,Activiti通常会选择最新版本。
  3. 指定版本(如果需要)
    • 虽然通常不需要直接指定版本,但在某些情况下,你可能想要启动一个特定版本的流程实例。这可以通过先查询特定版本的流程定义ID(processDefinitionId),然后使用该ID来启动流程实例来实现。例如,你可以使用RuntimeService.startProcessInstanceById(String processDefinitionId, Map<String, Object> variables)方法来启动流程实例。
    • 但请注意,这种做法通常不是必需的,并且可能会使你的代码更难以理解和维护。在大多数情况下,让Activiti自动选择最新版本的流程定义来启动流程实例是更好的做法。
  4. 总结
    • 在Activiti中启动流程时,通常不需要直接指定启动流程的版本。Activiti会根据你提供的流程定义key自动选择最新的活动版本来启动流程实例。如果你需要启动特定版本的流程实例,可以通过查询特定版本的流程定义ID来实现。

六、Activiti流程定义的key是什么?

在Activiti中,流程定义的key是一个用于唯一标识流程定义的字符串。当你使用BPMN文件部署一个流程到Activiti引擎时,该文件会定义一个或多个流程,并且每个流程都会有一个与之关联的key。这个key在Activiti的数据库表(如act_re_procdef)中作为字段KEY_(或类似名称)存储,并在Activiti API中用于引用和启动流程实例。

key的主要用途包括:

  1. 唯一标识key用于在Activiti引擎中唯一标识一个流程定义。它允许你在不同的部署中区分具有相同名称但可能内容不同的流程定义。

  2. 启动流程实例:你可以使用key来启动一个新的流程实例。例如,通过RuntimeService.startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables)方法,你可以传入流程定义的key和一组变量来启动一个新的流程实例。

  3. 查询流程定义:你可以使用key来查询流程定义的信息,如流程定义的版本、ID等。这对于了解当前部署的流程定义和版本管理非常有用。

  4. 版本控制:当同一个BPMN文件被多次部署到Activiti引擎时,引擎会基于key来识别不同的版本。每次部署都会创建一个新的流程定义版本,但key保持不变。这样,你可以通过key来引用不同的版本,或者查询某个key下所有可用的版本。

在BPMN文件中,key通常不是直接指定的,而是由Activiti在部署时自动生成的。然而,你可以通过BPMN文件的特定属性或元素(取决于你使用的BPMN编辑器和工具)来间接设置或影响key的值。在Activiti Modeler或Activiti Designer等图形化工具中,你可能会在创建流程时直接为流程定义设置一个名称和keykey与流程定义的ID(processDefinitionId)不同。ID是Activiti在部署时自动生成的唯一标识符,用于在内部引用和跟踪流程定义。而key则是更高级别的标识符,用于在API调用和查询中引用流程定义。

 七、activiti候选组怎么设置?

在Activiti中设置候选组(Candidate Groups)通常涉及在流程定义(BPMN文件)中配置任务节点,或者通过编程方式在流程启动或任务创建时动态设置。以下是设置候选组的几种方法:

1. 在BPMN文件中设置候选组

在BPMN文件中,可以通过配置任务节点来静态设置候选组。例如:

<userTask id="myTask" name="My Task">  
  <activiti:candidateGroups>group1,group2,group3</activiti:candidateGroups>  
</userTask>

在这个例子中,myTask 是一个用户任务,activiti:candidateGroups 标签定义了三个候选组:group1group2 和 group3。这些组中的用户都有资格申领这个任务。

2. 动态设置候选组

如果你需要在流程运行时动态设置候选组,可以通过编程方式实现。这通常涉及在流程启动或任务创建时,使用TaskService的API来设置任务变量或流程变量。

例如,你可以通过以下方式在流程启动时设置候选组:

Map<String, Object> variables = new HashMap<>();  
List<String> candidateGroups = new ArrayList<>();  
candidateGroups.add("group1");  
candidateGroups.add("group2");  
variables.put("candidateGroups", candidateGroups);  
//这里是process的id
runtimeService.startProcessInstanceByKey("myProcess", variables);

然后,在BPMN文件中,你可以使用UEL(Unified Expression Language)表达式来引用这个变量:

<userTask id="myTask" name="My Task">  
  <activiti:candidateGroups>${candidateGroups}</activiti:candidateGroups>  
</userTask>

我们在上面还看到了如下类似的候选组定义:

<userTask id="verifyReportTask" name="编写月度财务报告">
    <potentialOwner>
         <resourceAssignmentExpression>
            <formalExpression>${candidateGroups}</formalExpression>
         </resourceAssignmentExpression>
    </potentialOwner>
</userTask>

<!--
<potentialOwner>:这表示此任务有一个或多个潜在的拥有者(即候选用户或候选组)。
<resourceAssignmentExpression>:这是一个更通用的标签,用于定义资源分配的方式。它允许你使用不同的表达式类型(如formalExpression、user、candidateGroup等)来指定资源的分配。
<formalExpression>:这是一个表达式,其值通常是一个标识符,用于引用在Activiti流程引擎中配置的某个值。这个值可能是一个组ID、一个用户ID或者是一个动态表达式,该表达式在运行时会被解析为一个或多个用户或组的ID。
-->

 那么它们两个都是指定候选组,有什么区别呢?

  1. 标签和命名空间
    • 第一段定义使用了 <potentialOwner> 和 <resourceAssignmentExpression> 标签,并通过 <formalExpression> 来指定候选组。这种写法可能是在BPMN 2.0规范的一个更广泛的资源分配表达式的上下文中,并允许使用更复杂的表达式类型。
    • 第二段定义使用了 <activiti:candidateGroups> 标签,这是Activiti特定的扩展,直接指定了候选组。<activiti:> 命名空间前缀表明这个元素是Activiti引擎特定的,不是BPMN 2.0规范的一部分。
  2. 简洁性和直接性
    • 使用 <activiti:candidateGroups> 标签更加直接和简洁,它直接指定了候选组,无需额外的嵌套标签或表达式。
    • 使用 <potentialOwner> 和 <resourceAssignmentExpression> 的方式提供了更多的灵活性,因为它允许使用不同的表达式类型(虽然在这个例子中只是用到了简单的文本值)。
  3. 可读性和可维护性
    • 对于不熟悉Activiti特定扩展的开发人员来说,<potentialOwner> 和 <resourceAssignmentExpression> 的方式可能需要更多的上下文才能理解其含义。
    • <activiti:candidateGroups> 标签则更加直观,直接表明了其用途。
  4. 兼容性
    • <activiti:candidateGroups> 是Activiti特有的,因此它可能在与其他BPMN引擎(如Camunda BPM)的兼容性方面存在问题,除非这些引擎也支持相同的扩展。
    • <potentialOwner> 和 <resourceAssignmentExpression> 是BPMN 2.0规范的一部分(尽管 <formalExpression> 的具体使用方式可能因引擎而异),因此它们可能在不同的BPMN引擎之间具有更好的兼容性。
  5. 功能性
    • 在功能上,这两段定义都是将名为${candidateGroups}的用户组指定为用户任务的候选组。无论使用哪种方式,结果都是相同的。

其实这两段定义在功能上是等效的,但在语法、可读性和兼容性方面有所不同。选择哪种方式取决于你的具体需求、开发团队的偏好以及你使用的BPMN引擎的兼容性。在Activiti中,使用 <activiti:candidateGroups> 通常更为常见和直观。

3. 使用Java API在运行时设置候选组

如果你需要在流程执行过程中动态地为某个任务设置候选组,可以使用TaskServiceaddCandidateGroup方法

Task task = taskService.createTaskQuery().taskId("myTaskId").singleResult();  
taskService.addCandidateGroup(task.getId(), "group1");  
taskService.addCandidateGroup(task.getId(), "group2");

在这个例子中,我们首先通过任务ID查询到一个任务,然后使用addCandidateGroup方法为这个任务添加了两个候选组。

4. 注意事项

  • 候选组中的用户是候选人的潜在执行者,但并不代表这些用户就是任务的实际执行者。他们需要先通过“申领”操作将任务变为个人任务,然后才能执行。
  • 如果任务已经被申领为个人任务,那么它就不再对候选组中的其他用户可见。
  • 在使用UEL表达式时,需要确保引用的变量在流程执行时已经存在并且是可访问的。
  • 在设置候选组时,需要注意并发问题,特别是当多个用户或系统同时尝试申领同一个任务时。Activiti提供了锁机制来确保任务在某一时刻只能被一个用户申领。

八、如果 某个人(如fozzie)不在候选组中他能申领这个任务吗?

如果 fozzie 不在候选组中,通常情况下他是不能直接申领这个任务的。在Activiti工作流引擎中,候选组或候选用户的概念通常用于指定哪些用户或用户组有资格申领一个特定的任务。

但是,这并不意味着 fozzie 永远不能申领这个任务。有几种可能的情况或方式可以使非候选组的用户能够申领任务:

  1. 管理员干预:系统管理员或具有适当权限的用户可能能够手动分配任务给任何用户,包括那些不在候选组中的用户。

  2. 流程逻辑:BPMN流程定义可以包含逻辑来动态地修改候选用户或候选组。如果流程逻辑允许,那么可以在运行时将 fozzie 添加到候选用户或候选组中,然后他可以申领任务。

  3. 监听器或任务分配策略:可以使用Activiti的监听器(Listener)或自定义任务分配策略来修改任务的候选用户或候选组。这些可以在流程实例启动时或在特定任务节点触发时运行。

  4. 编程方式:通过编程方式,使用Activiti的API,可以修改任务的候选用户或候选组,然后允许 fozzie 申领任务。

  5. 直接分配:在某些情况下,如果任务已经被分配给一个用户(而不是处于候选状态),那么即使该用户不是候选用户,他也可能能够处理该任务。但是,这通常不是通过申领操作来完成的,而是通过直接的任务分配。

总之,如果 fozzie 不在候选组中,他通常不能直接申领任务。但是,通过管理员干预、流程逻辑、监听器、任务分配策略或编程方式,可以修改任务的候选用户或候选组,从而允许 fozzie 申领任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1793670.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java--方法的定义和调用

1.Java的方法类似于其他语言的函数&#xff0c;是一段用来用来完成特定功能的代码片段&#xff0c;一般情况下&#xff0c;定义一个方法包含以下语法&#xff1a; 1.方法包含一个方法头和方法体&#xff0c;。下面是一个方法的所有部分&#xff1a; 1.修饰符&#xff1a;修饰符…

重生奇迹mu战士技能石头在哪打

战士技能石头是靠打怪物&#xff0c;从它们身上掉下来而获得的&#xff0c;战士的技能石头分几种&#xff0c;每种都分布在不同的地方&#xff1a; 1、袭风刺技能石头可以到沙漠之地&#xff0c;通过打尖嘴猪获得。 2、雷霆裂闪技能石头可以到沙漠之地通过打黑暗大师或者破坏…

如何防止线上事故?从一次流水号重复引发的故障说起

最近我负责的系统出了一次生产事故&#xff0c;这次事故竟然是因为流水号重复导致的。今天来给大家分享一下。 1.问题背景 这个流水号的使用场景是上游系统调用下游接口时传入一个唯一 ID&#xff0c;流水号这个参数在联调或定位问题时很方便。 我们系统中的流水号是一个 32…

React权限管理系统实现

目录 一、需求 二、逻辑 三、实现 &#xff08;一&#xff09;代码 &#xff08;二&#xff09;解释 1. 获取权限对照数组 (queryReferencePermissionsInfo) 2. 获取处理对照数组 (queryDisposePermissionsInfo) 3. 获取权限映射表信息并处理 (queryPermissionsInfo) 4…

awdawdawd

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

2024-06-05-记一次cnvd渗透

前言&#xff1a;挖src挖郁闷了&#xff0c;闲来无事选择挖一个cnvd来练练手&#xff0c;本次的漏洞都没啥难度&#xff0c;企查查资产过了5000万 说一下cnvd证书的下放标准 对于中危及中危以上通用型漏洞&#xff08;CVSS2.0基准评分超过4.0分&#xff09;&#xff0c;以及涉…

eclipse添加maven插件

打开eclipse菜单 Help/Install New SoftwareWork with下拉菜单选择 2022-03 - https://download.eclipse.org/releases/2022-03‘type filter text’搜索框中输入 maven选择 M2E - Maven Integration for Eclipse一路next安装&#xff0c;重启eclipseImport项目时&#xff0c;就…

国外视频流量密码!我想要好好的,不要废掉我——早读(逆天打工人爬取热门微信文章解读)

耐心点好吗&#xff1f; 引言Python 代码第一篇 洞见 废掉一个人最隐蔽的方式&#xff1a;陷于底层习惯第二篇 视频信息差结尾 引言 戒骄戒躁 昨天晚上在沙发上睡着了 原因是身体不想睡 神想睡 于是身体躺在沙发上 神就睡着 早上早早就起来 差一点感冒 不过身体在冷水浴 还有呼…

Mac下载Homebrew

通过command空格搜索终端打开 直接输入 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 然后输入电脑密码 然后直接回车等待安装完成 注意⚠️&#xff1a;如果出现报错/opt/homebrew/bin is not in your PATH…

LW-DETR:实时目标检测的Transformer, Apache-2.0 开源可商用,实验超 YOLOv8

LW-DETR&#xff1a;实时目标检测的Transformer&#xff0c; Apache-2.0 开源可商用&#xff0c;实验超 YOLOv8 LW-DETR 架构实例化高效训练高效推理 目的与解法拆解ViT编码器和DETR解码器多级特征图聚合变形交叉注意力窗口注意力和全局注意力 论文&#xff1a;https://arxiv.o…

Vue3实战笔记(57)—一键换肤:在Vuetify中打造个性化主题切换体验

文章目录 前言一键换肤总结 前言 在当今追求极致用户体验的时代&#xff0c;为应用程序提供个性化的主题切换功能已经成为提升用户满意度和留存率的关键因素之一。Vuetify&#xff0c;作为基于Vue.js的流行前端框架&#xff0c;以其丰富的组件库和高度可定制性&#xff0c;为开…

数字影像产业园的三大赋能:科技、创新与无限可能

数字影像产业园作为文创产业的重要载体&#xff0c;以科技为核心驱动力&#xff0c;不断推动产业的技术革新和升级。 园区内汇聚了最前沿的数字技术资源&#xff0c;高清摄影设备、虚拟现实技术、人工智能应用等尖端科技在这里得到广泛应用&#xff0c;不仅提升了生产效率&…

池化层【马赛克】

最大池化&#xff0c;也叫下采样。 公式&#xff1a; 参数&#xff1a; celling的意思&#xff1a; 例子&#xff1a; 尺寸&#xff1a; code: import torchimport torchvision.datasetsfrom tensorboardX import SummaryWriterfrom torch import nnfrom torch.nn import MaxP…

自定义类型:枚举和联合体

在之前我们已经深入学习了自定义类型中的结构体类型 &#xff0c;了解了结构体当中的内存对齐&#xff0c;位段等知识&#xff0c;接下来在本篇中将继续学习剩下的两个自定义类型&#xff1a;枚举类型与联合体类型&#xff0c;一起加油&#xff01;&#xff01; 1.枚举类型 …

flink Jobmanager metaspace oom 分析

文章目录 现象作业背景分析现象分析类卸载条件MAT 分析 解决办法flink 官方提示 现象 通过flink 页面提交程序&#xff0c;多次提交后&#xff0c;jobmanager 报metaspace oom 作业背景 用户代码是flink 代码Spring nacos 分析 现象分析 从现象来看肯定是因为有的类没有被…

HDFS文件块损坏处理方案

1、问题概述 flume采集文本文件存储到hdfs中hive的ods层目录,并在hive中通过msck repair table刷新元数据,加载文本文件。报错如下: 2、问题分析 文件块BP-531411289-172.31.57.12-1539657748238出现了未知异常,导致namenode不能获取该文件块的信息,该文件块是由flume采…

Django项目部署(命令函部署)

Django项目搭建 一. 下载宝塔面板 我这里使用的是命令函部署 , 下载宝塔主要为了是方便操作 , 宝塔的终端支持复制粘贴 , 而且可以帮助我们快速的检索文件目录以及避免一些软件的环境配置 下载方法: ​ 打开浏览器访问 : 宝塔面板下载&#xff0c;免费全能的服务器运维软件…

关于stm32的软件复位

使用软件复位的目的&#xff1a; 软件复位并不会擦除存储器中的数据&#xff0c;它只是将处理器恢复到复位状态&#xff0c;即中断使能位被清除&#xff0c;系统寄存器被重置&#xff0c;但RAM和Flash存储器中的数据保持不变。 STM32软件复位(基于库文件V3.5) &#xff0c;对…

Junit(Java单元测试)

配置文件 要想使用 Junit 进行单元测试需要引入以下第三方库&#xff1a; 引入后可以使用 Test&#xff0c;BeforeEach等注解 <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --><dependency><groupId>org.junit.jupiter<…

JVM之垃圾回收面试总结

文章目录 1.GC概述1.1 什么是垃圾1.2 为什么需要GC&#xff1f;1.3 早期垃圾回收1.4 Java垃圾回收机制1.5 评估GC的性能指标 2.垃圾回收相关算法2.1 垃圾标记阶段的算法2.1.1 引用计数算法(Java没有使用)2.1.2 可达性分析算法 2.2 垃圾清除阶段的算法2.2.1 标记-清除(Mark-Swee…