Skip to content

Commit 21e3c25

Browse files
committed
add Script ThreadPools
1 parent 5cbdc3e commit 21e3c25

File tree

11 files changed

+202
-49
lines changed

11 files changed

+202
-49
lines changed

admin-ui/src/components/Flow/utils/script.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
class GroovyScript {
44

55
public static defaultOutTrigger = "def run(content) {return true;}";
6-
public static defaultTitleGenerator = "def run(content){ return content.getCreateOperator().getName() + \'-\' + content.getFlowWork().getTitle() + \'-\' + content.getFlowNode().getName();}";
6+
public static defaultTitleGenerator = "def run(content){ return content.getCurrentOperator().getName() + '-' + content.getFlowWork().getTitle() + '-' + content.getFlowNode().getName();}";
77

88
public static anyOperatorMatcher="def run(content) {return [content.getCurrentOperator().getUserId()];}";
99
public static creatorOperatorMatcher="def run(content) {return [content.getCreateOperator().getUserId()];}";

springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/error/ErrTrigger.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package com.codingapi.springboot.flow.error;
22

33
import com.codingapi.springboot.flow.content.FlowSession;
4-
import groovy.lang.GroovyShell;
5-
import groovy.lang.Script;
4+
import com.codingapi.springboot.flow.script.GroovyShellContext;
65
import lombok.Getter;
76
import org.springframework.util.StringUtils;
87

@@ -14,16 +13,15 @@ public class ErrTrigger {
1413
@Getter
1514
private final String script;
1615

17-
private final Script runtime;
16+
private final GroovyShellContext.ShellScript runtime;
1817

1918

2019
public ErrTrigger(String script) {
2120
if (!StringUtils.hasLength(script)) {
2221
throw new IllegalArgumentException("script is empty");
2322
}
2423
this.script = script;
25-
GroovyShell groovyShell = new GroovyShell();
26-
this.runtime = groovyShell.parse(script);
24+
this.runtime = GroovyShellContext.getInstance().parse(script);
2725
}
2826

2927
/**

springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/generator/TitleGenerator.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
11
package com.codingapi.springboot.flow.generator;
22

33
import com.codingapi.springboot.flow.content.FlowSession;
4-
import groovy.lang.GroovyShell;
5-
import groovy.lang.Script;
4+
import com.codingapi.springboot.flow.script.GroovyShellContext;
65
import lombok.Getter;
76
import org.springframework.util.StringUtils;
87

98
/**
109
* 标题生成器
1110
*/
12-
public class TitleGenerator {
11+
public class TitleGenerator {
1312

1413
@Getter
1514
private final String script;
1615

17-
private final Script runtime;
16+
private final GroovyShellContext.ShellScript runtime;
1817

1918
public TitleGenerator(String script) {
2019
if (!StringUtils.hasLength(script)) {
2120
throw new IllegalArgumentException("script is empty");
2221
}
2322
this.script = script;
24-
GroovyShell groovyShell = new GroovyShell();
25-
this.runtime = groovyShell.parse(script);
23+
this.runtime = GroovyShellContext.getInstance().parse(script);
2624
}
2725

2826

@@ -32,7 +30,7 @@ public TitleGenerator(String script) {
3230
* @return 标题生成器
3331
*/
3432
public static TitleGenerator defaultTitleGenerator() {
35-
return new TitleGenerator("def run(content){ return content.getCreateOperator().getName() + '-' + content.getFlowWork().getTitle() + '-' + content.getFlowNode().getName();}");
33+
return new TitleGenerator("def run(content){ return content.getCurrentOperator().getName() + '-' + content.getFlowWork().getTitle() + '-' + content.getFlowNode().getName();}");
3634
}
3735

3836

springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/matcher/OperatorMatcher.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package com.codingapi.springboot.flow.matcher;
22

33
import com.codingapi.springboot.flow.content.FlowSession;
4-
import groovy.lang.GroovyShell;
5-
import groovy.lang.Script;
4+
import com.codingapi.springboot.flow.script.GroovyShellContext;
65
import lombok.Getter;
76
import org.springframework.util.StringUtils;
87

@@ -20,7 +19,7 @@ public class OperatorMatcher {
2019

2120
private final int state;
2221

23-
private final Script runtime;
22+
private final GroovyShellContext.ShellScript runtime;
2423

2524
// 指定用户
2625
public static final int STATE_SPECIFY = 1;
@@ -42,12 +41,12 @@ public boolean isSpecify() {
4241
return state == STATE_SPECIFY;
4342
}
4443

45-
private static int parseState(String script){
46-
if(script.contains("content.getCurrentOperator().getUserId()")){
44+
private static int parseState(String script) {
45+
if (script.contains("content.getCurrentOperator().getUserId()")) {
4746
return STATE_ANY;
48-
}else if(script.contains("content.getCreateOperator().getUserId()")){
47+
} else if (script.contains("content.getCreateOperator().getUserId()")) {
4948
return STATE_CREATOR;
50-
}else{
49+
} else {
5150
return STATE_SPECIFY;
5251
}
5352
}
@@ -63,8 +62,7 @@ public OperatorMatcher(String script, int state) {
6362
}
6463
this.script = script;
6564
this.state = state;
66-
GroovyShell groovyShell = new GroovyShell();
67-
this.runtime = groovyShell.parse(script);
65+
this.runtime = GroovyShellContext.getInstance().parse(script);
6866
}
6967

7068
/**

springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/pojo/FlowDetail.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,7 @@ public FlowDetail(FlowRecord flowRecord,
6868
this.flowRecord = flowRecord;
6969
this.flowWork = flowWork;
7070
this.bindData = snapshot.toBindData();
71-
this.historyRecords = historyRecords.
72-
stream().
73-
sorted((o1, o2) -> (int) (o1.getCreateTime() - o2.getCreateTime()))
74-
.toList();
71+
this.historyRecords = historyRecords;
7572
this.opinions = historyRecords.stream().map(FlowOpinion::new).toList();
7673
this.flowCreator = operators.stream().filter(o -> o.getUserId() == flowRecord.getCreateOperatorId()).findFirst().orElse(null);
7774
this.flowCreateTime = flowRecord.getCreateTime();

springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/record/FlowRecord.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,4 +407,11 @@ public boolean isTimeout() {
407407
public boolean isPostponed() {
408408
return this.postponedCount > 0;
409409
}
410+
411+
/**
412+
* 是否是发起节点
413+
*/
414+
public boolean isStartRecord() {
415+
return this.preId == 0;
416+
}
410417
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.codingapi.springboot.flow.script;
2+
3+
import com.codingapi.springboot.flow.utils.Sha256Utils;
4+
import groovy.lang.GroovyShell;
5+
import groovy.lang.Script;
6+
import lombok.Getter;
7+
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
import java.util.concurrent.ExecutorService;
11+
import java.util.concurrent.Executors;
12+
13+
public class GroovyShellContext {
14+
15+
@Getter
16+
private final static GroovyShellContext instance = new GroovyShellContext();
17+
18+
private final static GroovyShell groovyShell = new GroovyShell();
19+
20+
private final Map<String, ShellScript> cache = new HashMap<>();
21+
22+
private final static ExecutorService threadPool = Executors.newFixedThreadPool(10);
23+
24+
// 缓存最大值
25+
private final static int MAX_CACHE_SIZE = 10000;
26+
27+
28+
private GroovyShellContext() {
29+
}
30+
31+
public ShellScript parse(String script) {
32+
String hash = Sha256Utils.generateSHA256(script);
33+
if (cache.containsKey(hash)) {
34+
return cache.get(hash);
35+
} else {
36+
if (cache.size() > MAX_CACHE_SIZE) {
37+
cache.clear();
38+
}
39+
ShellScript shellScript = new ShellScript(script);
40+
threadPool.submit(shellScript);
41+
cache.put(hash, shellScript);
42+
return shellScript;
43+
}
44+
}
45+
46+
47+
public int size() {
48+
return cache.size();
49+
}
50+
51+
public static class ShellScript implements Runnable {
52+
53+
@Getter
54+
private final String script;
55+
56+
private Script runtime;
57+
58+
public ShellScript(String script) {
59+
this.script = script;
60+
}
61+
62+
public Object invokeMethod(String run, Object params) {
63+
synchronized (ShellScript.this) {
64+
if (runtime == null) {
65+
try {
66+
ShellScript.this.wait(1000);
67+
} catch (InterruptedException ignored) {
68+
}
69+
if (runtime == null) {
70+
runtime = groovyShell.parse(script);
71+
}
72+
}
73+
return runtime.invokeMethod(run, params);
74+
}
75+
}
76+
77+
@Override
78+
public void run() {
79+
runtime = groovyShell.parse(script);
80+
synchronized (ShellScript.this) {
81+
this.notifyAll();
82+
}
83+
}
84+
}
85+
86+
87+
}

springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/service/FlowService.java

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void urge(long recordId, IFlowOperator currentOperator) {
9595
// 推送催办消息
9696
for (FlowRecord record : todoRecords) {
9797
IFlowOperator pushOperator = flowOperatorRepository.getFlowOperatorById(record.getCurrentOperatorId());
98-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_URGE, record, pushOperator, flowWork,null));
98+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_URGE, record, pushOperator, flowWork, null));
9999
}
100100

101101
}
@@ -122,7 +122,10 @@ public FlowDetail detail(long recordId, IFlowOperator currentOperator) {
122122

123123

124124
BindDataSnapshot snapshot = flowBindDataRepository.getBindDataSnapshotById(flowRecord.getSnapshotId());
125-
List<FlowRecord> flowRecords = flowRecordRepository.findFlowRecordByProcessId(flowRecord.getProcessId());
125+
List<FlowRecord> flowRecords = flowRecordRepository.findFlowRecordByProcessId(flowRecord.getProcessId()).
126+
stream().
127+
sorted((o1, o2) -> (int) (o1.getId() - o2.getId()))
128+
.toList();
126129

127130
// 获取所有的操作者
128131
List<Long> operatorIds = new ArrayList<>();
@@ -201,8 +204,12 @@ public void transfer(long recordId, IFlowOperator currentOperator, IFlowOperator
201204
IFlowOperator createOperator = flowOperatorRepository.getFlowOperatorById(flowRecord.getCreateOperatorId());
202205

203206
// 与当前流程同级的流程记录
204-
List<FlowRecord> historyRecords = flowRecordRepository.findFlowRecordByPreId(flowRecord.getPreId());
205-
207+
List<FlowRecord> historyRecords;
208+
if (flowRecord.isStartRecord()) {
209+
historyRecords = new ArrayList<>();
210+
} else {
211+
historyRecords = flowRecordRepository.findFlowRecordByPreId(flowRecord.getPreId());
212+
}
206213

207214
// 创建新的待办标题
208215
FlowSession content = new FlowSession(flowWork, flowNode, createOperator, targetOperator, snapshot.toBindData(), opinion, historyRecords);
@@ -214,10 +221,10 @@ public void transfer(long recordId, IFlowOperator currentOperator, IFlowOperator
214221
flowRecordRepository.save(List.of(transferRecord));
215222

216223
// 推送转办消息
217-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TRANSFER, flowRecord, currentOperator, flowWork,snapshot.toBindData()));
224+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TRANSFER, flowRecord, currentOperator, flowWork, snapshot.toBindData()));
218225

219226
// 推送待办消息
220-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TODO, transferRecord, targetOperator, flowWork,snapshot.toBindData()));
227+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TODO, transferRecord, targetOperator, flowWork, snapshot.toBindData()));
221228
}
222229

