SpringBoot – LiteFlow Engine Framework

Time:2024-3-5

Introduction to LiteFlow

LiteFlowanLightweight and powerful domestic rules engine frameworkIt can be used in the area of orchestration for complex componentized businesses. Helps make systems silky smooth and flexible. UtilizingLiteFlowYou can transform the waterfall code into a component as the core concept of the code structure, the benefit of this structure is that it can be arbitrarily orchestrated, components are decoupled from each other, components can be defined by scripts, and the flow between components is driven by rules.LiteFlowWith the simplest open source rules engineDSLGrammar.LiteFlow Official Website LiteFlowin2020officially open-sourced in 2007.2021In 2007, it won the award for the most popular open source software of the year in Open Source China. In2022annual awardGiteeMost valuable open source projectsGVPHonors. It is an open source project that is in rapid development.LiteFlowis a community-driven project with a2500community of multiple users. Although compared toAcitivitiFlowableas far as sth. is concernedLiteFlowis much less well known and not as powerful as these well known and established engines, but theLiteFlowThere are still a number of advantages that will fulfill the vast majority of your scenarios. These advantages include: [1] Diversification of rules: Rules SupportxmljsonymlThree ways to write a rules file. [2] Easy to use: pull a fewjarpackage, implement a few interfaces, write a process orchestration file, and run it. [3] Richly organized: Supports a variety of scheduling methods such as serial, parallel, selective, cyclic, exception handling, nested, and so on. [4] Event Listening: Supports event triggering and state change listening, which makes it easy to extend and customize workflow processing logic. [5] Asynchronous timeout: Supports asynchronous execution and timeout control, which can improve the concurrent processing capability and stability of the system. [6] Scripting support: Support for all major scripting languages. [7] Configuration sources are abundant: Support for putting process definitions intoZK/DB/Etcd/Nacos/Redis/Apolloand custom extensions, etc. Equivalently, dynamic configuration changes can be implemented. [8] Customization: Highly customizable, users can freely expand and customize according to their needsLiteFlowThe various components and functions of the [9] Numerous scripting languages are supported: LiteFlowScripting components that support a wide range of scripting languagesGroovy/JavaScript/QLExpress/Python/Lua/Aviator/JavaThe exact same thing as theJavaHit the pass and you can script any logic. [10] Elegant thermal refresh mechanism: Rule changes, instantly change the rules of your application without restarting your application. High concurrency does not cause any misalignment of the rules being executed due to refreshing the rules. [11] Support is widespread: It doesn’t matter if your project is based onSpringbootSpringOr any otherjavaframework construction.LiteFlowIt’s all swimmingly. [12] Contextual isolation mechanisms: Reliable context isolation mechanism, you do not need to worry about data streaming in highly concurrent situations. [13] Excellent performance: The framework itself consumes little additional performance; performance depends on how efficiently your components execute. [14] Comes with simple monitoring: The framework comes with a command line monitor to know the running time ranking of each component.
Systems suitable for this technology
In every company’s system, there are always some systems with complex business logic, these systems carry the core business logic, almost every requirement is related to these core businesses, these core business business logic is lengthy, involving internal logic operations, caching operations, persistence operations, external resource retrieval, internal other systems.RPCCalls and so on. Over time, the project changes hands several times, and maintenance costs become higher and higher. A variety of hard code judgment, branching conditions more and more. Code abstraction, reuse rate is also getting lower and lower, the coupling between the various modules is very high. A small change in the logic will affect other modules, and complete regression testing is required to verify. If you want to flexibly change the order of business processes, you have to make major code changes for abstraction and rewrite the methods. It is almost difficult to realize the real-time hot change business process. How to break the deadlock?LiteFlowBuilt for decoupling logic, built for orchestration, in the use of theLiteFlowAfter that, you’ll find that building a low-coupled, flexible system becomes a snap!

(ii) LiteFlow principle

