Sfoglia il codice sorgente

1. chain、script分离方式支持Apollo动态配置

zhanghua 2 anni fa
parent
commit
7e2e0c337c

+ 0 - 4
liteflow-rule-plugin/liteflow-rule-apollo/pom.xml

@@ -26,10 +26,6 @@
             <scope>provided</scope>
         </dependency>
 
-        <dependency>
-            <groupId>com.alibaba.nacos</groupId>
-            <artifactId>nacos-client</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>

+ 13 - 10
liteflow-rule-plugin/liteflow-rule-apollo/src/main/java/com/yomahub/liteflow/parser/apollo/ApolloXmlELParser.java

@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.bean.copier.CopyOptions;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.core.FlowInitHook;
 import com.yomahub.liteflow.parser.apollo.exception.ApolloException;
 import com.yomahub.liteflow.parser.apollo.util.ApolloParseHelper;
 import com.yomahub.liteflow.parser.apollo.vo.ApolloParserConfigVO;
@@ -13,7 +14,6 @@ import com.yomahub.liteflow.property.LiteflowConfigGetter;
 import com.yomahub.liteflow.util.JsonUtil;
 
 import java.util.Objects;
-import java.util.function.Consumer;
 
 /**
  * @Description:
@@ -33,29 +33,32 @@ public class ApolloXmlELParser extends ClassXmlFlowELParser {
 			} else if (StrUtil.isNotBlank(liteflowConfig.getRuleSourceExtData())) {
 				apolloParserConfigVO = JsonUtil.parseObject(liteflowConfig.getRuleSourceExtData(), ApolloParserConfigVO.class);
 			}
+
+			// check config
 			if (Objects.isNull(apolloParserConfigVO)) {
 				throw new ApolloException("ruleSourceExtData or map is empty");
 			}
 
+			if (StrUtil.isBlank(apolloParserConfigVO.getChainNamespace())) {
+				throw new ApolloException("chainNamespace is empty, you must configure the chainNamespace property");
+			}
+
 			apolloParseHelper = new ApolloParseHelper(apolloParserConfigVO);
 		} catch (Exception e) {
 			throw new ApolloException(e.getMessage());
 		}
 	}
 
+
 	@Override
 	public String parseCustom() {
-		Consumer<String> parseConsumer = t -> {
-			try {
-				parse(t);
-			} catch (Exception e) {
-				throw new ApolloException(e.getMessage());
-			}
-		};
+
 		try {
 			String content = apolloParseHelper.getContent();
-			apolloParseHelper.checkContent(content);
-			apolloParseHelper.listen(parseConsumer);
+			FlowInitHook.addHook(() -> {
+				apolloParseHelper.listenApollo();
+				return true;
+			});
 			return content;
 
 		} catch (Exception e) {

+ 180 - 28
liteflow-rule-plugin/liteflow-rule-apollo/src/main/java/com/yomahub/liteflow/parser/apollo/util/ApolloParseHelper.java

@@ -1,17 +1,26 @@
 package com.yomahub.liteflow.parser.apollo.util;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
-import com.ctrip.framework.apollo.ConfigFile;
+import com.ctrip.framework.apollo.Config;
 import com.ctrip.framework.apollo.ConfigService;
-import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
-import com.yomahub.liteflow.exception.ParseException;
+import com.ctrip.framework.apollo.enums.PropertyChangeType;
+import com.ctrip.framework.apollo.model.ConfigChange;
+import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
+import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
+import com.yomahub.liteflow.enums.NodeTypeEnum;
+import com.yomahub.liteflow.flow.FlowBus;
 import com.yomahub.liteflow.parser.apollo.exception.ApolloException;
 import com.yomahub.liteflow.parser.apollo.vo.ApolloParserConfigVO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.List;
 import java.util.Objects;
-import java.util.function.Consumer;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @Description:
@@ -23,54 +32,197 @@ public class ApolloParseHelper {
 
 	private static final Logger LOG = LoggerFactory.getLogger(ApolloParseHelper.class);
 
+	private final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
+
+	private final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
+
+	private final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\"><![CDATA[{}]]></node>";
+
+	private final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
+
 	private final ApolloParserConfigVO apolloParserConfigVO;
 
-	private ConfigFile liteflowConfigFile;
+	private Config chainConfig;
+
+	private Config scriptConfig;
+
 
 	public ApolloParseHelper(ApolloParserConfigVO apolloParserConfigVO) {
 		this.apolloParserConfigVO = apolloParserConfigVO;
 		try {
-			liteflowConfigFile = ConfigService.getConfigFile(apolloParserConfigVO.getNamespace(), ConfigFileFormat.XML);
+			chainConfig = ConfigService.getConfig(apolloParserConfigVO.getChainNamespace());
+			String scriptNamespace;
+			// scriptConfig is optional
+			if (StrUtil.isNotBlank(scriptNamespace = apolloParserConfigVO.getScriptNamespace())) {
+				scriptConfig = ConfigService.getConfig(scriptNamespace);
+			}
 		} catch (Exception e) {
-			LOG.error("[ApolloParseHelper] liteflowConfigFile get init error, apolloParserConfigVO:{}", apolloParserConfigVO);
 			throw new ApolloException(e.getMessage());
 		}
 	}
 
 	public String getContent() {
+
 		try {
-			ConfigFile configFile = ConfigService.getConfigFile(apolloParserConfigVO.getNamespace(), ConfigFileFormat.XML);
-			String content;
-			if (Objects.isNull(configFile) || StrUtil.isBlank(content = configFile.getContent())) {
-				throw new ApolloException(String.format("not find config file, namespace:%s", apolloParserConfigVO.getNamespace()));
+			// 1. handle chain
+			Set<String> propertyNames = chainConfig.getPropertyNames();
+			if (CollectionUtil.isEmpty(propertyNames)) {
+				throw new ApolloException(StrUtil.format("There are no chains in namespace : {}", apolloParserConfigVO.getChainNamespace()));
 			}
-			return content;
+			List<String> chainItemContentList = propertyNames.stream()
+					.map(item -> StrUtil.format(CHAIN_XML_PATTERN, item, chainConfig.getProperty(item, StrUtil.EMPTY)))
+					.collect(Collectors.toList());
+			// merge all chain content
+			String chainAllContent = CollUtil.join(chainItemContentList, StrUtil.EMPTY);
+
+			// 2. handle script if needed
+			String scriptAllContent = StrUtil.EMPTY;
+			Set<String> scriptNamespaces;
+			if (Objects.nonNull(scriptConfig) && CollectionUtil.isNotEmpty(scriptNamespaces = scriptConfig.getPropertyNames())) {
+
+				List<String> scriptItemContentList = scriptNamespaces.stream()
+						.map(item -> convert(item, scriptConfig.getProperty(item, StrUtil.EMPTY)))
+						.filter(Objects::nonNull)
+						.map(item -> StrUtil.format(NODE_ITEM_XML_PATTERN, item.getNodeId(), item.getName(), item.getType(), item.getScript()))
+						.collect(Collectors.toList());
+
+				scriptAllContent = StrUtil.format(NODE_XML_PATTERN, CollUtil.join(scriptItemContentList, StrUtil.EMPTY));
+			}
+
+			return StrUtil.format(XML_PATTERN, scriptAllContent, chainAllContent);
 		} catch (Exception e) {
 			throw new ApolloException(e.getMessage());
 		}
 	}
 
+
 	/**
-	 * 检查 content 是否合法
+	 * listen apollo config change
 	 */