223230

@@ -296,14 +303,16 @@ public void startFlow(long workId, IFlowOperator operator, IBindData bindData, S
296303
// 设置开始流程的上一个流程id
297304
long preId = 0;
298305

306+
List<FlowRecord> historyRecords = new ArrayList<>();
307+
299308
FlowRecordBuilderService flowRecordBuilderService = new FlowRecordBuilderService(
300309
flowOperatorRepository,
301310
flowRecordRepository,
302311
snapshot,
303312
opinion,
304313
operator,
305314
operator,
306-
new ArrayList<>(),
315+
historyRecords,
307316
flowWork,
308317
processId,
309318
preId
@@ -320,8 +329,8 @@ public void startFlow(long workId, IFlowOperator operator, IBindData bindData, S
320329

321330
// 推送事件消息
322331
for (FlowRecord record : records) {
323-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_CREATE, record, operator, flowWork,snapshot.toBindData()));
324-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TODO, record, operator, flowWork,snapshot.toBindData()));
332+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_CREATE, record, operator, flowWork, snapshot.toBindData()));
333+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TODO, record, operator, flowWork, snapshot.toBindData()));
325334
}
326335

327336
}
@@ -379,8 +388,13 @@ public void submitFlow(long recordId, IFlowOperator currentOperator, IBindData b
379388
flowRecord.submitRecord(currentOperator, snapshot, opinion, flowSourceDirection);
380389
flowRecordRepository.update(flowRecord);
381390

382-
// 获取与当前流程同级的流程记录
383-
List<FlowRecord> historyRecords = flowRecordRepository.findFlowRecordByPreId(flowRecord.getPreId());
391+
// 与当前流程同级的流程记录
392+
List<FlowRecord> historyRecords;
393+
if (flowRecord.isStartRecord()) {
394+
historyRecords = new ArrayList<>();
395+
} else {
396+
historyRecords = flowRecordRepository.findFlowRecordByPreId(flowRecord.getPreId());
397+
}
384398
flowDirectionService.bindHistoryRecords(historyRecords);
385399

386400
// 判断流程是否结束(会签时需要所有人都通过)
@@ -412,7 +426,7 @@ public void submitFlow(long recordId, IFlowOperator currentOperator, IBindData b
412426
flowRecordRepository.update(flowRecord);
413427
flowRecordRepository.finishFlowRecordByProcessId(flowRecord.getProcessId());
414428

415-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_FINISH, flowRecord, currentOperator, flowWork,snapshot.toBindData()));
429+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_FINISH, flowRecord, currentOperator, flowWork, snapshot.toBindData()));
416430
return;
417431
}
418432