If you’re rewriting or refactoring complex business logic, use theLiteFlowThe best fit. It is an orchestrated rules engine framework with component orchestration that helps decouple business code so that every piece of business is a component. LiteFlowThe core of this approach is “process as code”, which means that business processes and code structures are tightly coupled.LiteFlowusing a methodology based onXMLThe document’s process definition approach describes the entire workflow by defining process nodes and connecting lines. Each process node corresponds to theJavaA method in the code, and the connecting line corresponds to the calling relationship between the methods. In this way, we can very intuitively see how the whole business process is handled, and it is easier and faster to modify the process. SpringBoot - LiteFlow Engine Framework assembliesReal-time hot turnover, which can also add a component to a choreographed logic flow in real time, thus changing your business logic. SpringBoot - LiteFlow Engine Framework The orchestration syntax is powerful enough to orchestrate any logical flow you want for example: SpringBoot - LiteFlow Engine Framework

III. Scenarios of use

LiteFlowWhat scenarios are applicable: LiteFlowApply to have complex logic of the business, such as price engine, order process, etc., these businesses often have a lot of steps, these steps can be completely in accordance with the business granularity of the split into a separate component, assembly reuse changes. UseLiteFlowYou’ll get a system that is highly flexible and scalable. Because the components are independent of each other, you can also avoid the risk of changing one thing and moving the whole body. LiteFlowWhich scenarios are not applicable: LiteFlowIt is not suitable for the flow between role tasks, similar to the approval flow, after A approves it should be approved by B and then flow to C role. Affirmation here.LiteFlowOnly do logic based flows, not role task based flows. If you want to do role task based flow, it is recommended to use theflowableactivitiThese 2 frames.

IV. JDK Support

LiteFlowRequired minimumJDKVersions for8SupportJDK8~JDK17All versions. If you are usingJDK11above to ensure thatLiteFlowThe version ofv2.10.6and above. BecauseLiteFlowfromv2.10.6To begin with, for theJDK11andJDK17Detailed use case testing was performed, passing all of the900multiple test cases. While thev2.10.6The following versions, inJDK11The above is not secured by test cases. In particular, note that if you useJDK11and above, make sure that thejvmparameter plus the following parameters:
--add-opens java.base/sun.reflect.annotation=ALL-UNNAMED

V. Springboot integration process

LiteFlowdemandingSpringbootThe lowest version of2.0. The range of support isSpringboot 2.X ~ Springboot 3.X. If you are using the latestSpringboot 3.XThe corresponding JDK version should also be switched to theJDK17LiteFlowoffersliteflow-spring-boot-starterDependency packages to provide automated assembly
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-spring-boot-starter</artifactId>
    <version>2.11.3</version>
</dependency>

Component Definition

After relying on the abovejarAfter the package, you need to define and implement some components to ensure that theSpringBootwill scan for these components and register them into the context.
@Component("a")
public class ACmp extends NodeComponent {

	@Override
	public void process() {
		//do your business
	}
}
And so on before defining the b,c components separately:
@Component("b")
public class BCmp extends NodeComponent {

	@Override
	public void process() {
		//do your business
	}
}


@Component("c")
public class CCmp extends NodeComponent {

	@Override
	public void process() {
		//do your business
	}
}

SpringBoot Configuration File