-	public void checkContent(String content) {
-		if (StrUtil.isBlank(content)) {
-			String error = StrUtil.format("the node[{}] value is empty", apolloParserConfigVO.toString());
-			throw new ParseException(error);
+	public void listenApollo() {
+
+		// chain
+		chainConfig.addChangeListener(changeEvent ->
+				changeEvent.changedKeys().forEach(changeKey -> {
+					ConfigChange configChange = changeEvent.getChange(changeKey);
+					String newValue = configChange.getNewValue();
+					PropertyChangeType changeType = configChange.getChangeType();
+					switch (changeType) {
+						case ADDED:
+						case MODIFIED:
+							LOG.info("starting reload flow config... {} key={} value={},", changeType.name(), changeKey, newValue);
+							LiteFlowChainELBuilder.createChain()
+									.setChainId(changeKey)
+									.setEL(newValue)
+									.build();
+							break;
+						case DELETED:
+							LOG.info("starting reload flow config... delete key={}", changeKey);
+							FlowBus.removeChain(changeKey);
+
+					}
+				}));
+
+		// script
+		if (Objects.isNull(scriptConfig)) {
+			// no script config
+			return;
 		}
+		scriptConfig.addChangeListener(changeEvent ->
+				changeEvent.changedKeys().forEach(changeKey -> {
+					ConfigChange configChange = changeEvent.getChange(changeKey);
+					String newValue = configChange.getNewValue();
+
+					PropertyChangeType changeType = configChange.getChangeType();
+
+					NodeSimpleVO nodeSimpleVO;
+					switch (changeType) {
+						case ADDED:
+						case MODIFIED:
+							LOG.info("starting reload flow config... {} key={} value={},", changeType.name(), changeKey, newValue);
+							nodeSimpleVO = convert(changeKey, newValue);
+							LiteFlowNodeBuilder.createScriptNode()
+									.setId(nodeSimpleVO.getNodeId())
+									.setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType()))
+									.setName(nodeSimpleVO.getName())
+									.setScript(nodeSimpleVO.getScript())
+									.build();
+							break;
+						case DELETED:
+							LOG.info("starting reload flow config... delete key={}", changeKey);
+							nodeSimpleVO = convert(changeKey, null);
+							FlowBus.getNodeMap().remove(nodeSimpleVO.getNodeId());
+					}
+				}));
+
 	}
 
