千家信息网

来自平行世界的救赎

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,神级的拷问来了为什么要说是救赎呢?先跟各位讨论个"死亡问题",如果你的女票或者你老婆问你,"我跟你妈落水了,你先救谁?"哈哈,没错,就是这个来之中国的古老声音,这个拷问你内心的世纪难题!怕了没?可以抛
千家信息网最后更新 2026年11月02日来自平行世界的救赎

神级的拷问来了


为什么要说是救赎呢?先跟各位讨论个"死亡问题",如果你的女票或者你老婆问你,"我跟你妈落水了,你先救谁?"

哈哈,没错,就是这个来之中国的古老声音,这个拷问你内心的世纪难题!怕了没?
可以抛硬币,也可以找个渔网一次性捞起来,可是等等,在这紧急关头你真的有这么多时间?
此时的你肯定最想变成超人,或者修得绝世秘法"分身术",这样就不用做这道艰难的选择题了。
平行宇宙论告诉我们,这世界有无数个copy,你也有无数个copy,只要找另外一个世界借一个你过来,你的内心就能得到神圣的救赎了。


怎么做

好了,假设真的由一个平行世界,为了保证这个方法落地的可行性,我们还需要保证

  • 平行世界的真的是我

    我代表着不仅仅是名字外貌,还有我的人生种种组成才是完整的我,最佳结果是什么?平行世界的我就是从这一刻跟我分离出来的,是我的真正copy,通一个版本的copy!

  • 另一个我能到这个世界来帮我救一个人

    这是我们讨论这个问题的本质,解决不了的话,再来100个平行世界的我又能怎么样?所以他要能干涉到我们这个世界,能在这个世界行动!可是既然是平行世界,那么肯定是无法过来的啊,怎么办呢?大家都知道,作为高纬度的神可以投影到低纬度的世界中,通过"投影"来行动,或许我们可以这么干?

整理下思路

两个同样的我同时救了两个生命中最重要的人,不踩坑不扎心,再来几个老婆都救得了,简直完美!


圣者(程序猿)时间

解决哲学问题而内心得到升华的我们,此时回归真我(现实),利用仅存的圣者模式思考这个方法的现实意义。
"高大上"的工程师职业过程中,我们会遇上前人有意或者无意在代码中留下的坑,譬如

  • 某些设计得很不合理的单例模式,这让我们在一个JVM中只有一个实例存在
  • 将某些数据(如状态)存在静态字段中,如果修改可能导致运行出错
  • 或者其它蛋疼不考虑后来人的设计

但我们需要为这类对象创建全新一个实例去拯救世界时,除了内心被千万草泥马践踏而过之外,似乎只能感受到这世界满满的恶意了。
不,肯定不是!
我们可是在圣者模式!!
在操蛋的现实社会中我们只是屌丝,但在0和1的世界里,我们可是神!
无所不能的神!

神爱世人,怎么会让自己的羔羊生活在水深火热中呢?
就像拯救你妈你老婆和你内心那样,我们可以创造出一个平行世界出来啊,从虚无中造物不就是我们的本能么?


设计

前面我们已经讨论过世纪难题的解决方案,也给出了设计图,此时的我们只要把这个思维转换为由0和1组成的另一个世界的方式表达,似乎就可以了?

我们要通过救世主对象去操作一堆"待拯救的对象",嗯,这就是救世主应该做的。
但是,另外一边出现灾难了,又有一堆"待拯救的对象"排排坐,等着救世主来拯救。
救世主说,卧槽,我TM分身乏术啊,上帝没给我分身这个超能力,我也很无助啊。

好了,这个时候就是英雄闪亮登场的机会啦。

你爹妈不给你分身术,咱不分身啦,咱直接开一个新的世界,拉一个过来呗,别问为啥,就是这么任性。

嗯,具体操作就像如何把大象放进冰箱一样分3步

1、新开辟一个世界;
2、复制一个救世主过去;
3、把救世主投影过来;

