Skip to content

Commit 6d1345a

Browse files
authored
Merge pull request #9 from baileyfu/reusableWork
Reusable work
2 parents c9f1433 + 5584d5b commit 6d1345a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1306
-178
lines changed

README.md

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,30 @@ RouteAble Work的定义,如下:
143143
- start: 起始Task;从指定Task开始执行;必填
144144
- finish:最终Task;无论如何都会执行,即使执行过程中出现异常;选填
145145

146-
#### 3.4 Extra的配置
146+
#### 3.4 复用Work
147+
有时,一个work的通用性较好,希望将其作为其它work的一个task而被复用;使用taskWrapper标签将该work封装为task:
148+
```
149+
<!- 通用性较好的work,将被复用 ->
150+
<tf:work id="subWork" start="calTask" traceable="true"/>
151+
<!-- 将subWork封装为task供其它work使用 -->
152+
<tf:taskWrapper id="subWorkWrapper" refWork="subWork" resultKey="subWorkResultName">
153+
<tf:routing toTask="someTask"/>
154+
</tf:taskWrapper>
155+
156+
157+
<tf:work id="mainWork" class="taskflow.work.SequentialRouteWork">
158+
<tf:task-ref value="task1"/>
159+
<tf:task-ref value="task2"/>
160+
<!-- 复用subWork,方式一:使用task-ref标签指定被taskWrapper封装过的work -->
161+
<tf:task-ref value="subWorkWrapper"/>
162+
<!-- 复用subWork,方式二:使用work-ref标签指定workId -->
163+
<!-- <tf:work-ref value="subWork"/> -->
164+
</tf:work>
165+
```
166+
配置文件详情见[task-config.xml](./src/test/resources/task-config.xml)
167+
编程式用例见[WorkBuilderDemoApplication](./src/test/java/demo/WorkBuilderDemoApplication.java)
168+
169+
#### 3.5 Extra的配置
147170
在开发中往往需要定义许多的Work,这些不同的Work可能会引用到同一个Task,在执行该Task时,不同的Work可能会需要不同的参数;
148171