-	/**
-	 * 监听 apollo 数据变化
-	 */
-	public void listen(Consumer<String> parseConsumer) {
-		try {
-			liteflowConfigFile.addChangeListener(configFileChangeEvent -> {
-				String newContext = configFileChangeEvent.getNewValue();
-				parseConsumer.accept(newContext);
-			});
-		} catch (Exception e) {
-			throw new ApolloException(e.getMessage());
+
+	private NodeSimpleVO convert(String key, String value) {
+		//不需要去理解这串正则,就是一个匹配冒号的
+		//一定得是a:b,或是a:b:c...这种完整类型的字符串的
+		List<String> matchItemList = ReUtil.findAllGroup0("(?<=[^:]:)[^:]+|[^:]+(?=:[^:])", key);
+		if (CollUtil.isEmpty(matchItemList)) {
+			return null;
+		}
+
+		NodeSimpleVO nodeSimpleVO = new NodeSimpleVO();
+		if (matchItemList.size() > 1) {
+			nodeSimpleVO.setNodeId(matchItemList.get(0));
+			nodeSimpleVO.setType(matchItemList.get(1));
+		}
+
+		if (matchItemList.size() > 2) {
+			nodeSimpleVO.setName(matchItemList.get(2));
+		}
+
+		// set script
+		nodeSimpleVO.setScript(value);
+
+		return nodeSimpleVO;
+	}
+
+
+	private static class NodeSimpleVO {
+
+		private String nodeId;
+
+		private String type;
+
+		private String name = StrUtil.EMPTY;
+
+		private String script;
+
+		public String getNodeId() {
+			return nodeId;
+		}
+
+		public void setNodeId(String nodeId) {
+			this.nodeId = nodeId;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public void setType(String type) {
+			this.type = type;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		public String getScript() {
+			return script;
+		}
+
+		public void setScript(String script) {
+			this.script = script;
 		}
 	}
 

+ 20 - 8
liteflow-rule-plugin/liteflow-rule-apollo/src/main/java/com/yomahub/liteflow/parser/apollo/vo/ApolloParserConfigVO.java

@@ -7,28 +7,40 @@ package com.yomahub.liteflow.parser.apollo.vo;
  */
 public class ApolloParserConfigVO {
 
-	private String namespace;
+	private String chainNamespace;
+
+	private String scriptNamespace;
 
 
 	public ApolloParserConfigVO() {
 	}
 
-	public ApolloParserConfigVO(String namespace) {
-		this.namespace = namespace;
+	public ApolloParserConfigVO(String chainNamespace, String scriptNamespace) {
+		this.chainNamespace = chainNamespace;
+		this.scriptNamespace = scriptNamespace;
+	}
+
+	public String getChainNamespace() {
+		return chainNamespace;
+	}
+
+	public void setChainNamespace(String chainNamespace) {
+		this.chainNamespace = chainNamespace;
 	}
 
-	public String getNamespace() {
-		return namespace;
+	public String getScriptNamespace() {
+		return scriptNamespace;
 	}
 
-	public void setNamespace(String namespace) {
-		this.namespace = namespace;
+	public void setScriptNamespace(String scriptNamespace) {
+		this.scriptNamespace = scriptNamespace;
 	}
 
 	@Override
 	public String toString() {
 		return "ApolloParserConfigVO{" +
-				"namespace='" + namespace + '\'' +
+				"chainNamespace='" + chainNamespace + '\'' +
+				", scriptNamespace='" + scriptNamespace + '\'' +
 				'}';
 	}
 }

+ 0 - 2
pom.xml

@@ -377,8 +377,6 @@
 		<module>liteflow-spring-boot-starter</module>
 		<module>liteflow-spring</module>
 		<module>liteflow-testcase-el</module>
-        <module>liteflow-rule-apollo</module>
-		<module>liteflow-testcase-el-apollo-springboot</module>
 	</modules>
 
 	<distributionManagement>