Dubbo接口自动化测试(二)--如何自动化配置点对点直连的consumer.xml文件

xml文件读取参考:https://blog.csdn.net/qq_26676207/article/details/53035567

上文讲到dubbo接口测试中点对点的直连方式,需要明确dubbo服务的路径和接口名,如果项目dubbo服务太多的情况下,手动配置显然是下下之策,所以想到有没有什么方式能够把dubbo服务的信息获取到,然后自动生成xml配置文件。方法则是通过zkclient连接到dubbo服务的注册中心zookeeper,然后在zookeeper上面拿到对应服务的相关信息。

pom.xml文件配置

我们需要配置zkclient,工程pom文件加上以下内容

        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>

获取dubbo服务的相关信息

首先博主展示在zookeeper里面如何获取服务信息
1、找到zk目录,在bin目录下面输入

sh zkCli.sh

2、进入zk之后,然后再输入指令

ls /dubbo
到这一步之后,我们会看到所有注册到zk上面的工程文件的接口名,整个信息是一个列表,如下
[com.xxx.service1,com.xxxx.service2]

3、然后选择任意接口,输入以下指令

ls /dubbo/com.xxx.service1
到这一步,会看到展示以下内容
[consumers, routers, configurators, providers]

4、输入以下指令

ls /dubbo/com.xxx.service1/providers
到这一步会输出该接口服务的相关信息(urlencode内容,可以在线解码即可),如下所示
[dubbo%3a%2f%2f10.10.10.10%3a8080%2fcom.xxxxx.service%3faccesslog%3dfalse%26anyhost%3dtrue%26application%3ddubbo-rpc%26charset%3dUTF-8%26dubbo%3d3.0.0%26generic%3dfalse%26interface%3dcom.dubbo.service1%26iothreads%3d8%26logger%3dslf4j%26methods%3ddubboFunction%26organization%3dxxx%26owner%3dxxx%26payload%3d883886%26pid%3d6914%26serialization%3dkryo%26server%3dnetty%26side%3dprovider%26threadpool%3dcached%26threads%3d250%26timestamp%3d1527509257826%26version%3d2.1]

urldecode解码之后的内容:

dubbo://10.10.10.10:8080/com.xxxxx.service?accesslog=false&anyhost=true&application=dubbo-rpc&charset=UTF-8&dubbo=3.0.0&generic=false&interface=com.dubbo.service1&iothreads=8&logger=slf4j&methods=dubboFunction&organization=xxx&owner=xxx&payload=883886&pid=6914&serialization=kryo&server=netty&side=provider&threadpool=cached&threads=250&timestamp=1527509257826&version=2.1

很明显,我们可以从上面的信息中获取到ip,端口号,接口名称,方法名称(博主暂时没用到),以及版本号(确认版本号信息是在这个字符串的最后面,不用担心跑到中间位置)

zkclient连接zk并处理信息

直接贴代码

    private static  List<String> getDubboInfo(String path){
        List<String> list = new ArrayList<String>();
        String servers = getProperties("zk.servers");
//        String roopath = getProperties("zk.rootpath");

        ZkClient zkClient = new ZkClient(servers, 5000);
        zkClient.subscribeChildChanges(path, new IZkChildListener() {
            @Override
            public void handleChildChange(String s, List<String> list) throws Exception {
                System.out.println("parentPath:"+s+", currentchilds:"+list);
            }
        });

        try{
            list = zkClient.getChildren(path);
            Thread.sleep(1000);
//            return list;
        } catch (Exception e){
            logger.error(String.valueOf(e));
        }
        return list;
    }

这段代码需要一个path参数作为入参,其实就是”/dubbo”,这个zk里面的根节点,主要是通过获取到配置文件中的zk地址(zk.servers)然后建立连接之后拿到节点下面的服务名形成一个list,这个list包含了所有注册到zk的服务

获取dubbo服务的ip:port与接口服务对应关系

这一块,博主希望通过一个map建立一组管理,每一组用json描述如下:

{
    "10.10.10.10:8888":"com.xxxx.service",
    "version":"2.1"
}

当然version并不一定存在,providers节点下面也不一定有信息,这个在代码里面都有做处理,如下:

private static  List<Map<String, String>> getInterfaceInfo(){
        final List<Map<String, String>> LIST2= new ArrayList<Map<String, String>>();
        final String ROOTPATH = getProperties("zk.rootpath");
        final List<String> LIST = getDubboInfo(ROOTPATH);

        for(int i = 0; i < LIST.size(); i++){
            final int J = i;
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    try{
                        String path = ROOTPATH + "/"+ LIST.get(J)+"/providers";
                        List<String> list1 = getDubboInfo(path);
                        if (list1.size() == 0){
                        }else {
                            String url = URLDecoder.decode(list1.get(0));
                            //检测URl是否为用户所需
                            if(checkUrlValid(url)){
                                System.out.println(url);
                                String host = "dubbo://"+ url.split("\\?")[0].split("dubbo://")[1].split("/")[0];
                                String inter = url.split("\\?")[0].split("dubbo://")[1].split("/")[1];
                                //如果接口服务有端口号,需要带上
                                Map<String ,String> map = new HashMap<String, String>();
                                if(url.contains("&version=")){
                                    String version = url.split("&version=")[1];
                                    map.put("version", version);
                                }
                                map.put(host, inter);
                                LIST2.add(map);
                            }
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            };
            executor.submit(task);
        }
        executor.shutdown();
        while (true){
            if(executor.isTerminated()){
                logger.info("所有子线程结束!");
                break;
            }
        }
        return LIST2;

    }

这里使用了for循环的多线程,主要是为了加速信息处理,不然的话整块代码运行会非常缓慢(启动dubbo连接,进入某个节点,blablabla,流程比较繁琐),博主自己的项目大概需要10分钟,使用多线程之后也就10s不到的样子。
代码中有个checkUrlValid方法,这个是博主有个配置文件,配置了用户想要测试的rpc服务的接口名,减少pom文件添加的”痛苦“,因为如果这里不进行一定的过滤,他会拿到所有注册到zk上面的服务,那么可想而知我们的pom文件在添加依赖的的时候会有多蛋疼,所以写了一个方法进行过滤,就是简单的字符串操作,如下:

    private static boolean checkUrlValid(String url){
        String services = getProperties("project.tag");
        String [] service = services.split(",");
        boolean check = false;
        for(int i =0;i < service.length;i++){
            if (url.contains(service[i])){
                check = true;
            }
        }
        return check;
    }

consumer.xml文件读写

博主使用了两个xml文件,结构如下:
base.xml,会引入consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                             http://www.springframework.org/schema/beans/spring-beans.xsd
                             http://code.alibabatech.com/schema/dubbo
                             http://code.alibabatech.com/schema/dubbo/dubbo.xsd
                             ">
    <dubbo:application name="" owner="Venn"/>
    <dubbo:monitor protocol="registry"/>
    <import resource="classpath*:entity-consumer/consumer.xml"/>
</beans>

consumer.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans                              http://www.springframework.org/schema/beans/spring-beans.xsd                              http://code.alibabatech.com/schema/dubbo                              http://code.alibabatech.com/schema/dubbo/dubbo.xsd                              ">
</beans>

consumer.xml我们用来读写,首先新建一个模板文件就如上面的consumer.xml,文件读写如下:

public static void addUser(List<Map<String, String>> list){
        /*
         * 1. 得到Document
         * 2. 得到root元素
         * 3. 要把User对象转换成Element元素
         * 4. 把user元素插入到root元素中
         * 5. 回写document
         */
        try{
            //1.得到document
            // 创建解析器
            SAXReader reader = new SAXReader();
            //调用读方法,得到document
            Document doc = reader.read("src/main/resources/entity-consumer/consumer.xml");
            //2.得到root元素
            Element root = doc.getRootElement();
            String child = "dubbo:reference";
            //删除之前的同类型子节点
            removeNodes(root, child);

            for(int i = 0;i <list.size();i++){
                String url = getUrl(list.get(i));
                String inter = getInterface(list.get(i));
                String id = getId(list.get(i));
                String version = getVersion(list.get(i));
//                System.out.println(version);
                //3.完成添加元素,并返回添加的元素!
                Element dubboElement = root.addElement("dubbo:reference");
                dubboElement.addAttribute("id",id);
                dubboElement.addAttribute("check", "false");
                dubboElement.addAttribute("timeout","1000");
                dubboElement.addAttribute("url", url);
                dubboElement.addAttribute("interface", inter);
                if(version.equals("")){
                }else {
                    dubboElement.addAttribute("version", version);
                }
            }
            //3.回写
            Writer out = new PrintWriter("src/main/resources/entity-consumer/consumer.xml");
            OutputFormat format = new OutputFormat("\t", true);
            format.setTrimText(true);//先干掉原来的空白(\t和换行和空格)!

            XMLWriter writer = new XMLWriter(out, format);
            //把document对象写到out流中
            writer.write(doc);
            //关闭流
            out.close();
            writer.close();
        }catch (Exception e){
            // 把编译异常转换成运行异常!
            throw new RuntimeException(e);
        }
    }

大概逻辑就是,打开xml文件,删除之前的dubbo:reference节点,添加新的节点。generateString是一个随机数方法,主要是避免多个工程有相同的id,毕竟博主的id取的是接口的最后一段字符串,比如:com.xxx.service,那么博主的id就是service,这个容易冲突。
节点删除方法,也贴出来,当然需要注意,使用节点删除的时候一定要配合”回写“,不然无法生效。

    public static void removeNodes( Element root, String child){
        List nodes = root.selectNodes(child);
        for(int i =0;i < nodes.size();i++){
            Node node = (Node) nodes.get(i);
            node.getParent().remove(node);
        }

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值