步骤有啦,分析下怎么执行。

  1. 新开辟一个世界

    我们是务实的工程师,不能吹逼,所以不应该叫新开辟世界,应该叫做制作一个相对比较隔离的环境出来,要求呢?这个环境应该

    • 工作在里面的对象跟外面的能力应该是完全一样的
    • 环境外面应该是无法感知里面的情况的
    • 环境内外的对象应该是完全不同的

    我们暂且为这个环境命名为"沙箱"(Sandbox)吧。
    以单例设计为参考,单例设计一般是寄托于类(Class)存在的,为了复制这个对象,我们需要做的是将整个Class复制一份。

    我们知道Java中的Class是由ClassLoader装载进内存的,而ClassLoader采用的是双亲委派机制,一个ClassLoader内独有的业务对象对其它ClassLoader是不存在的,这不就完美满足我们上面说的三个点吗?Good,就它了!
    方案:采用ClassLoader作为沙箱环境隔离

  2. 复制一个救世主过去

    前面我们确定了ClassLoader方案后思路自然豁然开朗,现在考虑将Class复制进沙箱(ClassLoader)内就非常简单啦!
    我们知道,ClassLoader装载Class时候其实是读取.class文件,再通过ClassLoader的defineClass来实际定义一个类的,嗯,那我们将沙箱外的类定义复制过来也可以这样,两步
    首先读取.class内容。这个文件在哪里呢?当jar包被ClassLoader装入内存后,通过getResource就可以将文件数据读取到啦,完美!
    在沙箱内定义类。简单,就一个defineClass,打完收工~
    嘿,别急,小心类重新定义哦,记得记录下定义过哪些类。

  3. 把救世主投影过来

    对,这也是个问题。
    刚刚我们有说过,不同ClassLoader的独有业务对象对其它ClassLoader而言是不存在的!这就引发出问题了,外面无法使用里面创造出来的对象实例!

    举个例子

    BizObject biz = new BizObject(); //OKBizObject biz2 = Sandbox.createObject(BizObject.class); //出错

    为什么出错呢?因为沙箱内外的BizObject是不一样的啊,正反粒子在一起会湮灭的。。。
    所以我们需要投影。
    好吧,不是投影,我们需要有一个代理,在沙箱外培养一个傀儡,哦不是,是代理,对这个代理的所有操作都能反馈到沙箱内去执行。

嗯,到这里为止,我们基本将问题梳理一遍了,那么下一步。。。。。。


神说,要有光

通过上面分析和梳理,我们基本已经确定了方向和逻辑,现在呢,万事俱备,只缺一道神奇的东风我们就可以进入全新世界里了,那我们开始撸代码!

等等这位同学,我们是不是漏了什么?
撸代码前我们先要进行设计啊!

好吧,我们讨论下本次需求。。。
首先,我们假定了已经设定了一个神奇的"沙箱",沙箱内外隔离,所以内外的通信只能通过一座也是非常神奇的桥梁来进行,这就是"代理";
当外部的某位同学需要创建一个对象但又受到各种限制的时候,他可以在沙箱内创建一个此对象的分身,然后通过分身的代理进行操作就可以实现对分身的操纵,从而达成目的。
嗯,需求只有这么多,接下来我们谈谈设计。
上面讨论中我们决定了使用ClassLoader对沙箱内外进行隔离,可是不是直接暴露ClassLoader接口给外部使用呢?
ClassLoader能对底层类进行操作,虽然功能强大,但操作复杂度高,一不留神容易出现问题,所以我们应该对它进行封装,仅提供我们期望用户去使用的接口,而且我们认为它应该具备这些特点

  • 功能单一
  • 与沙箱不相干的都不要暴露
  • 创建对象后直接可以使用

这对ClassLoader来说有些强人所难,所以我们需要把它隐藏起来,创造一个沙箱对外提供服务,而将ClassLoader隐藏在沙箱内部,假定它叫"SandboxClassLoader"。
这样我们就有了

  • 调用者
  • 沙箱
  • SandboxClassLoader
  • 外部ClassLoader

四个对象了。
还有一点,上面说过我们的调用者通过代理对沙箱内对象进行操作,还记得为什么要使用代理吗?使用代理的本质原因是沙箱内外的类分属不同ClassLoader,即使同名类也是不同的!
同样道理,当我们通过代理对象进行调用时,参数传递使用的是沙箱外的对象,进入沙箱内也是不能直接使用的,因此,我们同样需要对这类对象进行转换。
此处我们仅考虑值对象参数,各位同学如果关心其它对象传参的话,需要进行类似的代理转换,但值对象的话,我们只要进行值复制就行了,无需太过复杂处理
我们通过一幅图来说明下这个关系