Then, in yourSpringBoottheapplication.propertiesorapplication.ymlAdd the configuration in theyamlAs an example.propertiesIt’s the same thing.)
liteflow:
  # Rule file path
  rule-source: config/flow.el.xml
  #----------------- following non-required -----------------
  Whether #liteflow is enabled or not, default is true.
  enable: true
  Whether #liteflow's banner printing is enabled or not, defaults to true.
  print-banner: true
  #zkNode's node, only works when using zk as a configuration source, defaults to /lite-flow/flow
  zk-node: /lite-flow/flow
  Maximum number of slots for #contexts, default value is 1024
  slot-size: 1024
  The number of threads in the #FlowExecutor's execute2Future, default is 64.
  main-executor-works: 64
  Custom thread pool Builder for #FlowExecutor's execute2Future, LiteFlow provides a default Builder
  main-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder
  #Customize the generation class for request IDs, LiteFlow provides a default generation class
  request-id-generator-class: com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator
  Thread Pool Builder for #parallel nodes, LiteFlow provides a default Builder
  thread-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultWhenExecutorBuilder
  Maximum wait time for # asynchronous threads (only used for when), default value is 15000
  when-max-wait-time: 15000
  Maximum wait time for # asynchronous threads (only for when), defaults to MILLISECONDS, milliseconds
  when-max-wait-time-unit: MILLISECONDS
  Maximum number of threads in the global asynchronous thread pool for the #when node, default is 16
  when-max-workers: 16
  Maximum number of threads in the thread pool for #parallel loop subitems, default is 16
  parallelLoop-max-workers: 16
  # Parallel loop sub-item thread pool waiting queue number, default is 512
  parallelLoop-queue-limit: 512
  Thread Pool Builder for #Parallel Loop Subterms, LiteFlow provides default Builder
  parallelLoop-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder
  #when node global asynchronous thread pool waiting queue number, default is 512
  when-queue-limit: 512
  # Whether to parse rules at startup, default is true
  parse-on-start: true
  # global retry count, default is 0
  retry-count: 0
  # Whether to support mixing different types of loading methods, default is false
  support-multiple-type: false
  # Global default node executor
  node-executor-class: com.yomahub.liteflow.flow.executor.DefaultNodeExecutor
  #Whether to print the log during execution, default is true.
  print-execution-log: true
  # Whether to enable local file listening, the default is false.
  enable-monitor-file: false
  # Easy monitoring configuration options
  monitor:
    #Whether monitoring is enabled or not, default is not enabled
    enable-log: false
    # Monitor queue storage size, default value is 200
    queue-limit: 200
    # Monitor how much execution is delayed at the beginning, default value is 300000 milliseconds, that is 5 minutes
    delay: 300000
    # Monitor log prints how much time has elapsed since the execution, the default value is 300000 milliseconds, which is 5 minutes.
    period: 300000

Definition of the rules document

In the meantime, you’ll have to be inresourceslowerconfig/flow.el.xmlDefine the rules in:SpringBootThe rules file is automatically loaded at startup.
<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="chain1">
        THEN(a, b, c);
    </chain>
</flow>

fulfillment

Declare the startup class:
@SpringBootApplication
// Sweep the components you defined into the Spring context
@ComponentScan({"com.xxx.xxx.cmp"})
public class LiteflowExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(LiteflowExampleApplication.class, args);
    }
}
You will then be able to add theSpringbootarbitrarilySpringHosted class to get theflowExecutor, performs the execution of the link: thisDefaultContextis the default context, and the user can use the most own arbitraryBeanPassed in as a context, if you need to pass in your own context, you need to pass in the userBeantheClasscausality
@Component
public class YourClass{
    
    @Resource
    private FlowExecutor flowExecutor;
    
    public void testConfig(){
        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
    }
}

VI. Data context

A data context instance is assigned to this request when the executor executes the process. The data context instances for different requests are completely isolated. It holds all the user data for this request. No parameters are passed between different components, all data interactions are realized through this data context.The concept of data context is used in theLiteFlowIt’s very important in the framework that all your business data is placed in a data context.To be programmable, it must eliminate the variability of each component. If every component’s outgoing and incoming parameters are inconsistent, then it can’t be orchestrated. LiteFlowThis has a unique design concept, usually we write a waterfall program, A call B, then A must be B need to pass the parameters to B, and in theLiteFlowThe framework system is defined in such a way that each component is not required to accept parameters and returns nothing.Each component only needs to get the data it cares about from the data context, without caring who provides this data, and similarly, each component only needs to put the resultant data from its own execution into the data context, without caring to whom this data is actually provided. In this way, a certain degree of decoupling from the data level. Thus achieving the purpose of programmability.About this idea, also inLiteFlowThe design principles in the brief are mentioned, and a visual example is given, so you can go back and look at it again.
Once the data is put in the data context, it is fetchable by any node in the entire link.

