• org.activiti.engine


    Survive by day and develop by night.
    talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive.
    happy for hardess to solve denpendies.

    目录

    在这里插入图片描述

    概述

    org.activiti.engine是一个非常常见的需求。

    需求:

    设计思路

    实现思路分析

    1.TaskService

    public interface TaskService {
    
      /**
       * Creates a new task that is not related to any process instance.
       *
       * The returned task is transient and must be saved with {@link #saveTask(Task)} 'manually'.
       */
      Task newTask();
    
      /** create a new task with a user defined task id */
      Task newTask(String taskId);
    
      /**
       * Saves the given task to the persistent data store. If the task is already present in the persistent store, it is updated. After a new task has been saved, the task instance passed into this
       * method is updated with the id of the newly created task.
       *
       * @param task
       *          the task, cannot be null.
       */
      Task saveTask(Task task);
    
      /**
       * Deletes the given task, not deleting historic information that is related to this task.
       *
       * @param taskId
       *          The id of the task that will be deleted, cannot be null. If no task exists with the given taskId, the operation is ignored.
       * @throws ActivitiObjectNotFoundException
       *           when the task with given id does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the task or in case the task is part of a running process.
       */
      void deleteTask(String taskId);
    
      /**
       * Deletes all tasks of the given collection, not deleting historic information that is related to these tasks.
       *
       * @param taskIds
       *          The id's of the tasks that will be deleted, cannot be null. All id's in the list that don't have an existing task will be ignored.
       * @throws ActivitiObjectNotFoundException
       *           when one of the task does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the tasks or in case one of the tasks is part of a running process.
       */
      void deleteTasks(Collection<String> taskIds);
    
      /**
       * Deletes the given task.
       *
       * @param taskId
       *          The id of the task that will be deleted, cannot be null. If no task exists with the given taskId, the operation is ignored.
       * @param cascade
       *          If cascade is true, also the historic information related to this task is deleted.
       * @throws ActivitiObjectNotFoundException
       *           when the task with given id does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the task or in case the task is part of a running process.
       */
      void deleteTask(String taskId, boolean cascade);
    
      /**
       * Deletes all tasks of the given collection.
       *
       * @param taskIds
       *          The id's of the tasks that will be deleted, cannot be null. All id's in the list that don't have an existing task will be ignored.
       * @param cascade
       *          If cascade is true, also the historic information related to this task is deleted.
       * @throws ActivitiObjectNotFoundException
       *           when one of the tasks does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the tasks or in case one of the tasks is part of a running process.
       */
      void deleteTasks(Collection<String> taskIds, boolean cascade);
    
      /**
       * Deletes the given task, not deleting historic information that is related to this task..
       *
       * @param taskId
       *          The id of the task that will be deleted, cannot be null. If no task exists with the given taskId, the operation is ignored.
       * @param deleteReason
       *          reason the task is deleted. Is recorded in history, if enabled.
       * @throws ActivitiObjectNotFoundException
       *           when the task with given id does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the task or in case the task is part of a running process
       */
      void deleteTask(String taskId, String deleteReason);
    
      /**
       * Deletes the given task, not deleting historic information that is related to this task..
       *
       * @param taskId
       *          The id of the task that will be deleted, cannot be null. If no task exists with the given taskId, the operation is ignored.
       * @param deleteReason
       *          reason the task is deleted. Is recorded in history, if enabled.
       * @param cancel
       *          mark the task as cancelled
       * @throws ActivitiObjectNotFoundException
       *           when the task with given id does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the task or in case the task is part of a running process
       */
      void deleteTask(String taskId, String deleteReason, boolean cancel);
    
      /**
       * Deletes all tasks of the given collection, not deleting historic information that is related to these tasks.
       *
       * @param taskIds
       *          The id's of the tasks that will be deleted, cannot be null. All id's in the list that don't have an existing task will be ignored.
       * @param deleteReason
       *          reason the task is deleted. Is recorded in history, if enabled.
       * @throws ActivitiObjectNotFoundException
       *           when one of the tasks does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the tasks or in case one of the tasks is part of a running process.
       */
      void deleteTasks(Collection<String> taskIds, String deleteReason);
    
      /**
       * Deletes all tasks of the given collection, not deleting historic information that is related to these tasks.
       *
       * @param taskIds
       *          The id's of the tasks that will be deleted, cannot be null. All id's in the list that don't have an existing task will be ignored.
       * @param deleteReason
       *          reason the task is deleted. Is recorded in history, if enabled.
       * @oaramn cancel
       *           mark the task as cancelled
       * @throws ActivitiObjectNotFoundException
       *           when one of the tasks does not exist.
       * @throws ActivitiException
       *           when an error occurs while deleting the tasks or in case one of the tasks is part of a running process.
       */
      void deleteTasks(Collection<String> taskIds, String deleteReason, boolean cancel);
    
      /**
       * Claim responsibility for a task: the given user is made assignee for the task. The difference with {@link #setAssignee(String, String)} is that here a check is done if the task already has a user
       * assigned to it. No check is done whether the user is known by the identity component.
       *
       * @param taskId
       *          task to claim, cannot be null.
       * @param userId
       *          user that claims the task. When userId is null the task is unclaimed, assigned to no one.
       * @throws ActivitiObjectNotFoundException
       *           when the task doesn't exist.
       * @throws ActivitiTaskAlreadyClaimedException
       *           when the task is already claimed by another user.
       */
      void claim(String taskId, String userId);
    
      /**
       * A shortcut to {@link #claim} with null user in order to unclaim the task
       *
       * @param taskId
       *          task to unclaim, cannot be null.
       * @throws ActivitiObjectNotFoundException
       *           when the task doesn't exist.
       */
      void unclaim(String taskId);
    
      /**
       * Called when the task is successfully executed.
       *
       * @param taskId
       *          the id of the task to complete, cannot be null.
       * @throws ActivitiObjectNotFoundException
       *           when no task exists with the given id.
       * @throws ActivitiException
       *           when this task is {@link DelegationState#PENDING} delegation.
       */
      void complete(String taskId);
    
      /**
       * Delegates the task to another user. This means that the assignee is set and the delegation state is set to {@link DelegationState#PENDING}. If no owner is set on the task, the owner is set to the
       * current assignee of the task.
       *
       * @param taskId
       *          The id of the task that will be delegated.
       * @param userId
       *          The id of the user that will be set as assignee.
       * @throws ActivitiObjectNotF
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179

    2.RuntimeService

    public interface RuntimeService {
    
      /**
       * Create a {@link ProcessInstanceBuilder}, that allows to set various options for starting a process instance,
       * as an alternative to the various startProcessInstanceByXX methods.
       */
      ProcessInstanceBuilder createProcessInstanceBuilder();
    
      /**
       * Starts a process instance previously created.
       *
       * @param createdProcessInstance
       *          The already created process instance.
       * @throws ActivitiObjectNotFoundException
       *          when user does not have permission to start the process instance
       * @throws NotFoundException
       *          when no process instance with the given id is found
       */
      ProcessInstance startCreatedProcessInstance(ProcessInstance createdProcessInstance, Map<String, Object> variables);
    
      /**
       * Starts a new process instance in the latest version of the process definition with the given key.
       *
       * @param processDefinitionKey
       *          key of process definition, cannot be null.
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceByKey(String processDefinitionKey);
    
      /**
       * Starts a new process instance in the latest version of the process definition with the given key.
       *
       * A business key can be provided to associate the process instance with a certain identifier that has a clear business meaning. For example in an order process, the business key could be an order
       * id. This business key can then be used to easily look up that process instance , see {@link ProcessInstanceQuery#processInstanceBusinessKey(String)}. Providing such a business key is definitely a
       * best practice.
       *
       * @param processDefinitionKey
       *          key of process definition, cannot be null.
       * @param businessKey
       *          a key that uniquely identifies the process instance in the context or the given process definition.
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey);
    
      /**
       * Starts a new process instance in the latest version of the process definition with the given key
       *
       * @param processDefinitionKey
       *          key of process definition, cannot be null.
       * @param variables
       *          the variables to pass, can be null.
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
    
      /**
       * Starts a new process instance in the latest version of the process definition with the given key.
       *
       * A business key can be provided to associate the process instance with a certain identifier that has a clear business meaning. For example in an order process, the business key could be an order
       * id. This business key can then be used to easily look up that process instance , see {@link ProcessInstanceQuery#processInstanceBusinessKey(String)}. Providing such a business key is definitely a
       * best practice.
       *
       * The combination of processdefinitionKey-businessKey must be unique.
       *
       * @param processDefinitionKey
       *          key of process definition, cannot be null.
       * @param variables
       *          the variables to pass, can be null.
       * @param businessKey
       *          a key that uniquely identifies the process instance in the context or the given process definition.
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables);
    
      /**
       * Similar to {@link #startProcessInstanceByKey(String)}, but using a specific tenant identifier.
       */
      ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId);
    
      /**
       * Similar to {@link #startProcessInstanceByKey(String, String)}, but using a specific tenant identifier.
       */
      ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, String tenantId);
    
      /**
       * Similar to {@link #startProcessInstanceByKey(String, Map)}, but using a specific tenant identifier.
       */
      ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, Map<String, Object> variables, String tenantId);
    
      /**
       * Similar to {@link #startProcessInstanceByKey(String, String, Map)}, but using a specific tenant identifier.
       */
      ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, Map<String, Object> variables, String tenantId);
    
      /**
       * Starts a new process instance in the exactly specified version of the process definition with the given id.
       *
       * @param processDefinitionId
       *          the id of the process definition, cannot be null.
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceById(String processDefinitionId);
    
      /**
       * Starts a new process instance in the exactly specified version of the process definition with the given id.
       *
       * A business key can be provided to associate the process instance with a certain identifier that has a clear business meaning. For example in an order process, the business key could be an order
       * id. This business key can then be used to easily look up that process instance , see {@link ProcessInstanceQuery#processInstanceBusinessKey(String)}. Providing such a business key is definitely a
       * best practice.
       *
       * @param processDefinitionId
       *          the id of the process definition, cannot be null.
       * @param businessKey
       *          a key that uniquely identifies the process instance in the context or the given process definition.
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceById(String processDefinitionId, String businessKey);
    
      /**
       * Starts a new process instance in the exactly specified version of the process definition with the given id.
       *
       * @param processDefinitionId
       *          the id of the process definition, cannot be null.
       * @param variables
       *          variables to be passed, can be null
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceById(String processDefinitionId, Map<String, Object> variables);
    
      /**
       * Starts a new process instance in the exactly specified version of the process definition with the given id.
       *
       * A business key can be provided to associate the process instance with a certain identifier that has a clear business meaning. For example in an order process, the business key could be an order
       * id. This business key can then be used to easily look up that process instance , see {@link ProcessInstanceQuery#processInstanceBusinessKey(String)}. Providing such a business key is definitely a
       * best practice.
       *
       * @param processDefinitionId
       *          the id of the process definition, cannot be null.
       * @param variables
       *          variables to be passed, can be null
       * @throws ActivitiObjectNotFoundException
       *           when no process definition is deployed with the given key.
       */
      ProcessInstance startProcessInstanceById(String processDefinitionId, String businessKey, Map<String, Object> variables);
    
      /**
       * 

    * Signals the process engine that a message is received and starts a new {@link ProcessInstance}. *

    * *

    * Calling this method can have two different outcomes: *

      *
    • If the message name is associated with a message start event, a new process instance is started.
    • *
    • If no subscription to a message with the given name exists, {@link ActivitiException} is thrown
    • *
    *

    * * @param messageName * the 'name' of the message as specified as an attribute on the bpmn20 {@code } element. * * @return the {@link ProcessInstance} object representing the started process instance * * @throws ActivitiException * if no subscription to a message with the given name exists * * @since 5.9 */
    ProcessInstance startProcessInstanceByMessage(String messageName); /** * Similar to {@link RuntimeService#startProcessInstanceByMessage(String)}, but with tenant context. */ ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, String tenantId); /** *

    * Signals the process engine that a message is received and starts a new {@link ProcessInstance}. *

    * * See {@link #startProcessInstanceByMessage(String, Map)}. This method allows specifying a business key. * * @param messageName * the 'name' of the message as specified as an attribute on the bpmn20 {@code } element. * @param businessKey * the business key which is added to the started process instance * * @throws ActivitiException * if no subscription to a message with the given name exists * * @since 5.10 */
    ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey); /** * Similar to {@link RuntimeService#startProcessInstanceByMessage(String, String)}, but with tenant context. */ ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, String businessKey, String tenantId); /** *

    * Signals the process engine that a message is received and starts a new {@link ProcessInstance}. *

    * * See {@link #startProcessInstanceByMessage(String)}. In addition, this method allows specifying a the payload of the message as a map of process variables. * * @param messageName * the 'name' of the message as specified as an attribute on the bpmn20 {@code } element. * @param processVariables * the 'payload' of the message. The variables are added as processes variables to the started process instance. * @return the {@link ProcessInstance} object representing the started process instance * * @throws ActivitiException * if no subscription to a message with the given name exists * * @since 5.9 */
    ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables); /** * Similar to {@link RuntimeService#startProcessInstanceByMessage(String, Map)}, but with tenant context. */ ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, Map<String, Object> processVariables, String tenantId); /** *

    * Signals the process engine that a message is received and starts a new {@link ProcessInstance}. *

    * * See {@link #startProcessInstanceByMessage(String, Map)}. In addition, this method allows specifying a business key. * * @param messageName * the 'name' of the message as specified as an attribute on the bpmn20 {@code } element. * @param businessKey * the business key which is added to the started process instance * @param processVariables * the 'payload' of the message. The variables are added as processes variables to the started process instance. * @return the {@link ProcessInstance} object representing the started process instance * * @throws ActivitiException * if no subscription to a message with the given name exists * * @since 5.9 */
    ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables); /** * Similar to {@link RuntimeService#startProcessInstanceByMessage(String, String, Map)}, but with tenant context. */ ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, String businessKey, Map<String, Object> processVariables, String tenantId); /** * Delete an existing runtime process instance. * * @param processInstanceId * id of process instance to delete, cannot be null. * @param deleteReason * reason for deleting, can be null. * @throws ActivitiObjectNotFoundException * when no process instance is found with the given id. */ void deleteProcessInstance(String processInstanceId, String deleteReason); /** * Finds the activity ids for all executions that are waiting in activities. This is a list because a single activity can be active multiple times. * * @param executionId * id of the execution, cannot be null. * @throws ActivitiObjectNotFoundException * when no execution exists with the given executionId. */ List<String> getActiveActivityIds(String executionId); /** * Sends an external trigger to an activity instance that is waiting inside the given execution. * * @param executionId * id of execution to signal, cannot be null. * @throws ActivitiObjectNotFoundException * when no execution is found for the given executionId. */ void trigger(String executionId); /** * Sends an external trigger to an activity instance that is waiting inside the given execution. * * @param executionId * id of execution to signal, cannot be null. * @param processVariables * a map of process variables * @throws ActivitiObjectNotFoundException * when no execution is found for the given executionId. */ void trigger(String executionId, Map<String, Object> processVariables); /** * Similar to {@link #trigger(String, Map)}, but with an extra parameter that allows to pass * transient variables. */ void trigger(String executionId, Map<String, Object> processVariables, Map<String, Object> transientVariables); /** * Updates the business key for the provided process instance * * @param processInstanceId * id of the process instance to set the business key, cannot be null * @param businessKey * new businessKey value */ void updateBusinessKey(String processInstanceId, String businessKey); // Identity Links // /// /** * Involves a user with a process instance. The type of identity link is defined by the given identityLinkType. * * @param processInstanceId * id of the process instance, cannot be null. * @param userId * id of the user involve, cannot be null. * @param identityLinkType * type of identityLink, cannot be null (@see {@link IdentityLinkType}). * @throws ActivitiObjectNotFoundException * when the process instance doesn't exist. */ void addUserIdentityLink(String processInstanceId, String userId, String identityLinkType); /** * Involves a group with a process instance. The type of identityLink is defined by the given identityLink. * * @param processInstanceId * id of the process instance, cannot be null. * @param groupId * id of the group to involve, cannot be null. * @param identityLinkType * type of identity, cannot be null (@see {@link IdentityLinkType}). * @throws ActivitiObjectNotFoundException * when the process instance or group doesn't exist. */ void addGroupIdentityLink(String processInstanceId, String groupId, String identityLinkType); /** * Convenience shorthand for {@link #addUserIdentityLink(String, String, String)}; with type {@link IdentityLinkType#CANDIDATE} * * @param processInstanceId * id of the process instance, cannot be null. * @param userId * id of the user to use as candidate, cannot be null. * @throws ActivitiObjectNotFoundException * when the task or user doesn't exist. */ void addParticipantUser(String processInstanceId, String userId); /** * Convenience shorthand for {@link #addGroupIdentityLink(String, String, String)}; with type {@link IdentityLinkType#CANDIDATE} * * @param processInstanceId * id of the process instance, cannot be null. * @param groupId * id of the group to use as candidate, cannot be null. * @throws ActivitiObjectNotFoundException * when the task or group doesn't exist. */ void addParticipantGroup(String processInstanceId, String groupId); /** * Convenience shorthand for {@link #deleteUserIdentityLink(String, String, String)}; with type {@link IdentityLinkType#CANDIDATE} * * @param processInstanceId * id of the process instance, cannot be null. * @param userId * id of the user to use as candidate, cannot be null. * @throws ActivitiObjectNotFoundException * when the task or user doesn't exist. */ void deleteParticipantUser(String processInstanceId, String userId); /** * Convenience shorthand for {@link #deleteGroupIdentityLink(String, String, String)}; with type {@link IdentityLinkType#CANDIDATE} * * @param processInstanceId * id of the process instance, cannot be null. * @param groupId * id of the group to use as candidate, cannot be null. * @throws ActivitiObjectNotFoundException * when the task or group doesn't exist. */ void deleteParticipantGroup(String processInstanceId, String groupId); /** * Removes the association between a user and a process instance for the given identityLinkType. * * @param processInstanceId * id of the process instance, cannot be null. * @param userId * id of the user involve, cannot be null. * @param identityLinkType * type of identityLink, cannot be null (@see {@link IdentityLinkType}). * @throws ActivitiObjectNotFoundException * when the task or user doesn't exist. */ void deleteUserIdentityLink(String processInstanceId, String userId, String identityLinkType); /** * Removes the association between a group and a process instance for the given identityLinkType. * * @param processInstanceId * id of the process instance, cannot be null. * @param groupId * id of the group to involve, cannot be null. * @param identityLinkType * type of identity, cannot be null (@see {@link IdentityLinkType}). * @throws ActivitiObjectNotFoundException * when the task or group doesn't exist. */ void deleteGroupIdentityLink(String processInstanceId, String groupId, String identityLinkType); /** * Retrieves the {@link IdentityLink}s associated with the given process instance. Such an {@link IdentityLink} informs how a certain user is involved with a process instance. */ List<IdentityLink> getIdentityLinksForProcessInstance(String instanceId); // Variables //
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434

    在这里插入图片描述

    3.ProcessEngines

    在这里插入图片描述

    public abstract class ProcessEngines {
    
      private static Logger log = LoggerFactory.getLogger(ProcessEngines.class);
    
      public static final String NAME_DEFAULT = "default";
    
      protected static boolean isInitialized;
      protected static Map<String, ProcessEngine> processEngines = new HashMap<String, ProcessEngine>();
      protected static Map<String, ProcessEngineInfo> processEngineInfosByName = new HashMap<String, ProcessEngineInfo>();
      protected static Map<String, ProcessEngineInfo> processEngineInfosByResourceUrl = new HashMap<String, ProcessEngineInfo>();
      protected static List<ProcessEngineInfo> processEngineInfos = new ArrayList<ProcessEngineInfo>();
    
      /**
       * Initializes all process engines that can be found on the classpath for resources activiti.cfg.xml (plain Activiti style configuration) and for resources
       * activiti-context.xml (Spring style configuration).
       */
      public synchronized static void init() {
        if (!isInitialized()) {
          if (processEngines == null) {
            // Create new map to store process-engines if current map is
            // null
            processEngines = new HashMap<String, ProcessEngine>();
          }
          ClassLoader classLoader = ReflectUtil.getClassLoader();
          Enumeration<URL> resources = null;
          try {
            resources = classLoader.getResources("activiti.cfg.xml");
          } catch (IOException e) {
            throw new ActivitiIllegalArgumentException("problem retrieving activiti.cfg.xml resources on the classpath: " + System.getProperty("java.class.path"), e);
          }
    
          // Remove duplicated configuration URL's using set. Some
          // classloaders may return identical URL's twice, causing duplicate
          // startups
          Set<URL> configUrls = new HashSet<URL>();
          while (resources.hasMoreElements()) {
            configUrls.add(resources.nextElement());
          }
          for (Iterator<URL> iterator = configUrls.iterator(); iterator.hasNext();) {
            URL resource = iterator.next();
            log.info("Initializing process engine using configuration '{}'", resource.toString());
            initProcessEngineFromResource(resource);
          }
    
          try {
            resources = classLoader.getResources("activiti-context.xml");
          } catch (IOException e) {
            throw new ActivitiIllegalArgumentException("problem retrieving activiti-context.xml resources on the classpath: " + System.getProperty("java.class.path"), e);
          }
          while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            log.info("Initializing process engine using Spring configuration '{}'", resource.toString());
            initProcessEngineFromSpringResource(resource);
          }
    
          setInitialized(true);
        } else {
          log.info("Process engines already initialized");
        }
      }
    
      protected static void initProcessEngineFromSpringResource(URL resource) {
        try {
          Class<?> springConfigurationHelperClass = ReflectUtil.loadClass("org.activiti.spring.SpringConfigurationHelper");
          Method method = springConfigurationHelperClass.getDeclaredMethod("buildProcessEngine", new Class<?>[] { URL.class });
          ProcessEngine processEngine = (ProcessEngine) method.invoke(null, new Object[] { resource });
    
          String processEngineName = processEngine.getName();
          ProcessEngineInfo processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resource.toString(), null);
          processEngineInfosByName.put(processEngineName, processEngineInfo);
          processEngineInfosByResourceUrl.put(resource.toString(), processEngineInfo);
    
        } catch (Exception e) {
          throw new ActivitiException("couldn't initialize process engine from spring configuration resource " + resource.toString() + ": " + e.getMessage(), e);
        }
      }
    
      /**
       * Registers the given process engine. No {@link ProcessEngineInfo} will be available for this process engine. An engine that is registered will be closed when the {@link ProcessEngines#destroy()}
       * is called.
       */
      public static void registerProcessEngine(ProcessEngine processEngine) {
        processEngines.put(processEngine.getName(), processEngine);
      }
    
      /**
       * Unregisters the given process engine.
       */
      public static void unregister(ProcessEngine processEngine) {
        processEngines.remove(processEngine.getName());
      }
    
      private static ProcessEngineInfo initProcessEngineFromResource(URL resourceUrl) {
        ProcessEngineInfo processEngineInfo = processEngineInfosByResourceUrl.get(resourceUrl.toString());
        // if there is an existing process engine info
        if (processEngineInfo != null) {
          // remove that process engine from the member fields
          processEngineInfos.remove(processEngineInfo);
          if (processEngineInfo.getException() == null) {
            String processEngineName = processEngineInfo.getName();
            processEngines.remove(processEngineName);
            processEngineInfosByName.remove(processEngineName);
          }
          processEngineInfosByResourceUrl.remove(processEngineInfo.getResourceUrl());
        }
    
        String resourceUrlString = resourceUrl.toString();
        try {
          log.info("initializing process engine for resource {}", resourceUrl);
          ProcessEngine processEngine = buildProcessEngine(resourceUrl);
          String processEngineName = processEngine.getName();
          log.info("initialised process engine {}", processEngineName);
          processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resourceUrlString, null);
          processEngines.put(processEngineName, processEngine);
          processEngineInfosByName.put(processEngineName, processEngineInfo);
        } catch (Throwable e) {
          log.error("Exception while initializing process engine: {}", e.getMessage(), e);
          processEngineInfo = new ProcessEngineInfoImpl(null, resourceUrlString, getExceptionString(e));
        }
        processEngineInfosByResourceUrl.put(resourceUrlString, processEngineInfo);
        processEngineInfos.add(processEngineInfo);
        return processEngineInfo;
      }
    
      private static String getExceptionString(Throwable e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
      }
    
      private static ProcessEngine buildProcessEngine(URL resource) {
        InputStream inputStream = null;
        try {
          inputStream = resource.openStream();
          ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream);
          return processEngineConfiguration.buildProcessEngine();
    
        } catch (IOException e) {
          throw new ActivitiIllegalArgumentException("couldn't open resource stream: " + e.getMessage(), e);
        } finally {
          IoUtil.closeSilently(inputStream);
        }
      }
    
      /** Get initialization results. */
      public static List<ProcessEngineInfo> getProcessEngineInfos() {
        return processEngineInfos;
      }
    
      /**
       * Get initialization results. Only info will we available for process engines which were added in the {@link ProcessEngines#init()}. No {@link ProcessEngineInfo} is available for engines which were
       * registered programatically.
       */
      public static ProcessEngineInfo getProcessEngineInfo(String processEngineName) {
        return processEngineInfosByName.get(processEngineName);
      }
    
      public static ProcessEngine getDefaultProcessEngine() {
        return getProcessEngine(NAME_DEFAULT);
      }
    
      /**
       * obtain a process engine by name.
       *
       * @param processEngineName
       *          is the name of the process engine or null for the default process engine.
       */
      public static ProcessEngine getProcessEngine(String processEngineName) {
        if (!isInitialized()) {
          init();
        }
        return processEngines.get(processEngineName);
      }
    
      /**
       * retries to initialize a process engine that previously failed.
       */
      public static ProcessEngineInfo retry(String resourceUrl) {
        log.debug("retying initializing of resource {}", resourceUrl);
        try {
          return initProcessEngineFromResource(new URL(resourceUrl));
        } catch (MalformedURLException e) {
          throw new ActivitiIllegalArgumentException("invalid url: " + resourceUrl, e);
        }
      }
    
      /**
       * provides access to process engine to application clients in a managed server environment.
       */
      public static Map<String, ProcessEngine> getProcessEngines() {
        return processEngines;
      }
    
      /**
       * closes all process engines. This method should be called when the server shuts down.
       */
      public synchronized static void destroy() {
        if (isInitialized()) {
          Map<String, ProcessEngine> engines = new HashMap<String, ProcessEngine>(processEngines);
          processEngines = new HashMap<String, ProcessEngine>();
    
          for (String processEngineName : engines.keySet()) {
            ProcessEngine processEngine = engines.get(processEngineName);
            try {
              processEngine.close();
            } catch (Exception e) {
              log.error("exception while closing {}", (processEngineName == null ? "the default process engine" : "process engine " + processEngineName), e);
            }
          }
    
          processEngineInfosByName.clear();
          processEngineInfosByResourceUrl.clear();
          processEngineInfos.clear();
    
          setInitialized(false);
        }
      }
    
      public static boolean isInitialized() {
        return isInitialized;
      }
    
      public static void setInitialized(boolean isInitialized) {
        ProcessEngines.isInitialized = isInitialized;
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228

    4.ProcessEngineLifecycleListener

    public interface ProcessEngineLifecycleListener {
    
      /**
       * Called right after the process-engine has been built.
       *
       * @param processEngine
       *          engine that was built
       */
      void onProcessEngineBuilt(ProcessEngine processEngine);
    
      /**
       * Called right after the process-engine has been closed.
       *
       * @param processEngine
       *          engine that was closed
       */
      void onProcessEngineClosed(ProcessEngine processEngine);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    5.ProcessEngines

    public abstract class ProcessEngines {
    
      private static Logger log = LoggerFactory.getLogger(ProcessEngines.class);
    
      public static final String NAME_DEFAULT = "default";
    
      protected static boolean isInitialized;
      protected static Map<String, ProcessEngine> processEngines = new HashMap<String, ProcessEngine>();
      protected static Map<String, ProcessEngineInfo> processEngineInfosByName = new HashMap<String, ProcessEngineInfo>();
      protected static Map<String, ProcessEngineInfo> processEngineInfosByResourceUrl = new HashMap<String, ProcessEngineInfo>();
      protected static List<ProcessEngineInfo> processEngineInfos = new ArrayList<ProcessEngineInfo>();
    
      /**
       * Initializes all process engines that can be found on the classpath for resources activiti.cfg.xml (plain Activiti style configuration) and for resources
       * activiti-context.xml (Spring style configuration).
       */
      public synchronized static void init() {
        if (!isInitialized()) {
          if (processEngines == null) {
            // Create new map to store process-engines if current map is
            // null
            processEngines = new HashMap<String, ProcessEngine>();
          }
          ClassLoader classLoader = ReflectUtil.getClassLoader();
          Enumeration<URL> resources = null;
          try {
            resources = classLoader.getResources("activiti.cfg.xml");
          } catch (IOException e) {
            throw new ActivitiIllegalArgumentException("problem retrieving activiti.cfg.xml resources on the classpath: " + System.getProperty("java.class.path"), e);
          }
    
          // Remove duplicated configuration URL's using set. Some
          // classloaders may return identical URL's twice, causing duplicate
          // startups
          Set<URL> configUrls = new HashSet<URL>();
          while (resources.hasMoreElements()) {
            configUrls.add(resources.nextElement());
          }
          for (Iterator<URL> iterator = configUrls.iterator(); iterator.hasNext();) {
            URL resource = iterator.next();
            log.info("Initializing process engine using configuration '{}'", resource.toString());
            initProcessEngineFromResource(resource);
          }
    
          try {
            resources = classLoader.getResources("activiti-context.xml");
          } catch (IOException e) {
            throw new ActivitiIllegalArgumentException("problem retrieving activiti-context.xml resources on the classpath: " + System.getProperty("java.class.path"), e);
          }
          while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            log.info("Initializing process engine using Spring configuration '{}'", resource.toString());
            initProcessEngineFromSpringResource(resource);
          }
    
          setInitialized(true);
        } else {
          log.info("Process engines already initialized");
        }
      }
    
      protected static void initProcessEngineFromSpringResource(URL resource) {
        try {
          Class<?> springConfigurationHelperClass = ReflectUtil.loadClass("org.activiti.spring.SpringConfigurationHelper");
          Method method = springConfigurationHelperClass.getDeclaredMethod("buildProcessEngine", new Class<?>[] { URL.class });
          ProcessEngine processEngine = (ProcessEngine) method.invoke(null, new Object[] { resource });
    
          String processEngineName = processEngine.getName();
          ProcessEngineInfo processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resource.toString(), null);
          processEngineInfosByName.put(processEngineName, processEngineInfo);
          processEngineInfosByResourceUrl.put(resource.toString(), processEngineInfo);
    
        } catch (Exception e) {
          throw new ActivitiException("couldn't initialize process engine from spring configuration resource " + resource.toString() + ": " + e.getMessage(), e);
        }
      }
    
      /**
       * Registers the given process engine. No {@link ProcessEngineInfo} will be available for this process engine. An engine that is registered will be closed when the {@link ProcessEngines#destroy()}
       * is called.
       */
      public static void registerProcessEngine(ProcessEngine processEngine) {
        processEngines.put(processEngine.getName(), processEngine);
      }
    
      /**
       * Unregisters the given process engine.
       */
      public static void unregister(ProcessEngine processEngine) {
        processEngines.remove(processEngine.getName());
      }
    
      private static ProcessEngineInfo initProcessEngineFromResource(URL resourceUrl) {
        ProcessEngineInfo processEngineInfo = processEngineInfosByResourceUrl.get(resourceUrl.toString());
        // if there is an existing process engine info
        if (processEngineInfo != null) {
          // remove that process engine from the member fields
          processEngineInfos.remove(processEngineInfo);
          if (processEngineInfo.getException() == null) {
            String processEngineName = processEngineInfo.getName();
            processEngines.remove(processEngineName);
            processEngineInfosByName.remove(processEngineName);
          }
          processEngineInfosByResourceUrl.remove(processEngineInfo.getResourceUrl());
        }
    
        String resourceUrlString = resourceUrl.toString();
        try {
          log.info("initializing process engine for resource {}", resourceUrl);
          ProcessEngine processEngine = buildProcessEngine(resourceUrl);
          String processEngineName = processEngine.getName();
          log.info("initialised process engine {}", processEngineName);
          processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resourceUrlString, null);
          processEngines.put(processEngineName, processEngine);
          processEngineInfosByName.put(processEngineName, processEngineInfo);
        } catch (Throwable e) {
          log.error("Exception while initializing process engine: {}", e.getMessage(), e);
          processEngineInfo = new ProcessEngineInfoImpl(null, resourceUrlString, getExceptionString(e));
        }
        processEngineInfosByResourceUrl.put(resourceUrlString, processEngineInfo);
        processEngineInfos.add(processEngineInfo);
        return processEngineInfo;
      }
    
      private static String getExceptionString(Throwable e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
      }
    
      private static ProcessEngine buildProcessEngine(URL resource) {
        InputStream inputStream = null;
        try {
          inputStream = resource.openStream();
          ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream);
          return processEngineConfiguration.buildProcessEngine();
    
        } catch (IOException e) {
          throw new ActivitiIllegalArgumentException("couldn't open resource stream: " + e.getMessage(), e);
        } finally {
          IoUtil.closeSilently(inputStream);
        }
      }
    
      /** Get initialization results. */
      public static List<ProcessEngineInfo> getProcessEngineInfos() {
        return processEngineInfos;
      }
    
      /**
       * Get initialization results. Only info will we available for process engines which were added in the {@link ProcessEngines#init()}. No {@link ProcessEngineInfo} is available for engines which were
       * registered programatically.
       */
      public static ProcessEngineInfo getProcessEngineInfo(String processEngineName) {
        return processEngineInfosByName.get(processEngineName);
      }
    
      public static ProcessEngine getDefaultProcessEngine() {
        return getProcessEngine(NAME_DEFAULT);
      }
    
      /**
       * obtain a process engine by name.
       *
       * @param processEngineName
       *          is the name of the process engine or null for the default process engine.
       */
      public static ProcessEngine getProcessEngine(String processEngineName) {
        if (!isInitialized()) {
          init();
        }
        return processEngines.get(processEngineName);
      }
    
      /**
       * retries to initialize a process engine that previously failed.
       */
      public static ProcessEngineInfo retry(String resourceUrl) {
        log.debug("retying initializing of resource {}", resourceUrl);
        try {
          return initProcessEngineFromResource(new URL(resourceUrl));
        } catch (MalformedURLException e) {
          throw new ActivitiIllegalArgumentException("invalid url: " + resourceUrl, e);
        }
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187

    在这里插入图片描述

    参考资料和推荐阅读

    [1].www.activite.org

    欢迎阅读,各位老铁,如果对你有帮助,点个赞加个关注呗!~

  • 相关阅读:
    【华为OD机试python】报文回路【2023 B卷|100分】
    Redis的分布式锁问题(十)最强分布式锁工具:Redisson
    【代码案例】网页版表白墙 & 待办事项 (包含完整源码)
    Redis系列17:聊聊布隆过滤器(实践篇)
    typora+python打造舒适的文档写作环境
    拓世大模型 | 立足行业所需,发力终端,缔造智能无限可能
    maven配置jib-maven-plugin插件构建java应用docker镜像
    C++学习第五课--函数新特性、内联函数、const详解笔记
    读书笔记:《BackTrader 量化交易案例图解》
    JDBC中execute、executeQuery和executeUpdate的区别
  • 原文地址:https://blog.csdn.net/xiamaocheng/article/details/127932995