图片很直观,就不再重复解说啦
嗯,基本梳理应该已经非常清晰了,图中只有蓝色的"沙箱内某对象"属于工作在沙箱内,动态创建出来的,其它都是在沙箱外;
而方框画出了沙箱组件边界,调用者和APPClassLoader都属于已存在的实例无需关心,组件内部就属于需要实现的部分了。
列一下关键几个类

可以看出,Sandbox的API已经变得非常单一和简单了。
为了简化设计,这里规定了待创建的对象必须有无参构造函数,如果同学有需要通过有参构造函数构造对象的话,可以进行扩展实现,欢迎一起做好这个沙箱工具
为什么这里要分开枚举和非枚举对象呢?有同学清楚吗?
枚举的概念是指能有限列举出来的东西,在java中,枚举对象继承自Enum,不能通过new方法进行构造,只能从枚举的值中选取
而对象继承自Object,大家都非常的熟悉

创世纪

终于进入最重要的撸代码环节了。。。

挑重点的代码出来,咱撸一撸

public class Sandbox {    private SandboxClassLoader classLoader;    private SandboxUtil util = new SandboxUtil();    private List redefinedPackages;    public Sandbox(List packages){        redefinedPackages = packages;        classLoader = new SandboxClassLoader(getContextClassLoader());    }    /**     * 沙箱对象构造方法     * @param redefinedPackages 需工作在沙箱内的包     *                          此包下面所有类都在工作在沙箱内     */    public Sandbox(String... redefinedPackages){        this(Lists.newArrayList(redefinedPackages));    }    // ......}

先说说构造方法。
既然是沙箱对象,为什么要设计有参构造方法呢?
实际使用中,我们会考虑某些类之间内聚,当一个类放在沙箱内运行时,其它也建议放在沙箱内跑,而我们学过"单一性原则",知道一个包内一般都是比较内聚的,所以这里设计就是指定某些package路径,沙箱将会对这些包内对象进行接管。
对于不在这些包内的类,如果我们调用了沙箱来构造会怎么样呢?所谓"Talk is cheap, show me the code"~~
请稍后,我们继续构造函数,哈哈~~这个问题我们标记为问题1稍后讨论
这里出现了SandboxClassLoader,使用了getContextClassLoader()作为参数传递,此处做了什么呢?我们先看看SandboxClassLoader的构造方法