default context

LiteFlowProvides an implementation of the default data context:DefaultContext. This default implementation actually has the main container for storing data inside is aMap. You can find out more about this by going toDefaultContexthit the nail on the headsetDatamethod into the data via thegetDatamethod to get the data. ::: warning DefaultContextAlthough it can be used, but in the actual business, with this there will be a large number of weak types, access to the data are to be strong conversion, rather inconvenient. So it is officially recommended that you implement your own data context. :::

Custom Context

In a process, there are always some initial parameters, such as the order number, userIdAnd so on for some of the initial parameters. This time it needs to be passed in via the second parameter of the following method:
// Parameters are process IDs, no initial process entry, context type is the default DefaultContext
public LiteflowResponse execute2Resp(String chainId)
// The first parameter is the process ID and the second parameter is the process entry. The context type is the default DefaultContext
public LiteflowResponse execute2Resp(String chainId, Object param);
// The first parameter is the process ID, the second parameter is the process entry parameter, and multiple context classes can be passed in afterward.
public LiteflowResponse execute2Resp(String chainId, Object param, Class<?>... contextBeanClazzArray)
// The first parameter is the process ID, the second parameter is the process entry parameter, and you can pass in multiple contextual beans after that.
public LiteflowResponse execute2Resp(String chainId, Object param, Object... contextBeanArray)
You can use your own arbitraryBeanPassed in as a context.LiteFlowcontextualBeanThere are no requirements. A self-defined context is essentially a value object in the simplest sense of the word, and self-defined contexts are more relevant to business because they are strongly typed. You can make an incoming pass like this:
LiteflowResponse response = flowExecutor. Execute2Resp (" chain1 ", initial parameters, process CustomContext. Class);
After passing in theLiteFlowIt will be initialized at call time to assign a unique instance of this context. You can get this context instance in the component like this:
@LiteflowComponent("yourCmpId")
public class YourCmp extends NodeComponent {

	@Override
	public void process() {
		CustomContext context = this.getContextBean(CustomContext.class);
		// Or you can use this method to get context instances, which is equivalent to the above
		//CustomContext context = this.getFirstContextBean();
		...
	}
}

multi-context

LiteFlowMultiple contexts are supported in the new version, initializing multiple contexts you pass in at the same time during execution. It is also possible to initialize multiple contexts in a component based on theclassThe type is easy to get. You can make passes like this:
LiteflowResponse response = flowExecutor. Execute2Resp (" chain1 ", initial parameters, process OrderContext. Class, UserContext. Class, SignContext.class);
This is how you can get the context instance in the component:
@LiteflowComponent("yourCmpId")
public class YourCmp extends NodeComponent {

	@Override
	public void process() {
		OrderContext orderContext = this.getContextBean(OrderContext.class);
		UserContext userContext = this.getContextBean(UserContext.class);
		SignContext signContext = this.getContextBean(SignContext.class);
		
		//If you only want to get the first context, and the first context is OrderContext, then you can also use this method
		//OrderContext orderContext = this.getFirstContextBean();
		...
	}
}

Pass in the initialized context with the

LiteFlowfrom2.8.4version onwards, allowing the user to pass in one or more already initializedbeanas the context, instead of passing in theclassObject. After getting theFlowExecutorAfter that, you can pass in the initializedbeanas a context (multiple contexts are of course supported, only a single context is demonstrated here):
OrderContext orderContext = new OrderContext();
orderContext.setOrderNo("SO11223344");
LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, orderContext);
::: warning The framework does not support contextbeanandclassMix it up. You can either do it or you can do it.beanEither they all passclass。 :::