@@ -451,12 +465,12 @@ public void submitFlow(long recordId, IFlowOperator currentOperator, IBindData b
451465

452466
// 推送审批事件消息
453467
int eventState = flowSourceDirection == FlowSourceDirection.PASS ? FlowApprovalEvent.STATE_PASS : FlowApprovalEvent.STATE_REJECT;
454-
EventPusher.push(new FlowApprovalEvent(eventState, flowRecord, currentOperator, flowWork,snapshot.toBindData()));
468+
EventPusher.push(new FlowApprovalEvent(eventState, flowRecord, currentOperator, flowWork, snapshot.toBindData()));
455469

456470
// 推送待办事件消息
457471
for (FlowRecord record : records) {
458472
IFlowOperator pushOperator = flowOperatorRepository.getFlowOperatorById(record.getCurrentOperatorId());
459-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TODO, record, pushOperator, flowWork,snapshot.toBindData()));
473+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_TODO, record, pushOperator, flowWork, snapshot.toBindData()));
460474
}
461475
}
462476

@@ -498,7 +512,7 @@ public void recall(long recordId, IFlowOperator currentOperator) {
498512
flowRecordRepository.update(flowRecord);
499513

500514
flowRecordRepository.delete(childrenRecords);
501-
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_RECALL, flowRecord, currentOperator, flowWork,null));
515+
EventPusher.push(new FlowApprovalEvent(FlowApprovalEvent.STATE_RECALL, flowRecord, currentOperator, flowWork, null));
502516
}
503517

504518
}

0 commit comments

Comments
 (0)