    /**     * 沙箱隔离核心     *     * 通过ClassLoader将进行类级别的运行时隔离     *     * 此类本质上是代理了currentContextClassLoader对象,并增加了对部分需要在沙箱内运行的类处理能力     */    class SandboxClassLoader extends ClassLoader{        //当前上下文的ClassLoader,用于寻找类实例并克隆进沙箱        private final ClassLoader contextClassLoader;        //缓存已经创建过的Class实例,避免重复定义        private final Map cache = Maps.newHashMap();        SandboxClassLoader(ClassLoader contextClassLoader) {            this.contextClassLoader = contextClassLoader;        }        //......    }

SandboxClassLoader的构造方法仅仅是将传入的contextClassLoader进行暂存备用,那么我们还是看看getContextClassLoader方法

    /**     * 获取当前上下文的类装载器     *     * 此类装载器需包含MQClient相关类定义     * PS:单独定义为一个方法,是担心当这个上下文类装载器满足不了要求时可以快速更换     * @return 当前类装载器     */    private ClassLoader getContextClassLoader() {        //从类装载器机制而言,线程上下文的类转载器是最符合要求的        return Thread.currentThread().getContextClassLoader();    }

好简单!!
其实这里是有一些设计依据的:我们要去创建一个对象,那么这个对象的类定义必然在当前代码可访问的。
基于这个考虑,我们可以确定,当用户使用类似A a = Sandbox.createObject(A.class)进行创建沙箱内对象时,A类在这段代码执行的上下文必然可以访问,此时我们可以通过此上下文的ClassLoader去获取到这个A类对应的.class资源文件,然后重定义该类了。
继续看看相关代码,为了阅读方便,我重新组织了下代码结构

public class Sandbox {    private SandboxClassLoader classLoader;    //......    /**     * 在沙箱内创建指定名称的类实例     *     * 如该名称类不属于redefinedPackages所指定的包内,则直接返回外部类实例     * @param clzName 待创建实例的类名称     * @return 指定类名称的实例对象     */    public  T createObject(String clzName) throws ClassNotFoundException, SandboxCannotCreateObjectException {        Class clz = Class.forName(clzName);        return (T) createObject(clz);    }    /**     * 在沙箱内创建指定Class的实例     * @param clz 待创建实例的Class     * @return 跟clz功能相同并工作在沙箱内的类实例     */    public synchronized  T createObject(Class clz) throws SandboxCannotCreateObjectException {        try {            final Class clzInSandbox = classLoader.loadClass(clz.getName());            final Object objectInSandbox = clzInSandbox.newInstance();            //如果对象的类装载器和clz的类装载器一致,说明不是需要工作在沙箱内的对象,直接返回即可,无需代理            if(objectInSandbox.getClass().getClassLoader() == clz.getClassLoader()){                return (T) objectInSandbox;            }            /*            创建生产者的代理:由于沙箱内外的对象本质上属于不同的类,因此需要将两者能力桥接起来                            这里采用了代理模式,通过创建沙箱外的对象实例,并将其所有方法调用通过代理转发到沙箱内执行                            另外,由于沙箱内外的所有实例都属于不同的类,因此,对于参数和返回值还需要进行对象转换,将沙箱内外的对象进行对等克隆             */            //通过cglib创建对象的子类代理            Enhancer enhancer = new Enhancer();            enhancer.setSuperclass(clz);            enhancer.setCallback((MethodInterceptor) (o, method, args, methodProxy) -> {                Method targetMethod = clzInSandbox.getMethod(method.getName(), method.getParameterTypes());                //调用前需对参数进行克隆,转换为沙箱内对象                Object[] targetArgs = args == null ? null : util.cloneTo(args, classLoader);                Object result = targetMethod.invoke(objectInSandbox, targetArgs);                //调用后续对结果进行克隆,转换为沙箱外对象                return util.cloneTo(result, getContextClassLoader());            });            return (T) enhancer.create();        }catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {            throw new SandboxCannotCreateObjectException("无法在沙箱内创建对象", e);        }    }    //......}

Sandbox中创建对象的主要方法出现了!为了方便阅读,我将无关代码剔除,仅保留createObject方法。
T createObject(String clzName)方法无具体实现,仅进行参数clzName的校验,然后就转给T createObject(Class clz),因此主要分析这个方法。
其实代码量不多(仅19行还包括各种花括号),主要都是注释,脉络如下

  1. 先获取参数clz在沙箱内的对于类定义clzInSandbox,并通过clzInSandbox的newInstance创建该类的一个具体实例objectInSandbox;因此这里要求clz有无参构造函数
  2. 判断clzInSandbox是否运行在沙箱内,如果不是运行在沙箱内的话,无需创建代理直接将对象objectInSandbox返回;
    为什么要做这个判断嗯?这里可以顺带解答前面的问题1了,从代码

    //如果对象的类装载器和clz的类装载器一致,说明不是需要工作在沙箱内的对象,直接返回即可,无需代理if(objectInSandbox.getClass().getClassLoader() == > clz.getClassLoader()){    return (T) objectInSandbox;}

    我们可以看出来,当创建出来的objectInSandbox也是运行在外部的ClassLoader时,其实是不去创建代理的,因为它就是一个沙箱外的对象,又何必去创建代理这么多此一举呢?
    可我们明明调用的是classLoader.loadClass(clz.getName())去取得沙箱内的类定义,为什么得到的却是沙箱外的呢?这跟我们对SandboxClassLoader这个类的设计是否矛盾了呢?
    好,去看看对应的代码,show me the code

    class SandboxClassLoader extends ClassLoader{    //当前上下文的ClassLoader,用于寻找类实例并克隆进沙箱    private final ClassLoader contextClassLoader;    //......      /**     * 覆盖父类的转载类进内存的方法     * @param name 指定类名称     * @return 已转载进内存的Class实例     * @throws ClassNotFoundException     */    @Override    public Class<?> loadClass(String name) throws ClassNotFoundException {        return findClass(name);    }    /**     * 重定义类转载逻辑     *     * 1、对于需要运行在沙箱内的类(redefinedPackages中声明),通过复制contextClassLoader类定义的方式,直接运行在此ClassLoader下     * 2、对于不需要运行在沙箱内的类,直接返回上下文类定义,以减少资源占用     * @param name 类名称(全路径)     * @return 类定义     */    @Override    protected Class<?> findClass(String name) throws ClassNotFoundException {        if(isRedefinedClass(name)) {            return getSandboxClass(name);        } else {            return contextClassLoader.loadClass(name);        }    }    //......}

    看得出实际实现逻辑的代码是findClass方法,仅几句而已,翻译过来就是"需要重定义的类我们从沙箱内取得,不需要的直接从外部取",所以会有对象的ClassLoader是外部的。
    那什么是"需要重定义的类"呢?

    /** * 是否需要运行在沙箱内的类 * @param name 类名称 */boolean isRedefinedClass(String name) {    //校验是否沙箱约定的需要重定义的包    for (String redefinedPackage : redefinedPackages) {        if(name.startsWith(redefinedPackage)){            return true;        }    }    return false;}

    只要是Sandbox类构造时指定的包下面的类,统统都属于需要重新在SandboxClassLoader中重定义的。

  3. 利用cglib库创建objectInSandbox的代理对象,拦截该代理对象的所有方法执行,全部转去实际的对象objectInSandbox中执行;
    cglib创建对象的代码不分析了,本质就是通过创建一个指定类的子类对方法进行拦截的过程;
    我们关心的应该是拦截器干了什么?

    enhancer.setCallback((MethodInterceptor) (o, method, args, methodProxy) -> {            Method targetMethod = clzInSandbox.getMethod(method.getName(), method.getParameterTypes());            //调用前需对参数进行克隆,转换为沙箱内对象            Object[] targetArgs = args == null ? null : util.cloneTo(args, classLoader);            Object result = targetMethod.invoke(objectInSandbox, targetArgs);            //调用后续对结果进行克隆,转换为沙箱外对象            return util.cloneTo(result, getContextClassLoader());        });

    我们会从沙箱内的对象中取得同名同参的方法,然后将参数进行转换到沙箱内,再执行沙箱内对象方法并得到结果,最后还要将结果进行转换到沙箱外对象才返回;
    逻辑非常清晰,但沙箱内外对象如何转换呢?
    这里代码有些长且无聊就不单独贴出来了,有兴趣的同学可以上github上自行下载,大体逻辑如下

    1. 判断对象是否需要转换成沙箱内/外,不需要则返回此对象,需要就转2;
    2. 创建沙箱内/外对应的对象实例;
    3. 遍历该对象实例的每一个字段,对该字段执行步骤1,并将复制后的值赋值给新对象中对应字段;

    嗯,就是这样。
    前面我们有提到,我们假定传参对象都是值对象,所以这里的设计相对简单,如有哪位同学需要传非值对象,那么就需要对外部对象做代理

  4. 将代理对象返回;

有些同学关心类如何从沙箱外复制到沙箱内重定义的是吧?这是SandboxClassLoader的核心部分,展示下代码逻辑

class SandboxClassLoader extends ClassLoader {    //......    //缓存已经创建过的Class实例,避免重复定义    private final Map cache = Maps.newHashMap();    /**        * 内部方法:获取需要在沙箱内运行的Class实例        * @param name 类名称        * @return 沙箱内的类实例        * @throws ClassNotFoundException        */    private synchronized Class getSandboxClass(String name) throws ClassNotFoundException {        //1、先从缓存中查找是否已经转载过该类,有则直接返回        if(cache.containsKey(name)){            return cache.get(name);        }        //2、缓存不存在该类时,从currentContextClassLoader中复制一份到当前缓存中        Class clz = copyClass(name);        cache.put(name, clz);        return clz;    }    /**        * 从currentContextClassLoader中复制一份类到本ClassLoader中        *        * 此复制是将字节码copy到当前ClassLoader进行定义,因此与sandbox外部的Class已经完全不同实例,不能给外部直接赋值        * @param name 待复制的类名称        * @return 工作在当前ClassLoader中的Class        * @throws ClassNotFoundException        */    private synchronized Class copyClass(String name) throws ClassNotFoundException {        //取得.class文件所在路径        String path = name.replace('.', '/') + ".class";        //通过上下文类装载器获取资源句柄        try (InputStream stream = contextClassLoader.getResourceAsStream(path)) {            if(stream == null) throw new ClassNotFoundException(String.format("找不到类%s", name));            //读取所有字节内容            byte[] content = readFromStream(stream);            return defineClass(name, content, 0, content.length);        } catch (IOException e) {            throw new ClassNotFoundException("找不到指定的类", e);        }    }    //......}

涉及到的方法主要有两个,getSandboxClass方法主要负责获取对象时进行缓存层面的校验,缓存的目的一个是加速获取类定义的性能,一个是避免同一个类定义重复多次执行导致出错。
copyClass顾名思义就是复制类定义,是从contextClassLoader中将类对应的.class文件进行复制,并在SandboxClassLoader中defineClass的过程,具体请阅读代码。

Sandbox中我们还有一个getEnumValue方法,过程有些类似就不重复介绍,请下载代码阅读。

至此,我们完成了代码的编写了。
至此,我们完成了新世界的构建了!
至此,我们完成了所有工作了!!??
高兴得太早了。。。


到来的救赎

测试是代码质量的保障,是设计的保障,是运行的保障,是......的保障,总之,就是保障。
所以,我们还要通过测试,为我们的"世界"进行验证,看看它是否跟我们预期一致。
这只需要使用单元测试就可以做到了。代码

public class SandboxTest {    @Test    public void getEnumValue() throws SandboxCannotCreateObjectException {        //设定重定义的包        Sandbox sandbox = new Sandbox("com.google.common.collect");        //获取沙箱内对象,虽然是同名同值,但由于分属沙箱内外,因此预期应该不等        Enum type = sandbox.getEnumValue(com.google.common.collect.BoundType.CLOSED);        assertNotEquals(type, com.google.common.collect.BoundType.CLOSED);        //通过沙箱获取非设定需要重定义的包内对象,预期应该是相等        Enum property = sandbox.getEnumValue(com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH);        assertEquals(property, com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH);    }    @Test    public void createObject() throws SandboxCannotCreateObjectException, ClassNotFoundException {        //设定重定义的包        Sandbox sandbox = new Sandbox("com.google.common.eventbus");        //获取沙箱内对象,预期中类定义应该与沙箱外的类定义不等        com.google.common.eventbus.EventBus bus = sandbox.createObject(com.google.common.eventbus.EventBus.class);        assertNotEquals(bus.getClass(), com.google.common.eventbus.EventBus.class);        //通过名称获取,如上        bus = sandbox.createObject("com.google.common.eventbus.EventBus");        assertNotEquals(bus.getClass(), com.google.common.eventbus.EventBus.class);        //通过沙箱获取无需重定义的类,预期应该跟沙箱外相等        List list = sandbox.createObject(ArrayList.class);        assertEquals(list.getClass(), ArrayList.class);    }}

运行结果

OK,测试通过~~~


世界的坐标

  • -> github
  • -> 码云gitee

落地案例:如何在同一个Java进程中连接多个RocketMQ服务器

沙箱 对象 实例 方法 代理 世界 代码 设计 就是 运行 装载 问题 上下 上下文 参数 工作 同学 救世主 平行 不同 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司怎么样 科技互联网企业 与互联网科技公司 美国互联网科技 互联网科技公司有哪些 安控科技rtu产品工业互联网 广州恒生互联网科技有限 岳阳华臻互联网科技有限公司 苏州铭阳互联网科技有限公司 互联网科技的全部知识 山东子淼互联网科技有限公司 怎样加入科技互联网 互联网公司高科技产品 下一代互联网重大应用科技园 宁波跨境商互联网科技有限公司 上海同邻互联网科技有限公司规模 互联网金融运营模式中的金融科技 河南商务圈互联网科技有限公司 广东猫王互联网科技有限公司电话 如何强化互联网金融科技 互联网科技工作委员会毛军 互联网金融公司科技 深圳互联网络科技有限公司 上海挚品互联网科技 亿策互联网科技 互联网科技寓意 无锡工业互联网科技有限公司 互联网科技快讯热点 互联网科技和医药行业 武汉亿视互联网科技有限公司
0