VII. Asynchronous Future

public Future<LiteflowResponse> execute2Future(String chainId, Object param, Class<?>... contextBeanClazzArray)
If this method is called, it is non-blocking and trying to get theresponsePlease use the getfuture.get()That’s all. Also, the number of threads and the thread pool of the main executor in this mode can be customized, as configured below, theLiteFlowPresets have been set, or you can define your own.
liteflow.main-executor-works=64
liteflow.main-executor-class=com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder
If you define a custom thread pool, you need to create a new class and then implement theExecutorBuilderInterface:
public class CustomThreadBuilder implements ExecutorBuilder {
    @Override
    public ExecutorService buildExecutor() {
        return Executors.newCachedThreadPool();
    }
}

VIII. Writing of rules

serial scheduling

If you want to execute thea,b,c,dWith four components, you can use the THEN keyword, and it’s important to note that theTHENMust be capitalized.
<chain name="chain1">
    THEN(a, b, c, d);
</chain>

parallel programming

If you want to execute in parallela,b,cThree components that you can useWHENThe keyword, which needs to be noted, isWHENMust be capitalized.
<chain name="chain1">
    WHEN(a, b, c);
</chain>
and serial nested together: let’s use THEN and WHEN in combination to see an example:b,c,dThe default parallels are all executed before thee
<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d),
        e
    );
</chain>
SpringBoot - LiteFlow Engine Framework The above example should be well understood, so look at another example:
<chain name="chain1">
    THEN(
        a,
        WHEN(b, THEN(c, d)),
        e
    );