149172
extra可以用来指定处于不同Work中的同一个Task的执行参数;extra的数据类型为String,建议定义为JSON,这样更灵活;定义方式如下:
@@ -179,12 +202,15 @@ public class GetDiffTask {
179202
3. 如果最大值和最小值的差大于{x}输出“no”,否则输入“ok”
180203
4. {x}通过配置extra指定
181204

205+
#### 4.1 XML方式
182206
在classpath下新建配置文件task-config.xml
183207

184-
#### 第一步 编写Task类
208+
##### 第一步 编写Task类
209+
185210
编写相应的业务逻辑代码,详见test/demo
186211

187212
例如getDiff的核心代码如下:
213+
188214
```
189215
private NumberService numberService;
190216
public void getDiff(@Taskparam("maxValue") int a, @Taskparam("minValue") int b,WorkContext workContext) {
@@ -196,8 +222,11 @@ public void getDiff(@Taskparam("maxValue") int a, @Taskparam("minValue") int b,W
196222
}
197223
}
198224
```
199-
#### 第二步 定义Task
225+
226+
##### 第二步 定义Task
227+
200228
task-config.xml加入如下配置
229+
201230
```
202231
<bean id="findNumberTaskBean" class="demo.task.FindNumber"/>
203232
@@ -214,12 +243,16 @@ task-config.xml加入如下配置
214243
<tf:task id="soutOutOkTask" ref="findNumberTaskBean" method="soutOutOk"/>
215244
<tf:task id="soutOutNoTask" ref="findNumberTaskBean" method="soutOutNo"/>
216245
```
217-
#### 第三步 定义Work
246+
##### 第三步 定义Work
247+
218248
task-config.xml加入如下配置
249+
219250
```
220251
<tf:work id="testWork" start="findMaxTask" class="taskflow.work.CustomRouteWork"/>
221252
```
222-
#### 第四步 运行
253+
254+
##### 第四步 运行
255+
223256
```
224257
public class DemoApplication {
225258
public static void main(String[] args) {
@@ -240,6 +273,53 @@ public class DemoApplication {
240273
}
241274
```
242275

276+
#### 4.2 编程方式
277+
编程式定义work/task时,taskflow框架不再跟spring耦合,所有要使用到的业务bean应该自行管理。
278+
279+
##### 第一步 定义Task
280+
编写相应的业务逻辑代码,详见test/demo/WorkBuilderDemoApplication.java
281+
282+
示例代码如下:
283+
284+
```
285+
Task findMaxTask = (workContext)->{
286+
List<Integer> input = workContext.get("intList");
287+
int maxValue = numberService.findMax(input);
288+
workContext.put("maxValue", maxValue);
289+
};
290+
@Autowired
291+
FindNumber findNumber;
292+
Task getDiffTask = (workContext) -> {
293+
int maxValue = workContext.get("maxValue");
294+
int minValue = workContext.get("minValue");
295+
findNumber.getDiff(maxValue, minValue, workContext);
296+
};
297+
```
298+
299+
##### 第二步 使用WorkBuilder创建Work
300+
301+
WorkBuilder可以创建RouteAbleWorkBuilder和SequentialWorkBuilder,分别用来生成顺序Work和可路由Work。
302+
303+
```
304+
RouteAbleWorkBuilder workBuilder = WorkBuilder.newRouteableInstance();
305+
//添加task后可立即为其添加routing,多个routing可连续调用多次putRouting()方法来添加
306+
//定义routing时,若key和toTask都为空则routing无效,会被忽略
307+
//routing可指向当前task以循环执行,最大次数受maxTasks的影响;见test/demo.WorkBuilderApplication示例
308+
workBuilder.addTask(findMaxTask).putRouting(findMaxTask,RoutingBuilder.newInstance().toTask(findMinTask.getId()).build())
309+
.addTask(getDiffTask,"{threshold:1}").putRouting(RoutingBuilder.newInstance().key("ok").toTask(soutOutOkTask.getId()).extra("HighPriority_OK").build())
310+
.putRouting(RoutingBuilder.newInstance().key("no").toTask(soutOutNoTask.getId()).extra("HighPriority_NO").build()
311+
...
312+
.addTask(findNumber::soutOutOk);
313+
```
314+
315+
##### 第三步 运行work
316+
317+
```
318+
Work work=workBuilder.build();
319+
work.putContext("intList", Arrays.asList(5, 7, 1, 0, 1, 3, 4, 5, 6, 4));
320+
String result = work.run().getResult();
321+
```
322+
243323
### 5.异步Task
244324
Sequential Work支持异步执行Task(RouteAble Work不支持,因为每一个Task是否执行由上一个Task决定)。
245325
当Sequential Work中的某些Task跟其它Task没有依赖或执行顺序要求时,可以将该Task设置为异步方式执行,方式如下:
@@ -294,6 +374,11 @@ Task在执行时依然按照定义的顺序调用,若为异步Task则触发调
294374
<td>允许运行时动态重载work</td>
295375
<td>true</td>
296376
</tr>
377+
<tr>
378+
<td>taskflow.work.maxTasks</td>
379+
<td>允许执行的task次数上限</td>
380+
<td>1000</td>
381+
</tr>
297382
<tr>
298383
<td>taskflow.work.traceable</td>
299384
<td>允许记录task执行时的参数情况;开启时每个task执行会记录下当时workcontext的快照</td>
@@ -361,4 +446,14 @@ Task在执行时依然按照定义的顺序调用,若为异步Task则触发调
361446
3.xml形式注册work支持输出注册记录</td>
362447
<td>2022-2-11</td>
363448
</tr>
449+
<tr>
450+
<td>3.1.0</td>
451+
<td>1.work可复用<br/>
452+
2.Task接口参数由Work修改为WorkContext<br/>
453+
3.所有Task的入参不再接受Work,统一为WorkContext<br/>
454+
4.支持编程式定义work/task<br/>
455+
5.新增系统参数maxTasks<br/>
456+
</td>
457+
<td>2022-4-25</td>
458+
</tr>
364459
</table>

src/main/java/taskflow/config/TaskDefinitionParser.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,24 @@
1313

1414
import taskflow.config.bean.TaskDefinition;
1515
import taskflow.config.bean.TaskDefinition.RouteDefinition;
16+
import taskflow.config.bean.TaskDefinition.TaskWrapperDefinition;
1617
import taskflow.config.register.TaskRegister;
1718
import taskflow.enums.ConfigSource;
1819
import taskflow.enums.Tag;
1920
import taskflow.enums.TagAttribute;
20-
import taskflow.task.TaskRoutingWrap;
21+
import taskflow.task.routing.TaskRoutingWrap;
2122

2223
/**
2324
* 处理<tf:task>标签 对于ref的Task,使用{@link TaskRoutingWrap}进行包装 <br/>
25+
* 处理<tf:taskWrapper>标签 对于ref的Work,包装成{@link taskflow.task.TaskWrapper},然后再使用{@link TaskRoutingWrap}进行包装 <br/>
2426
* Created by lizhou on 2017/3/14/014. <br/>
2527
* updated by fuli on 2018/5 <br/>
2628
*/
2729
public class TaskDefinitionParser implements BeanDefinitionParser,TaskRegister {
2830
public BeanDefinition parse(Element element, ParserContext parserContext) {
31+
if (element.getTagName().equals(Tag.TASKWRAPPER.getTagName())) {
32+
return parseTaskwrapper(element, parserContext);
33+
}
2934
String id = element.getAttribute(ID_ATTRIBUTE);
3035
String ref = element.getAttribute(REF_ATTRIBUTE);
3136
String method = element.getAttribute(TagAttribute.TASK_METHOD.NAME);
@@ -36,6 +41,25 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
3641
taskDefinition.setTaskBeanId(ref);
3742
taskDefinition.setMethod(method);
3843
taskDefinition.setExtra(extra);
44+
taskDefinition.setRouteDefinitions(parseRouting(element));
45+
return registerTask(parserContext.getRegistry(), taskDefinition);
46+
}
47+
48+
private BeanDefinition parseTaskwrapper(Element element, ParserContext parserContext) {
49+
String id = element.getAttribute(ID_ATTRIBUTE);
50+
String refWork = element.getAttribute(TagAttribute.TASKWRAPPER_REF_WORK.NAME);
51+
String resultKey = element.getAttribute(TagAttribute.TASKWRAPPER_RESULT_KEY.NAME);
52+
53+
TaskWrapperDefinition taskWrapperDefinition = new TaskWrapperDefinition();
54+
taskWrapperDefinition.setTaskId(id);
55+
taskWrapperDefinition.setRefWork(refWork);
56+
taskWrapperDefinition.setResultKey(resultKey);
57+
58+
taskWrapperDefinition.setRouteDefinitions(parseRouting(element));
59+
return registerTask(parserContext.getRegistry(), taskWrapperDefinition);
60+
}
61+
62+
private Set<RouteDefinition> parseRouting(Element element){
3963
Set<RouteDefinition> routeDefinitions=new HashSet<>();
4064
int length = element.getChildNodes().getLength();
4165
for (int i = 0; i < length; i++) {
@@ -46,16 +70,15 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
4670
RouteDefinition routeDefinition=new RouteDefinition();
4771
routeDefinition.setKey(e.getAttribute(TagAttribute.TASK_ROUTING_KEY.NAME));
4872
routeDefinition.setToTask(e.getAttribute(TagAttribute.TASK_ROUTING_TO_TASK.NAME));
49-
routeDefinition.setPatten(e.getAttribute(TagAttribute.TASK_ROUTING_PATTEN.NAME));
73+
routeDefinition.setPattern(e.getAttribute(TagAttribute.TASK_ROUTING_PATTERN.NAME));
5074
routeDefinition.setExtra(e.getAttribute(TagAttribute.TASK_ROUTING_EXTRA.NAME));
5175
routeDefinitions.add(routeDefinition);
5276
}
5377
}
5478
}
55-
taskDefinition.setRouteDefinitions(routeDefinitions);
56-
return registerTask(parserContext.getRegistry(), taskDefinition);
79+
return routeDefinitions;
5780
}
58-
81+
5982
@Override
6083
public ConfigSource getConfigSource() {
6184
return ConfigSource.XML;

src/main/java/taskflow/config/TaskFlowConfiguration.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import org.springframework.context.ApplicationContext;
88
import org.springframework.context.annotation.Bean;
99
import org.springframework.context.annotation.Configuration;
10-
import org.springframework.core.env.Environment;
1110

1211
import taskflow.config.bean.TaskBeanDefinition;
1312
import taskflow.config.bean.TaskDefinition;
@@ -23,11 +22,11 @@
2322
@Configuration
2423
public class TaskFlowConfiguration {
2524
@Bean(initMethod = TaskFlowPropertySetterBean.NAME_OF_INIT_METHOD)
26-
public TaskFlowPropertySetterBean taskFlowPropertySetter(ApplicationContext applicationContext) {
25+
public TaskFlowPropertySetterBean taskFlowPropertySetter() {
2726
return new TaskFlowPropertySetterBean();
2827
}
2928
@Bean(initMethod=TaskFlowBeanReloadProcessor.NAME_OF_INIT_METHOD)
30-
public TaskFlowBeanReloadProcessor taskFlowBeanReloadProcessor(Environment environment) {
29+
public TaskFlowBeanReloadProcessor taskFlowBeanReloadProcessor() {
3130
return new TaskFlowBeanReloadProcessor();
3231
}
3332

src/main/java/taskflow/config/TaskFlowNamespaceHandlerSupport.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
*/
1111
public class TaskFlowNamespaceHandlerSupport extends NamespaceHandlerSupport{
1212
public void init() {
13-
registerBeanDefinitionParser(Tag.TASK.VALUE, new TaskDefinitionParser());
13+
TaskDefinitionParser taskDefinitionParser = new TaskDefinitionParser();
14+
registerBeanDefinitionParser(Tag.TASK.VALUE, taskDefinitionParser);
15+
registerBeanDefinitionParser(Tag.TASKWRAPPER.VALUE, taskDefinitionParser);
1416
registerBeanDefinitionParser(Tag.WORK.VALUE, new WorkDefinitionParser());
1517
registerBeanDefinitionParser(Tag.WORK_FACTORY.VALUE, new WorkFactoryDefinitionParser());
1618
}

src/main/java/taskflow/config/WorkDefinitionParser.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.CLASS_ATTRIBUTE;
44
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.ID_ATTRIBUTE;
5-
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.VALUE_ATTRIBUTE;
65
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.INDEX_ATTRIBUTE;
7-
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.TYPE_ATTRIBUTE;
86
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.NAME_ATTRIBUTE;
97
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.REF_ATTRIBUTE;
8+
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.TYPE_ATTRIBUTE;
9+
import static org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.VALUE_ATTRIBUTE;
1010

1111
import java.util.ArrayList;
1212

@@ -20,6 +20,7 @@
2020
import taskflow.config.bean.WorkDefinition;
2121
import taskflow.config.bean.WorkDefinition.ConstructorArg;
2222
import taskflow.config.bean.WorkDefinition.TaskRef;
23+
import taskflow.config.bean.WorkDefinition.WorkRef;
2324
import taskflow.config.register.WorkRegister;
2425
import taskflow.enums.ConfigSource;
2526
import taskflow.enums.Tag;
@@ -41,8 +42,8 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
4142
WorkDefinition workDefinition=new WorkDefinition();
4243
workDefinition.setWorkId(id);
4344
workDefinition.setWorkClazz(clazz);
44-
workDefinition.setStart(element.getAttribute(TagAttribute.WORK_START.NAME));
45-
workDefinition.setFinish(element.getAttribute(TagAttribute.WORK_FINISH.NAME));
45+
workDefinition.setStart(element.getAttribute(TagAttribute.WORK_START.NAME));
46+
workDefinition.setFinish(element.getAttribute(TagAttribute.WORK_FINISH.NAME));
4647
workDefinition.setMaxTasks(NumberUtils.toInt(maxTasks,0));
4748
workDefinition.setTraceable(BooleanUtils.toBoolean(traceable));
4849
ArrayList<ConstructorArg> constructorArgs = new ArrayList<>();
@@ -52,13 +53,21 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
5253
org.w3c.dom.Node node = element.getChildNodes().item(i);
5354
if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
5455
Element elm = (Element) node;
55-
if(Tag.TASK_REF.getTagName().equalsIgnoreCase(elm.getTagName())) {
56+
if (Tag.TASK_REF.getTagName().equalsIgnoreCase(elm.getTagName())) {
5657
TaskRef taskRef=new TaskRef();
5758
taskRef.setTaskId(elm.getAttribute(VALUE_ATTRIBUTE));
5859
taskRef.setExtra(elm.getAttribute(TagAttribute.TASK_EXTRA.NAME));
5960
taskRef.setAsync(Boolean.valueOf(elm.getAttribute(TagAttribute.TASK_ASYNC.NAME)));
6061
taskRefs.add(taskRef);
61-
}else if(Tag.CONSTRUCTOR_ARG.getTagName().equalsIgnoreCase(elm.getTagName())) {
62+
} if (Tag.WORK_REF.getTagName().equalsIgnoreCase(elm.getTagName())) {
63+
WorkRef taskRef=new WorkRef();
64+
String refWorkId = elm.getAttribute(VALUE_ATTRIBUTE);
65+
taskRef.setTaskId(refWorkId);
66+
taskRef.setRefWork(refWorkId);
67+
taskRef.setResultKey(elm.getAttribute(TagAttribute.TASKWRAPPER_RESULT_KEY.NAME));
68+
taskRef.setAsync(Boolean.valueOf(elm.getAttribute(TagAttribute.TASK_ASYNC.NAME)));
69+
taskRefs.add(taskRef);
70+
} else if (Tag.CONSTRUCTOR_ARG.getTagName().equalsIgnoreCase(elm.getTagName())) {
6271
ConstructorArg constructorArg = new ConstructorArg();
6372
constructorArg.setIndex(NumberUtils.toInt(elm.getAttribute(INDEX_ATTRIBUTE), 0));
6473
constructorArg.setName(elm.getAttribute(NAME_ATTRIBUTE));

0 commit comments

Comments
 (0)