公司dubbo服务都通过zk进行了注册,dubbo原生提供了消费者选择服务提供者的时候会进行一层路由过滤。
通过增加一条路由,限制测试服的消费者仅能选择部署在测试服的提供者,来规避测试人员测试过程中调用开发人员本地不稳定代码。
import com.eqxiu.dubboa.model.domain.Route; import com.eqxiu.dubboa.model.dto.ConditionRouteDTO; import com.eqxiu.dubboa.model.store.RoutingRule; import com.eqxiu.dubboa.util.RouteUtils; import com.eqxiu.dubboa.util.YamlParser; import org.apache.commons.lang3.StringUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.dubbo.common.URL; import org.apache.dubbo.registry.zookeeper.ZookeeperRegistry; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; import org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import static com.eqxiu.dubboa.route.Constants.DYNAMIC_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE; import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY; public class AutoRouteManager { static Logger logger = LoggerFactory.getLogger(AutoRouteManager.class); private String zkUrl = "127.0.0.1:2181"; private String service; private String appName; private CuratorFramework zkClient; private ZookeeperConfiguration configuration; private ZookeeperRegistry registry; private ZookeeperClient client; private String prefix = Constants.CONFIG_KEY; private String root; //服务路径 private String path; public CuratorFramework getZkClient() { String url = zkUrl; CuratorFrameworkFactory.Builder zkClientBuilder = CuratorFrameworkFactory.builder() .connectString(url) .retryPolicy(new ExponentialBackoffRetry(1000, 3)); zkClient = zkClientBuilder.build(); zkClient.start(); return zkClient; } public AutoRouteManager(CuratorFramework zkClient,String host,Integer port) { this.root = "/dubbo"; this.zkClient = zkClient; //初始化zk节点编辑工具类 configuration = new ZookeeperConfiguration(); configuration.init(this.zkClient); Map<String, String> parameters = new HashMap<>(2); parameters.put("interface", "org.apache.dubbo.registry.RegistryService"); parameters.put("group", "dubbo"); //初始化url,获取zk注册中心 URL url = new URL("zookeeper", host, port, "org.apache.dubbo.registry.RegistryService", parameters); ZookeeperTransporter zookeeperTransporter = new ZookeeperTransporter() { @Override public ZookeeperClient connect(URL url) { return new CuratorZookeeperClient(url); } }; registry = new ZookeeperRegistry(url, zookeeperTransporter); } /** * 针对服务名,项目名创建路由规则 * * @param service 服务名 * @param appName 项目名 * @param conditionUrl 条件路由 * @return * @author djl * @date 2020/7/3 9:51 上午 */ public void setRoute(String service ,String appName,String conditionUrl) { //入参整理 ConditionRouteDTO conditionRoute = new ConditionRouteDTO(); List<String> routeList = new ArrayList<>(); routeList.add(conditionUrl); conditionRoute.setConditions(routeList); conditionRoute.setPriority(0); conditionRoute.setEnabled(true); conditionRoute.setForce(true); conditionRoute.setRuntime(false); conditionRoute.setApplication(appName); conditionRoute.setService(service); //参数处理 String id = ConvertUtil.getIdFromDTO(conditionRoute); String path = getPath(id, Constants.CONDITION_ROUTE); String existConfig = configuration.getConfig(path); RoutingRule existRule = null; if (existConfig != null) { existRule = YamlParser.loadObject(existConfig, RoutingRule.class); } existRule = RouteUtils.insertConditionRule(existRule, conditionRoute); //register2.7 configuration.setConfig(path, YamlParser.dumpObject(existRule)); //register2.6 if (StringUtils.isNotEmpty(conditionRoute.getService())) { for (Route old : convertRouteToOldRoute(conditionRoute)) { //route://0.0.0.0/com.djl.test2?category=routers&compatible_config=true&dynamic=false&enabled=true&force=true&name=null&priority=0&router=condition&rule=+%3D%3E+host+%21%3D+172.22.3.91&runtime=false URL temp = old.toUrl().addParameter(Constants.COMPATIBLE_CONFIG, true); create(toUrlPath(temp), temp.getParameter(DYNAMIC_KEY, true)); } } } // path--->/dubbo/com.djl.test2/routers/route%3A%2F%2F0.0.0.0%2Fcom.djl.test2%3Fcategory%3Drouters%26compatible_config%3Dtrue%26dynamic%3Dfalse%26enabled%3Dtrue%26force%3Dtrue%26name%3Dnull%26priority%3D0%26router%3Dcondition%26rule%3D%2B%253D%253E%2Bhost%2B%2521%253D%2B172.22.3.91%26runtime%3Dfalse public void create(String path, boolean ephemeral) { if (!ephemeral) { if (checkExists(path)) { return; } } int i = path.lastIndexOf('/'); if (i > 0) { create(path.substring(0, i), false); } if (ephemeral) { // createEphemeral(path); } else { createPersistent(path); } } public void createPersistent(String path) { try { zkClient.create().forPath(path); } catch (KeeperException.NodeExistsException e) { } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } public boolean checkExists(String path) { try { if (zkClient.checkExists().forPath(path) != null) { return true; } } catch (Exception e) { } return false; } private String toUrlPath(URL url) { return toCategoryPath(url) + PATH_SEPARATOR + URL.encode(url.toFullString()); } private String toCategoryPath(URL url) { return toServicePath(url) + PATH_SEPARATOR + url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY); } private String toServicePath(URL url) { String name = url.getServiceInterface(); if (ANY_VALUE.equals(name)) { return toRootPath(); } return toRootDir() + URL.encode(name); } private String toRootPath() { return root; } private String toRootDir() { if (root.equals(PATH_SEPARATOR)) { return root; } return root + PATH_SEPARATOR; } private String getPath(String key, String type) { key = key.replace("/", "*"); if (type.equals(Constants.CONDITION_ROUTE)) { return prefix + Constants.PATH_SEPARATOR + key + Constants.CONDITION_RULE_SUFFIX; } else { return prefix + Constants.PATH_SEPARATOR + key + Constants.TAG_RULE_SUFFIX; } } private List<Route> convertRouteToOldRoute(ConditionRouteDTO route) { List<Route> oldList = new LinkedList<Route>(); for (String condition : route.getConditions()) { Route old = new Route(); old.setService(route.getService()); old.setEnabled(route.isEnabled()); old.setForce(route.isForce()); old.setRuntime(route.isRuntime()); old.setPriority(route.getPriority()); String rule = parseCondition(condition); old.setRule(rule); oldList.add(old); } return oldList; } private String parseCondition(String condition) { StringBuilder when = new StringBuilder(); StringBuilder then = new StringBuilder(); condition = condition.trim(); if (condition.contains("=>")) { String[] array = condition.split("=>", 2); String consumer = array[0].trim(); String provider = array[1].trim(); if (consumer.length() != 0) { if (when.length() != 0) { when.append(" & ").append(consumer); } else { when.append(consumer); } } if (provider.length() != 0) { if (then.length() != 0) { then.append(" & ").append(provider); } else { then.append(provider); } } } return (when.append(" => ").append(then)).toString(); } }