</chain>
SpringBoot - LiteFlow Engine Framework Ignore the error: WHENThe keyword provides a subkeywordignoreError(default `false“) to provide the feature of ignoring errors, used as follows:
<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d).ignoreError(true),
        e
    );
</chain>
SpringBoot - LiteFlow Engine Framework setb,c,deither one of the nodes has an exception, then the finaleIt will still be enforced. Either node finishes executing first then the others are ignored: WHENThe keyword provides a subkeywordany(defaults tofalse) is used to provide the property that in a parallel process, if any branch finishes first, the other branches are ignored and execution continues. It is used as follows: Assume thatenode finishes executing first, then the node will be executed immediately, regardless of whether the other branches finish executing.f
<chain name="chain1">
    THEN(
        a,
        WHEN(b, THEN(c, d), e).any(true),
        f
    );
</chain>
SpringBoot - LiteFlow Engine Framework Specifies that if any node finishes executing first, the others are ignored: LiteFlowfromv2.11.1Starting with the fact that the execution of a specified node in a parallel orchestration is supported ignores the other.WHENKeywords add subkeywordsmust(not null), which can be used to specify any node to be waited for execution, either as a1or more, if all the nodes specified are completed first, then the execution continues down the list, ignoring other tasks at the same level, the usage is as follows:mustspecifiedb,cfollowb,cis sure to be executed, if theb,cwhen all is said and donedhas not finished executing, it is ignored and the next component is executed directlyf
<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d).must(b, c),
        f
    );
</chain>
The above is the usage of a single node, themustOne or more expressions can also be specified. For example:WHENThere is a nestedTHENIf you need to specify this expression, then you need to set aidmustYou need to specify this in theid, it is important to note thatmustinner tubeid, need to be enclosed in quotation marks.
<chain name="chain1">
    THEN(
        a,
        WHEN(b, THEN(c, d).id("t1"), e).must(b, "t1"),
        f
    );
</chain>
Turn on WHEN thread pool isolation: at the present timeliteflowdesign aspectswhenThe thread pool, if you don’t set up a custom thread pool separately, then the default thread pool is used. And this thread pool, which is the default thread pool for allwhenCommon one.LiteFlow from 2.11.1Start by providing aliteflow.when-thread-pool-isolateparameter, which defaults tofalseIf set totrueThe program will be turned on.WHENThe thread pool isolation mechanism, which means that everywhenwill all have separate thread pools. This feature is useful for running complex nestedwhenIt is possible to increase the speed and avoid some of the locking problems. You can configure it as follows to turn it on:
liteflow.when-thread-pool-isolate=true

Selection Arrangement

When we write business logic, we usually run into the problem of selectivity, i.e., if we return the result 1, we go to theAprocess, and if it returns result 2, it goes to theBprocess, and if it returns a result of 3, it goes to theCProcess. It is also defined as an exclusion gateway in some process definitions. This is defined through theLiteFLowexpressions are also very easy to implement, you can use theSWITCH...TOThe combined keywords of theSWITCHMust be capitalized.toBoth upper and lower case are acceptable. If, depending on the componentato choose to execute theb,c,dYou can declare one of them as follows: SpringBoot - LiteFlow Engine Framework
@LiteflowComponent("a")
public class ACmp extends NodeSwitchComponent {

    @Override
    public String processSwitch() throws Exception {
        System.out.println("Acomp executed!");
        return "c";
    }
}
DEFAULT keyword: LiteFlowfrom2.9.5Starting with a new addition to the selection orchestrationDEFAULTKeywords. Used asSWITCH...TO...DEFAULT. For example, the following expression:
<chain name="chain1">
    SWITCH(x).TO(a, b, c).DEFAULT(y);
</chain>
as in the expression abovexIf the return is nota,b,cis selected by default to one of they. Of course.DEFAULTInside can also be an expression. Selection of the choreographedidGrammar: Next show aSWITCHmiddle setTHENandWHENexample. If you’ve read the chapter on selecting components, you should know that theLiteFlowDetermine what to select by selecting the return of the component. Then if theSWITCHOne centerfoldTHENThen select the component if you want to select thisTHENWhat should be returned?LiteFlowwhich states that each expression can have aidvalue, you can set the id value to set an expression’sidvalue. Then return this in the selection componentidReady to go. Usage is as follows:
<chain name="chain1">
    THEN(
        a,
        SWITCH(b).to(
            c, 
            THEN(d, e).id("t1")
        ),
        f
    );
</chain>
SpringBoot - LiteFlow Engine Framework If you want to chooseTHENexpression, then you can return thet1:
@LiteflowComponent("b")
public class BCmp extends NodeSwitchComponent {

    @Override
    public String processSwitch() throws Exception {
        //do your biz
        return "t1";
    }
}
Select the tag syntax in the orchestration: In fact, in addition to assigning values to expressionsidIn addition to the attributes, you can assign values to the expressiontagAttributes. Usage is as follows:
<chain name="chain1">
    THEN(
        a,
        SWITCH(b).to(
            c, 
            THEN(d, e).tag("t1")
        ),
        f
    );
</chain>
If you want to chooseTHENThis expression, then you can return: in the selection node.
@LiteflowComponent("b")
public class BCmp extends NodeSwitchComponent {

    @Override
    public String processSwitch() throws Exception {
        return "tag:t1";
        //The following is also possible
        return ":t1";
    }
}

condition scheduling

Conditional scheduling is a variant of selective scheduling, where selective scheduling logically selects one of several subitems. Conditional scheduling has only two subitems, true and false, which is very useful in dealing with certain business processes. In fact, to put it simply, conditional scheduling is the programming language ofif else. Only inLiteFlow ELThere are some different uses in the grammar. The followingIFandELIFThe first argument of the first parameter requires the definition of a conditional component. Binary expression for IF: included among thesexis the conditional node, and in the case of true, the execution link is thex->a->bIf the link is a false link, it isx->b
<chain name="chain1">
    THEN(
        IF(x, a),
        b
    );
</chain>
SpringBoot - LiteFlow Engine Framework
@Component("x")
public class XCmp extends NodeIfComponent {
	@Override
	public boolean processIf() throws Exception {
	    //do your biz
		return true;
	}
}
Ternary expression for IF: included among thesexis the conditional node, and in the case of true, the execution link is thex->a->cIf the link is a false link, it isx->b->c
<chain name="chain1">
    THEN(
        IF(x, a, b),
        c
    );
</chain>
SpringBoot - LiteFlow Engine Framework ELIF expression: ELIFKeyword usage is actually similar tojavalinguisticelse ifSimilarly, it can be followed by more than one, andIFAs with binary expression arguments, they usually end with aELSE, which is used for multi-conditional judgment:
<chain name="chain1">
    IF(x1, a).ELIF(x2, b).ELIF(x3, c).ELIF(x4, d).ELSE(THEN(m, n));
</chain>
SpringBoot - LiteFlow Engine Framework

circular programming

FOR loop: FORLoop expressions are used for a fixed number of loops and are typically used as:
<chain name="chain1">
    FOR(5).DO(THEN(a, b));
</chain>
The above expression means to puta->bThis link is a fixed loop.5times. If you’re not sure how many times you want to loop when you define the rule, and you won’t know until the code runs. Then you can also define it like this:
<chain name="chain1">
    FOR(f).DO(THEN(a, b));
</chain>
included among thesefThis node needs to be for the times loop component, which returns aintnumber of cycles.fThe definition of a node that needs to inherit theNodeForComponentThe need to realizeprocessForMethods:
@LiteflowComponent("f")
public class FCmp extends NodeForComponent {
    @Override
    public int processFor() throws Exception {
        //Here the result of the for is returned according to the business.
    }
}
Loop subscript fetch: keywordFOR...DO...In theDOAny of thesejavacomponents can all be accessed via thethis.getLoopIndex()to get the subscript. The subscript is obtained in the script via the_meta.loopIndexto get.
WHILE loop:
<chain name="chain1">
    WHILE(w).DO(THEN(a, b));
</chain>
included among thesewThis node needs to be a conditional loop component that returns a boolean value for thetruethen the loop continues
@LiteflowComponent("w")
public class WCmp extends NodeWhileComponent {
    @Override
    public boolean processWhile() throws Exception {
        // Here the while result is returned according to the business.
    }
}
Loop subscript fetch: keywordWHILE...DO...In theDOAny node inside can be passedthis.getLoopIndex()to get the subscript. The subscript is obtained in the script via the_meta.loopIndexto get.

ITERATOR iterative loop

<chain name="chain1">
    ITERATOR(x).DO(THEN(a, b));
</chain>
included among thesexThis node needs to be for an iteration loop component that returns an iterator:xThe definition of a node that needs to inherit theNodeIteratorComponentThe need to realizeprocessIteratorMethods:
@LiteflowComponent("x")
public class XCmp extends NodeIteratorComponent {
    @Override
    public Iterator<?> processIterator() throws Exception {
        List<String> list = ListUtil.toList("jack", "mary", "tom");
        return list.iterator();
    }
}

BREAK

LiteFlowThe same goes forBREAKsyntax, which represents an exit from the loop.BREAKThe keywords can be followed in theFORandWHILELater, it is usually used as:
<chain name="chain1">
    FOR(f).DO(THEN(a, b)).BREAK(c);
</chain>

<chain name="chain1">
    WHILE(w).DO(THEN(a, b)).BREAK(c);
</chain>
included among thesecThis node needs to return a boolean value for the exit loop component, for thetruethen the loop is exited.cThe definition of a node that needs to inherit theNodeBreakComponentThe need to realizeprocessBreakMethods:
@LiteflowComponent("c")
public class CCmp extends NodeBreakComponent {
    @Override
    public boolean processBreak() throws Exception {
        //Here the result of the break is returned according to the business.
    }
}
BREAKThe keyword is judged at the end of each loop.