diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml index 42941d4db6..d987afb2bf 100644 --- a/dubbo-cluster/pom.xml +++ b/dubbo-cluster/pom.xml @@ -34,5 +34,10 @@ dubbo-rpc-api ${project.parent.version} + + org.apache.dubbo + dubbo-config-dynamic + ${project.parent.version} + \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java index 47aa2515a3..43410b79ae 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java @@ -22,6 +22,7 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; import java.util.List; +import java.util.Map; /** * Router. (SPI, Prototype, ThreadSafe) @@ -32,7 +33,6 @@ import java.util.List; * @see org.apache.dubbo.rpc.cluster.Directory#list(Invocation) */ public interface Router extends Comparable { - /** * get the router url. * @@ -51,4 +51,20 @@ public interface Router extends Comparable { */ List> route(List> invokers, URL url, Invocation invocation) throws RpcException; + default Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException { + return null; + } + + default boolean isRuntime() { + return true; + } + + default String getKey() { + return ""; + } + + default boolean isForce() { + return false; + } + } \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java new file mode 100644 index 0000000000..dda01954e8 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.config.dynamic.DynamicConfiguration; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcInvocation; +import org.apache.dubbo.rpc.cluster.router.InvokerTreeCache; +import org.apache.dubbo.rpc.cluster.router.TreeNode; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * + */ +public class RouterChain { + + List> fullInvokers; + + private InvokerTreeCache treeCache; + + List routers; + + public static RouterChain buildChain(DynamicConfiguration dynamicConfiguration) { + List extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class).getActivateExtension(dynamicConfiguration.getUrl(), (String[]) null); + List routers = extensionFactories.stream().map(factory -> factory.getRouter(dynamicConfiguration)).collect(Collectors.toList()); + return new RouterChain<>(routers); + } + + public RouterChain(List routers) { + this.routers = routers; + } + + + public void addRouter(Router router) { + this.routers.add(router); + } + + public void sort() { + + } + + /** + * @param methodInvokers + * @param url + * @param invocation TODO has no been used yet + */ + public void preRoute(Map>> methodInvokers, URL url, Invocation invocation) { + if (CollectionUtils.isEmpty(routers)) { + return; + } + TreeNode root = treeCache.buildTree(); + Router router = routers.get(0); + methodInvokers.forEach((method, invokers) -> { + TreeNode node = new TreeNode<>("method", method, invokers, true); + root.addChild(node); + Invocation invocation1 = new RpcInvocation(method, new Class[0], new Object[0]); + routeeee(router, 1, root, router.preRoute(invokers, url, invocation1), url, invocation1); + }); + } + + private void routeeee(Router router, int i, TreeNode parentNode, Map>> invokers, URL url, Invocation invocation) { + invokers.forEach((routerValue, list) -> { + TreeNode node = new TreeNode<>(router.getKey(), routerValue, list, router.isForce()); + parentNode.addChild(node); + Router nextRouter = routers.get(i); + if (CollectionUtils.isNotEmpty(list)) { + routeeee(nextRouter, i + 1, node, nextRouter.preRoute(list, url, invocation), url, invocation); + } + }); + } + + public List> route(List> invokers, URL url, Invocation invocation) { + // TODO will calculate every time + List> finalInvokers = treeCache.getInvokers(treeCache.getTree(), url, invocation); + for (Router router : routers) { + if (router.isRuntime()) { + finalInvokers = router.route(finalInvokers, url, invocation); + } + } + return finalInvokers; + } + + public void notifyFullInvokers(Map>> invokers, URL url) { + preRoute(invokers, url, null); + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java index 679b9fe589..287ec7153a 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java @@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.cluster; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.config.dynamic.DynamicConfiguration; import org.apache.dubbo.rpc.Invocation; /** @@ -41,4 +42,7 @@ public interface RouterFactory { @Adaptive("protocol") Router getRouter(URL url); + default Router getRouter(DynamicConfiguration dynamicConfiguration) { + return null; + } } \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java index 085094df22..9bbdcf24cd 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java @@ -16,9 +16,7 @@ */ package org.apache.dubbo.rpc.cluster.directory; -import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.rpc.Invocation; @@ -26,11 +24,9 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Router; -import org.apache.dubbo.rpc.cluster.RouterFactory; -import org.apache.dubbo.rpc.cluster.router.MockInvokersSelector; +import org.apache.dubbo.rpc.cluster.RouterChain; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -48,22 +44,22 @@ public abstract class AbstractDirectory implements Directory { private volatile URL consumerUrl; - private volatile List routers; + protected RouterChain routerChain; public AbstractDirectory(URL url) { this(url, null); } - public AbstractDirectory(URL url, List routers) { - this(url, url, routers); + public AbstractDirectory(URL url, RouterChain routerChain) { + this(url, url, routerChain); } - public AbstractDirectory(URL url, URL consumerUrl, List routers) { + public AbstractDirectory(URL url, URL consumerUrl, RouterChain routerChain) { if (url == null) throw new IllegalArgumentException("url == null"); this.url = url; this.consumerUrl = consumerUrl; - setRouters(routers); + setRouterChain(routerChain); } @Override @@ -71,19 +67,16 @@ public abstract class AbstractDirectory implements Directory { if (destroyed) { throw new RpcException("Directory already destroyed .url: " + getUrl()); } + List> invokers = doList(invocation); - List localRouters = this.routers; // local reference - if (localRouters != null && !localRouters.isEmpty()) { - for (Router router : localRouters) { - try { - if (router.getUrl() == null || router.getUrl().getParameter(Constants.RUNTIME_KEY, false)) { - invokers = router.route(invokers, getConsumerUrl(), invocation); - } - } catch (Throwable t) { - logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t); - } - } + + try { + // runtime routers will be executed. + routerChain.route(invokers, getConsumerUrl(), invocation); + } catch (Throwable t) { + logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t); } + return invokers; } @@ -92,23 +85,24 @@ public abstract class AbstractDirectory implements Directory { return url; } - public List getRouters() { - return routers; + public RouterChain getRouterChain() { + return routerChain; } - protected void setRouters(List routers) { + public void setRouterChain(RouterChain routerChain) { + this.routerChain = routerChain; + } + + protected void addRouters(List routers) { // copy list - routers = routers == null ? new ArrayList() : new ArrayList(routers); - // append url router - String routerkey = url.getParameter(Constants.ROUTER_KEY); - if (routerkey != null && routerkey.length() > 0) { - RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(routerkey); - routers.add(routerFactory.getRouter(url)); - } - // append mock invoker selector - routers.add(new MockInvokersSelector()); - Collections.sort(routers); - this.routers = routers; + routers = routers == null ? new ArrayList<>() : new ArrayList<>(routers); + routers.forEach(this::addRouter); + } + + protected void addRouter(Router router) { + routerChain.addRouter(router); + // FIXME append mock invoker selector +// routerChain.add(new MockInvokersSelector()); } public URL getConsumerUrl() { diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java index 47a0d12bc7..9367bdf75f 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java @@ -20,13 +20,15 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.cluster.Router; +import org.apache.dubbo.rpc.cluster.RouterChain; import java.util.List; /** * StaticDirectory * + * FIXME We should add separate router rules for StaticDirectory, not use RouterChain in AbstractDirectory. For example, machineRoom rule only. Ask LVS team for help. + * */ public class StaticDirectory extends AbstractDirectory { @@ -36,16 +38,16 @@ public class StaticDirectory extends AbstractDirectory { this(null, invokers, null); } - public StaticDirectory(List> invokers, List routers) { - this(null, invokers, routers); + public StaticDirectory(List> invokers, RouterChain routerChain) { + this(null, invokers, routerChain); } public StaticDirectory(URL url, List> invokers) { this(url, invokers, null); } - public StaticDirectory(URL url, List> invokers, List routers) { - super(url == null && invokers != null && !invokers.isEmpty() ? invokers.get(0).getUrl() : url, routers); + public StaticDirectory(URL url, List> invokers, RouterChain routerChain) { + super(url == null && invokers != null && !invokers.isEmpty() ? invokers.get(0).getUrl() : url, routerChain); if (invokers == null || invokers.isEmpty()) throw new IllegalArgumentException("invokers == null"); this.invokers = invokers; diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/InvokerTreeCache.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/InvokerTreeCache.java new file mode 100644 index 0000000000..784dca94b0 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/InvokerTreeCache.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; + +import java.util.Collections; +import java.util.List; + +/** + * + */ +public class InvokerTreeCache { + + TreeNode tree; + + public TreeNode buildTree() { + tree = new TreeNode<>(); + return tree; + } + + public List> getInvokers(TreeNode node, URL url, Invocation invocation) { + if (node.getChildren() == null) { + return node.getInvokers(); + } + + if (tree.getChildren().size() == 1) { + return getInvokers(tree.getChildren().get(0), url, invocation); + } + + TreeNode failoverNode = null; + for (TreeNode n : tree.getChildren()) { + String key = n.getConditionKey(); + if (TreeNode.FAILOVER_KEY.equals(key)) { + failoverNode = n; + continue; + } + if (n.getConditionValue().equals(invocation.getAttachment(key, url.getParameter(key)))) { + if (n.getInvokers() != null || (n.getInvokers() == null && n.isForce())) + return getInvokers(n, url, invocation); + } + } + + if (failoverNode != null) { + return getInvokers(failoverNode, url, invocation); + } + return Collections.emptyList(); + } + + + public TreeNode getTree() { + return tree; + } + +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java index 0ca2a4997d..f775f899b2 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java @@ -18,13 +18,16 @@ package org.apache.dubbo.rpc.cluster.router; import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.cluster.Router; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * A specific Router designed to realize mock feature. @@ -49,6 +52,36 @@ public class MockInvokersSelector implements Router { return invokers; } + @Override + public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException { + Map>> map = new HashMap<>(); + + if (CollectionUtils.isEmpty(invokers)) { + return map; + } + + if (isRuntime()) { + map.put(TreeNode.FAILOVER_KEY, invokers); + return map; + } + return map; + } + + @Override + public boolean isRuntime() { + return true; + } + + @Override + public String getKey() { + return TreeNode.FAILOVER_KEY; + } + + @Override + public boolean isForce() { + return false; + } + private List> getMockedInvokers(final List> invokers) { if (!hasMockProviders(invokers)) { return null; diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/TreeNode.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/TreeNode.java new file mode 100644 index 0000000000..813a0c29f9 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/TreeNode.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router; + +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.rpc.Invoker; + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class TreeNode { + public static final String FAILOVER_KEY = "failover"; + + private String conditionKey; + private String conditionValue; + private boolean force; + private List> invokers; + private List> children; + + public TreeNode() { + this.children = new ArrayList<>(); + } + + public TreeNode(String conditionKey, String conditionValue, List> invokers, boolean force) { + this.conditionKey = conditionKey; + this.conditionValue = conditionValue; + this.invokers = invokers; + this.force = force; + this.children = new ArrayList<>(); + } + + public void traverse() { + + } + + public void addChild(TreeNode child) { + children.add(child); + } + + public boolean isLeaf() { + if (CollectionUtils.isEmpty(children)) { + return true; + } + return false; + } + + public String getConditionKey() { + return conditionKey; + } + + public void setConditionKey(String conditionKey) { + this.conditionKey = conditionKey; + } + + public String getConditionValue() { + return conditionValue; + } + + public void setConditionValue(String conditionValue) { + this.conditionValue = conditionValue; + } + + public List> getInvokers() { + return invokers; + } + + public void setInvokers(List> invokers) { + this.invokers = invokers; + } + + public List> getChildren() { + return children; + } + + public void setChildren(List> children) { + this.children = children; + } + + public boolean isForce() { + return force; + } + + public void setForce(boolean force) { + this.force = force; + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java index af36757028..a2de676a1f 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; @@ -27,6 +28,7 @@ import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.cluster.Router; +import org.apache.dubbo.rpc.cluster.router.TreeNode; import java.text.ParseException; import java.util.ArrayList; @@ -45,19 +47,26 @@ import java.util.regex.Pattern; public class ConditionRouter implements Router, Comparable { private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class); - private static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)"); - private final URL url; - private final int priority; - private final boolean force; - private final Map whenCondition; - private final Map thenCondition; + protected static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)"); + protected URL url; + protected int priority; + protected boolean force; + protected Map whenCondition; + protected Map thenCondition; + + protected ConditionRouter() { + + } public ConditionRouter(URL url) { this.url = url; this.priority = url.getParameter(Constants.PRIORITY_KEY, 0); this.force = url.getParameter(Constants.FORCE_KEY, false); + init(url.getParameterAndDecoded(Constants.RULE_KEY)); + } + + protected void init(String rule) { try { - String rule = url.getParameterAndDecoded(Constants.RULE_KEY); if (rule == null || rule.trim().length() == 0) { throw new IllegalArgumentException("Illegal route rule!"); } @@ -174,6 +183,37 @@ public class ConditionRouter implements Router, Comparable { return invokers; } + @Override + public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException { + Map>> map = new HashMap<>(); + + if (CollectionUtils.isEmpty(invokers)) { + return map; + } + + if (isRuntime()) { + map.put(TreeNode.FAILOVER_KEY, invokers); + return map; + } + return map; + } + + @Override + public boolean isRuntime() { + // We always return true for previously defined Router, don't support cache. + return this.url.getParameter(Constants.RUNTIME_KEY, false); + } + + @Override + public String getKey() { + return TreeNode.FAILOVER_KEY; + } + + @Override + public boolean isForce() { + return force; + } + @Override public URL getUrl() { return url; @@ -229,7 +269,7 @@ public class ConditionRouter implements Router, Comparable { return result; } - private static final class MatchPair { + protected static final class MatchPair { final Set matches = new HashSet(); final Set mismatches = new HashSet(); diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRouterRule.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRouterRule.java new file mode 100644 index 0000000000..886468f92e --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRouterRule.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router.condition.config; + +/** + * + */ +public class ConditionRouterRule { + private String ruleBody; + private boolean runtime; + private boolean force; + + public String getRuleBody() { + return ruleBody; + } + + public void setRuleBody(String ruleBody) { + this.ruleBody = ruleBody; + } + + public boolean isRuntime() { + return runtime; + } + + public void setRuntime(boolean runtime) { + this.runtime = runtime; + } + + public boolean isForce() { + return force; + } + + public void setForce(boolean force) { + this.force = force; + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRuleParser.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRuleParser.java new file mode 100644 index 0000000000..db90cc7152 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRuleParser.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router.condition.config; + +/** + * + */ +public class ConditionRuleParser { + + public static ConditionRouterRule parse(String rawRule) { + ConditionRouterRule conditionRouterRule = new ConditionRouterRule(); + conditionRouterRule.setRuleBody("host!=10.20.153.10,10.20.153.11=>"); + return conditionRouterRule; + } + +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java new file mode 100644 index 0000000000..846e560698 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router.condition.config; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.config.dynamic.ConfigChangeEvent; +import org.apache.dubbo.config.dynamic.ConfigurationListener; +import org.apache.dubbo.config.dynamic.DynamicConfiguration; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.cluster.router.TreeNode; +import org.apache.dubbo.rpc.cluster.router.condition.ConditionRouter; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class ConfigConditionRouter extends ConditionRouter implements ConfigurationListener { + private static final Logger logger = LoggerFactory.getLogger(ConfigConditionRouter.class); + private DynamicConfiguration configuration; + private ConditionRouterRule routerRule; + + public ConfigConditionRouter(URL url) { + super(url); + } + + public ConfigConditionRouter(DynamicConfiguration configuration) { + this.configuration = configuration; + this.priority = -2; + this.force = false; + try { + String app = configuration.getUrl().getParameter(Constants.APPLICATION_KEY); + String rawRule = configuration.getConfig(app + Constants.ROUTERS_SUFFIX, "dubbo", this); + ConditionRouterRule routerRule = ConditionRuleParser.parse(rawRule); + init(routerRule.getRuleBody()); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + @Override + public void process(ConfigChangeEvent event) { + String rawRule = event.getNewValue(); + ConditionRouterRule routerRule = ConditionRuleParser.parse(rawRule); + init(routerRule.getRuleBody()); + } + + @Override + public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException { + Map>> map = new HashMap<>(); + + if (CollectionUtils.isEmpty(invokers)) { + return map; + } + + if (isRuntime()) { + map.put(TreeNode.FAILOVER_KEY, invokers); + return map; + } + + map.put(TreeNode.FAILOVER_KEY, route(invokers, url, invocation)); + + return map; + } + + @Override + public boolean isRuntime() { + return routerRule.isRuntime(); + } + + @Override + public String getKey() { + return ""; + } + + @Override + public boolean isForce() { + return routerRule.isForce(); + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouterFactory.java new file mode 100644 index 0000000000..396b10b242 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouterFactory.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router.condition.config; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.dynamic.DynamicConfiguration; +import org.apache.dubbo.rpc.cluster.Router; +import org.apache.dubbo.rpc.cluster.RouterFactory; + +/** + * + */ +@Activate +public class ConfigConditionRouterFactory implements RouterFactory { + @Override + public Router getRouter(URL url) { + return null; + } + + @Override + public Router getRouter(DynamicConfiguration dynamicConfiguration) { + return new ConfigConditionRouter(dynamicConfiguration); + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouter.java new file mode 100644 index 0000000000..8508f176dc --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouter.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router.group; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.dynamic.ConfigChangeEvent; +import org.apache.dubbo.config.dynamic.ConfigurationListener; +import org.apache.dubbo.config.dynamic.DynamicConfiguration; +import org.apache.dubbo.config.dynamic.DynamicConfigurationFactory; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.cluster.Router; +import org.apache.dubbo.rpc.cluster.router.TreeNode; +import org.apache.dubbo.rpc.cluster.router.group.model.GroupRouterRule; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * + */ +public class GroupRouter implements Router, Comparable, ConfigurationListener { + private static final Logger logger = LoggerFactory.getLogger(GroupRouter.class); + private static final String GROUPRULE_DATAID = "global.routers"; + private static final String ROUTE_GROUP = "route.group"; + private static final String ROUTE_FAILOVER = "route.failover"; + private int priority; + private URL url; + private DynamicConfiguration configuration; + private GroupRouterRule groupRouterRule; + + public GroupRouter(URL url) { + this(ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class).getAdaptiveExtension().getDynamicConfiguration(url)); + this.url = url; + } + + public GroupRouter(DynamicConfiguration configuration) { + this.priority = -1; + this.configuration = configuration; + init(); + } + + public void init() { + String rawRule = configuration.getConfig(GROUPRULE_DATAID, "dubbo", this); + this.groupRouterRule = GroupRuleParser.parse(rawRule); + } + + @Override + public void process(ConfigChangeEvent event) { + String rawRule = event.getNewValue(); + // remove, set groupRouterRule to null + // change, update groupRouterRule + } + + @Override + public URL getUrl() { + return url; + } + + @Override + public List> route(List> invokers, URL url, Invocation invocation) throws RpcException { + if (CollectionUtils.isEmpty(invokers)) { + return invokers; + } + List> result = invokers; + String routeGroup = StringUtils.isEmpty(invocation.getAttachment(ROUTE_GROUP)) ? url.getParameter(ROUTE_GROUP) : invocation.getAttachment(ROUTE_GROUP); + if (StringUtils.isNotEmpty(routeGroup)) { + String providerApp = invokers.get(0).getUrl().getParameter(Constants.APPLICATION_KEY); + List ips = groupRouterRule.filter(routeGroup, providerApp); + if (CollectionUtils.isNotEmpty(ips)) { + result = filterInvoker(invokers, invoker -> ipMatches(invoker.getUrl(), ips)); + } else { + result = filterInvoker(invokers, invoker -> invoker.getUrl().getParameter(ROUTE_GROUP).equals(routeGroup)); + } + } + if (StringUtils.isEmpty(routeGroup) || (CollectionUtils.isEmpty(result) && url.getParameter(ROUTE_FAILOVER, true))) { + result = filterInvoker(invokers, invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(ROUTE_GROUP))); + } + return result; + } + + @Override + public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException { + Map>> map = new HashMap<>(); + + if (CollectionUtils.isEmpty(invokers)) { + return map; + } + + if (isRuntime()) { + map.put(TreeNode.FAILOVER_KEY, invokers); + return map; + } + + // FIXME Consider groupRouterRule + invokers.forEach(invoker -> { + String routeGroup = invoker.getUrl().getParameter(ROUTE_GROUP); + List> subInvokers = map.computeIfAbsent(routeGroup, k -> new ArrayList<>()); + subInvokers.add(invoker); + }); + + return map; + } + + @Override + public boolean isRuntime() { + return false; + } + + public boolean isRuntime(Invocation invocation) { + return true; + } + + private List> filterInvoker(List> invokers, Predicate> predicate) { + return invokers.stream() + .filter(predicate) + .collect(Collectors.toList()); + } + + private boolean ipMatches(URL url, List ips) { + return ips.contains(url.getHost()); + } + + @Override + public int compareTo(Router o) { + return 0; + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouterFactory.java new file mode 100644 index 0000000000..761d02e922 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouterFactory.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router.group; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.dynamic.DynamicConfiguration; +import org.apache.dubbo.rpc.cluster.Router; +import org.apache.dubbo.rpc.cluster.RouterFactory; + +/** + * + */ +@Activate +public class GroupRouterFactory implements RouterFactory { + + public static final String NAME = "group"; + + @Override + public Router getRouter(URL url) { + return new GroupRouter(url); + } + + public Router getRouter(DynamicConfiguration dynamicConfiguration) { + return new GroupRouter(dynamicConfiguration); + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRuleParser.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRuleParser.java new file mode 100644 index 0000000000..86569565ed --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRuleParser.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.cluster.router.group; + +import org.apache.dubbo.rpc.cluster.router.group.model.GroupRouterRule; + +/** + * + */ +public class GroupRuleParser { + + public static GroupRouterRule parse(String rawRule) { + return null; + } +} diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/RouterRule.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/model/GroupRouterRule.java similarity index 80% rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/RouterRule.java rename to dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/model/GroupRouterRule.java index 20621fa9d1..687a3fb945 100644 --- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/RouterRule.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/model/GroupRouterRule.java @@ -14,11 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.dynamic.parser.model; +package org.apache.dubbo.rpc.cluster.router.group.model; + +import java.util.List; /** * */ -public class RouterRule { - +public class GroupRouterRule { + public List filter(String routeGroup, String app) { + return null; + } } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java index 616432254a..c3f98155f3 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java @@ -20,11 +20,13 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.cluster.Router; +import org.apache.dubbo.rpc.cluster.router.TreeNode; import javax.script.Bindings; import javax.script.Compilable; @@ -34,6 +36,7 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -114,6 +117,37 @@ public class ScriptRouter implements Router { } } + @Override + public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException { + Map>> map = new HashMap<>(); + + if (CollectionUtils.isEmpty(invokers)) { + return map; + } + + if (isRuntime()) { + map.put(TreeNode.FAILOVER_KEY, invokers); + return map; + } + return map; + } + + @Override + public boolean isRuntime() { + // ignore config in url + return true; + } + + @Override + public String getKey() { + return TreeNode.FAILOVER_KEY; + } + + @Override + public boolean isForce() { + return url.getParameter(Constants.FORCE_KEY, false); + } + @Override public int compareTo(Router o) { if (o == null || o.getClass() != ScriptRouter.class) { diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory index 0ada9c3be9..f8bd6990b5 100644 --- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory +++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory @@ -1,3 +1,5 @@ file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory -condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory \ No newline at end of file +condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory +configcondition=org.apache.dubbo.rpc.cluster.router.condition.config.ConfigConditionRouterFactory +group=org.apache.dubbo.rpc.cluster.router.group.GroupRouterFactory \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java index 941e80cdd1..e596c74b05 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java @@ -27,10 +27,10 @@ import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcResult; import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.LoadBalance; +import org.apache.dubbo.rpc.cluster.RouterChain; import org.apache.dubbo.rpc.cluster.RouterFactory; import org.apache.dubbo.rpc.cluster.directory.StaticDirectory; import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker; - import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; @@ -159,7 +159,8 @@ public class FileRouterEngineTest { } private void initDic(URL url) { - dic = new StaticDirectory(url, invokers, Arrays.asList(routerFactory.getRouter(url))); + RouterChain routerChain = new RouterChain(Arrays.asList(routerFactory.getRouter(url))); + dic = new StaticDirectory(url, invokers, routerChain); } static class MockClusterInvoker extends AbstractClusterInvoker { diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java index 7ddc123eee..8da068df94 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java @@ -29,14 +29,13 @@ import org.apache.dubbo.config.dynamic.ConfigChangeType; import org.apache.dubbo.config.dynamic.ConfigType; import org.apache.dubbo.config.dynamic.ConfigurationListener; import org.apache.dubbo.config.dynamic.DynamicConfiguration; -import org.apache.dubbo.config.dynamic.parser.ConfigParser; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.integration.parser.ConfigParser; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Protocol; import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.cluster.Cluster; import org.apache.dubbo.rpc.cluster.Configurator; import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; @@ -215,13 +214,10 @@ public class RegistryDirectory extends AbstractDirectory implements Notify List configuratorUrls = new ArrayList<>(); List dynamicConfiguratorUrls = new ArrayList<>(); List appDynamicConfiguratorUrls = new ArrayList<>(); - List dynamicRouterUrls = new ArrayList<>(); for (URL url : urls) { String protocol = url.getProtocol(); String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); - if (Constants.DYNAMIC_ROUTERS_CATEGORY.equals(category)) { - dynamicRouterUrls.add(url); - } else if (Constants.ROUTERS_CATEGORY.equals(category) + if (Constants.ROUTERS_CATEGORY.equals(category) || Constants.ROUTE_PROTOCOL.equals(protocol)) { routerUrls.add(url); } else if (Constants.DYNAMIC_CONFIGURATORS_CATEGORY.equals(category)) { @@ -252,9 +248,7 @@ public class RegistryDirectory extends AbstractDirectory implements Notify // routers if (!routerUrls.isEmpty()) { List routers = toRouters(routerUrls); - if (routers != null) { // null - do nothing - setRouters(routers); - } + addRouters(routers); } List localConfigurators = this.configurators; // local reference // merge override parameters @@ -311,6 +305,8 @@ public class RegistryDirectory extends AbstractDirectory implements Notify } this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap; this.urlInvokerMap = newUrlInvokerMap; + // Route and build cache + routerChain.notifyFullInvokers(methodInvokerMap, getConsumerUrl()); try { destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker } catch (Exception e) { @@ -511,19 +507,6 @@ public class RegistryDirectory extends AbstractDirectory implements Notify return providerUrl; } - private List> route(List> invokers, String method) { - Invocation invocation = new RpcInvocation(method, new Class[0], new Object[0]); - List routers = getRouters(); - if (routers != null) { - for (Router router : routers) { - if (router.getUrl() != null) { - invokers = router.route(invokers, getConsumerUrl(), invocation); - } - } - } - return invokers; - } - /** * Transform the invokers list into a mapping relationship with a method * @@ -556,17 +539,7 @@ public class RegistryDirectory extends AbstractDirectory implements Notify invokersList.add(invoker); } } - List> newInvokersList = route(invokersList, null); - newMethodInvokerMap.put(Constants.ANY_VALUE, newInvokersList); - if (serviceMethods != null && serviceMethods.length > 0) { - for (String method : serviceMethods) { - List> methodInvokers = newMethodInvokerMap.get(method); - if (methodInvokers == null || methodInvokers.isEmpty()) { - methodInvokers = newInvokersList; - } - newMethodInvokerMap.put(method, route(methodInvokers, method)); - } - } + newMethodInvokerMap.put(Constants.ANY_VALUE, invokersList); // sort and unmodifiable for (String method : new HashSet(newMethodInvokerMap.keySet())) { List> methodInvokers = newMethodInvokerMap.get(method); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java index 5fe7a27102..8bd469f8b1 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java @@ -31,11 +31,11 @@ import org.apache.dubbo.config.dynamic.ConfigType; import org.apache.dubbo.config.dynamic.ConfigurationListener; import org.apache.dubbo.config.dynamic.DynamicConfiguration; import org.apache.dubbo.config.dynamic.DynamicConfigurationFactory; -import org.apache.dubbo.config.dynamic.parser.ConfigParser; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.RegistryFactory; import org.apache.dubbo.registry.RegistryService; +import org.apache.dubbo.registry.integration.parser.ConfigParser; import org.apache.dubbo.registry.support.ProviderConsumerRegTable; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invoker; @@ -44,6 +44,7 @@ import org.apache.dubbo.rpc.ProxyFactory; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.cluster.Cluster; import org.apache.dubbo.rpc.cluster.Configurator; +import org.apache.dubbo.rpc.cluster.RouterChain; import org.apache.dubbo.rpc.protocol.InvokerWrapper; import java.util.ArrayList; @@ -350,6 +351,7 @@ public class RegistryProtocol implements Protocol { directory.setRegistry(registry); directory.setProtocol(protocol); directory.setDynamicConfiguration(dynamicConfiguration); + directory.setRouterChain(RouterChain.buildChain(dynamicConfiguration)); // all attributes of REFER_KEY Map parameters = new HashMap(directory.getUrl().getParameters()); URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters); diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/ConfigParser.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/ConfigParser.java similarity index 96% rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/ConfigParser.java rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/ConfigParser.java index c8d3246dab..147f45400e 100644 --- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/ConfigParser.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/ConfigParser.java @@ -14,14 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.dynamic.parser; +package org.apache.dubbo.registry.integration.parser; import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.dynamic.parser.model.ConfigItem; -import org.apache.dubbo.config.dynamic.parser.model.ConfiguratorConfig; -import org.apache.dubbo.config.dynamic.parser.model.ConfiguratorRule; +import org.apache.dubbo.registry.integration.parser.model.ConfigItem; +import org.apache.dubbo.registry.integration.parser.model.ConfiguratorConfig; +import org.apache.dubbo.registry.integration.parser.model.ConfiguratorRule; import org.yaml.snakeyaml.TypeDescription; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Constructor; diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfigItem.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfigItem.java similarity index 96% rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfigItem.java rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfigItem.java index d65fa1bfb1..71d93c965e 100644 --- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfigItem.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfigItem.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.dynamic.parser.model; +package org.apache.dubbo.registry.integration.parser.model; import java.util.List; diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorConfig.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorConfig.java similarity index 96% rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorConfig.java rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorConfig.java index 18d0ddfac4..db7aab76e1 100644 --- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorConfig.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorConfig.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.dynamic.parser.model; +package org.apache.dubbo.registry.integration.parser.model; import java.util.List; diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorRule.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorRule.java similarity index 96% rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorRule.java rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorRule.java index a1b540b786..7fbdb87e2c 100644 --- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorRule.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorRule.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.dynamic.parser.model; +package org.apache.dubbo.registry.integration.parser.model; import java.util.Map; diff --git a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ConfigParserTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ConfigParserTest.java similarity index 96% rename from dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ConfigParserTest.java rename to dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ConfigParserTest.java index 1962999da2..bb90b9d8a1 100644 --- a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ConfigParserTest.java +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ConfigParserTest.java @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config; +package org.apache.dubbo.registry; import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; -import org.apache.dubbo.config.dynamic.parser.ConfigParser; -import org.apache.dubbo.config.dynamic.parser.model.ConfigItem; -import org.apache.dubbo.config.dynamic.parser.model.ConfiguratorConfig; +import org.apache.dubbo.registry.integration.parser.ConfigParser; +import org.apache.dubbo.registry.integration.parser.model.ConfigItem; +import org.apache.dubbo.registry.integration.parser.model.ConfiguratorConfig; import org.junit.Assert; import org.junit.Test; import org.yaml.snakeyaml.TypeDescription; diff --git a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ZKTools.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java similarity index 99% rename from dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ZKTools.java rename to dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java index fa29aba80b..5042068a25 100644 --- a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ZKTools.java +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config; +package org.apache.dubbo.registry; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory;