dubbo的Mock功能与源码实现

在开发自测,联调过程中,经常碰到一些下游服务调用不通的场景,这个时候我们如何不依赖于下游系统,就业务系统独立完成自测?
dubbo自身是支持mock服务的,在reference标签里,有一个参数mock,该参数有四个值,false,default,true,或者Mock类的类名。分别代表如下含义:

  • false,不调用mock服务。
  • true,当服务调用失败时,使用mock服务。
  • default,当服务调用失败时,使用mock服务。
  • force,强制使用Mock服务(不管服务能否调用成功)。(使用xml配置不生效,使用ReferenceConfigAPI可以生效)

使用方法:

  • 将mock参数启用,在<dubbo:reference>中添加参数项mock=true。

  • 实现需要调用的服务接口

    • 上游系统需要调用下游系统,则下游需要提供jar包给上有系统,该jar包只有接口,没有实现。我们需要实现该接口,且命名必须是该接口名+Mock,例如原接口是com.alibaba.dubbo.demo.DemoService,则实现类必须是com.alibaba.dubbo.demo.DemoServiceMock
      举个例子:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- consumer's application name, used for tracing dependency relationship (not a matching criterion),
    don't set it same as provider -->
    <dubbo:application name="demo-consumer"/>

    <!-- use multicast registry center to discover service -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!-- generate proxy for the remote service, then demoService can be used in the same way as the
    local regular interface -->
    <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>

</beans>
public class Consumer {
    public static void main(String[] args) {
        //Prevent to get IPV6 address,this way only work in debug mode
        //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not
        System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
        context.start();
        DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy
        try {
            Thread.sleep(1000);
            String hello = demoService.sayHello("world"); // call remote method
            System.out.println(hello); // get result

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

当我下游服务不启动的时候,也就是没有com.alibaba.dubbo.demo.DemoService的时候,运行该main函数,执行结果如下:

com.alibaba.dubbo.rpc.RpcException: No provider available from registry 127.0.0.1:2181 for service com.alibaba.dubbo.demo.DemoService on consumer 192.168.34.220 use dubbo version 2.0.0, please check status of providers(disabled, not registered or in blacklist).
    at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:574)
    at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73)
    at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:265)
    at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:224)
    at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:70)
    at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:51)
    at com.alibaba.dubbo.common.bytecode.proxy0.sayHello(proxy0.java)
    at com.alibaba.dubbo.demo.consumer.Consumer.main(Consumer.java:35)

当我将mock="true"加载demoService上以后,执行结果如下:

 <dubbo:reference id="demoService" check="false"  mock="true" interface="com.alibaba.dubbo.demo.DemoService"/>
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'demoService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Not found class com.alibaba.dubbo.demo.DemoServiceMock, cause: com.alibaba.dubbo.demo.DemoServiceMock
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1634)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:254)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078)
    at com.alibaba.dubbo.demo.consumer.Consumer.main(Consumer.java:30)
Caused by: java.lang.IllegalStateException: Not found class com.alibaba.dubbo.demo.DemoServiceMock, cause: com.alibaba.dubbo.demo.DemoServiceMock
    at com.alibaba.dubbo.common.utils.ReflectUtils.forName(ReflectUtils.java:605)
    at com.alibaba.dubbo.config.AbstractInterfaceConfig.checkStubAndMock(AbstractInterfaceConfig.java:313)
    at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:279)
    at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:163)
    at com.alibaba.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:65)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168)
    ... 6 more
Caused by: java.lang.ClassNotFoundException: com.alibaba.dubbo.demo.DemoServiceMock
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at com.alibaba.dubbo.common.utils.ReflectUtils.name2class(ReflectUtils.java:668)
    at com.alibaba.dubbo.common.utils.ReflectUtils.name2class(ReflectUtils.java:618)
    at com.alibaba.dubbo.common.utils.ReflectUtils.forName(ReflectUtils.java:603)
    ... 11 more

新建一个类:

package com.alibaba.dubbo.demo;

/**
 * Created by jetty on 18/3/10.
 */
public class DemoServiceMock implements DemoService{
    @Override
    public String sayHello(String name) {
        return "hello world";
    }
}

om.alibaba.dubbo.rpc.RpcException: No provider available from registry 127.0.0.1:2181 for service com.alibaba.dubbo.demo.DemoService on consumer 192.168.34.220 use dubbo version 2.0.0, please check status of providers(disabled, not registered or in blacklist).
    at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:574)
    at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73)
    at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:265)
    at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:224)
    at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:80)
    at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:51)
    at com.alibaba.dubbo.common.bytecode.proxy0.sayHello(proxy0.java)
    at com.alibaba.dubbo.demo.consumer.Consumer.main(Consumer.java:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
[10/03/18 05:45:06:006 CST] main  INFO wrapper.MockClusterInvoker:  [DUBBO] Exception when try to invoke mock. Get mock invokers error for service:com.alibaba.dubbo.demo.DemoService, method:sayHello, will contruct a new mock with 'new MockInvoker()'., dubbo version: 2.0.0, current host: 192.168.34.220
com.alibaba.dubbo.rpc.RpcException: No provider available from registry 127.0.0.1:2181 for service com.alibaba.dubbo.demo.DemoService on consumer 192.168.34.220 use dubbo version 2.0.0, please check status of providers(disabled, not registered or in blacklist).
    at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:574)
    at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73)
    at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.selectMockInvoker(MockClusterInvoker.java:145)
    at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.doMockInvoke(MockClusterInvoker.java:100)
    at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:88)
    at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:51)
    at com.alibaba.dubbo.common.bytecode.proxy0.sayHello(proxy0.java)
    at com.alibaba.dubbo.demo.consumer.Consumer.main(Consumer.java:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
hello world

可以看到结果,先去调用下游服务,发现没服务,报错,然后调用Mock服务,返回hello world。
当我将mock参数改为force的时候再执行,抛异常了。

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'demoService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Not found class force, cause: force
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1634)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:254)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078)
    at com.alibaba.dubbo.demo.consumer.Consumer.main(Consumer.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.IllegalStateException: Not found class force, cause: force
    at com.alibaba.dubbo.common.utils.ReflectUtils.forName(ReflectUtils.java:605)
    at com.alibaba.dubbo.config.AbstractInterfaceConfig.checkStubAndMock(AbstractInterfaceConfig.java:313)
    at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:279)
    at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:163)
    at com.alibaba.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:65)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168)
    ... 11 more
Caused by: java.lang.ClassNotFoundException: force
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at com.alibaba.dubbo.common.utils.ReflectUtils.name2class(ReflectUtils.java:668)
    at com.alibaba.dubbo.common.utils.ReflectUtils.name2class(ReflectUtils.java:618)
    at com.alibaba.dubbo.common.utils.ReflectUtils.forName(ReflectUtils.java:603)
    ... 16 more

报错在

 at com.alibaba.dubbo.common.utils.ReflectUtils.forName(ReflectUtils.java:605)
    at com.alibaba.dubbo.config.AbstractInterfaceConfig.checkStubAndMock(AbstractInterfaceConfig.java:313)
    at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:279)
    at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:163)

当dubbo服务在启动获取bean服务的时候,首先会检查mock属性是不是以return开头,不是的话判断是否是default,或者true,如果是default,或者true开头,则返回接口名+Mock为Mock实例的类名,不然,则直接以Mock属性的值为类名
因此如果这里为force,则会抛: Not found class force, 异常。

 protected void checkStubAndMock(Class<?> interfaceClass) {
    if (ConfigUtils.isNotEmpty(mock)) {
        //是不是以return开头
        if (mock.startsWith(Constants.RETURN_PREFIX)) {
            String value = mock.substring(Constants.RETURN_PREFIX.length());
            try {
                MockInvoker.parseMockValue(value);
            } catch (Exception e) {
                throw new IllegalStateException("Illegal mock json value in <dubbo:service ... mock=\"" + mock + "\" />");
            }
        } else {
            //判断是否是true/default,如果是返回接口名+Mock,如果不是,则直接返回Mock的参数
            Class<?> mockClass = ConfigUtils.isDefault(mock) ? ReflectUtils.forName(interfaceClass.getName() + "Mock") : ReflectUtils.forName(mock);
            if (!interfaceClass.isAssignableFrom(mockClass)) {
                throw new IllegalStateException("The mock implementation class " + mockClass.getName() + " not implement interface " + interfaceClass.getName());
            }
            try {
                mockClass.getConstructor(new Class<?>[0]);
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implementation class " + mockClass.getName());
            }
        }
    }
}

重点来了,当我不使用xml配置时,直接使用referenceConfig获取下游服务,可以调用成功,返回hello,world。重点在于consumerConfig.setMock("force");这行代码。

 @Test
public void testInjvm() throws Exception {
    ApplicationConfig application = new ApplicationConfig();
    application.setName("test-protocol-random-port");

    RegistryConfig registry = new RegistryConfig();
    registry.setAddress("multicast://224.5.6.7:1234");
    ProtocolConfig protocol = new ProtocolConfig();
    protocol.setName("dubbo");
    ReferenceConfig<DemoService> rc = new ReferenceConfig<DemoService>();
    rc.setApplication(application);
    rc.setRegistry(registry);
    ConsumerConfig consumerConfig=new ConsumerConfig();
    //重点在这里
    consumerConfig.setMock("force");
    rc.check=false;
    rc.setConsumer(consumerConfig);
    rc.setInterface(DemoService.class.getName());

    try {
        DemoService demoService2=  rc.get();
        String text=demoService2.sayName("hello");
        System.out.println(text);
        Assert.assertTrue(!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(
                rc.getInvoker().getUrl().getProtocol()));
    } finally {
    }
}

那么问题来了,到底这个算不算bug。。。。。
不关心这个了,重点是原理,mock是如何实现的。
再看看调用过程:

  • 查看是否有Mock的参数,没有或false,则直接调用invoker。
  • 若是以force开头,则强制走Mock
  • 其他场景,先调用下游,失败了调用Mock服务
    在调用Mock服务过程中,当发现没有Mock服务时,new一个MockInvoker,调用MockInvoker的服务。
public class MockClusterInvoker<T> implements Invoker<T> {

 
   public Result invoke(Invocation invocation) throws RpcException {
       Result result = null;
       //判断是否有Mock参数
       String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
       if (value.length() == 0 || value.equalsIgnoreCase("false")) {
          
           result = this.invoker.invoke(invocation);
       } else if (value.startsWith("force")) {
           Mock参数是否以force开头
           if (logger.isWarnEnabled()) {
               logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
           }
           //force:direct mock 强制走Mock
           result = doMockInvoke(invocation, null);
       } else {
           //fail-mock
           try {
               result = this.invoker.invoke(invocation);
           } catch (RpcException e) {
               if (e.isBiz()) {
                   throw e;
               } else {
                   if (logger.isWarnEnabled()) {
                       logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                   }
                   //失败走Mock
                   result = doMockInvoke(invocation, e);
               }
           }
       }
       return result;
   }

   private Result doMockInvoke(Invocation invocation, RpcException e) {
       Result result = null;
       Invoker<T> minvoker;
       //获取Mock的Invoker
       List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
       if (mockInvokers == null || mockInvokers.size() == 0) {
           ////没有获取到Mock的Invoker 新建一个MockInvoker
           minvoker = (Invoker<T>) new MockInvoker(directory.getUrl());
       } else {
           minvoker = mockInvokers.get(0);
       }
       try {
           //调用Mock服务。
           result = minvoker.invoke(invocation);
       } catch (RpcException me) {
           if (me.isBiz()) {
               result = new RpcResult(me.getCause());
           } else {
               throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
           }
       } catch (Throwable me) {
           throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
       }
       return result;
   }
}

在调用过程中,先从缓存中获取,获取不到,调用newInstance实例化一个。

//MockInvoker.java
 public Result invoke(Invocation invocation) throws RpcException {
    //忽略很多代码
    Invoker<T> invoker = getInvoker(mock);
    return invoker.invoke(invocation);   
}

 private Invoker<T> getInvoker(String mockService) {
    //缓存中获取
    Invoker<T> invoker = (Invoker<T>) mocks.get(mockService);
    if (invoker != null) {
        return invoker;
    } else {
        //newInstance获取的Mock服务实例
        T mockObject = (T) mockClass.newInstance();
        invoker = proxyFactory.getInvoker(mockObject, (Class<T>) serviceType, url);
        return invoker;
    }
}

fyi

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 一、前言 在之前的文章 http://www.jianshu.com/p/c128ed5c394e 中已经介绍了“...
    小程故事多阅读 2,729评论 3 18
  • 0 准备 安装注册中心:Zookeeper、Dubbox自带的dubbo-registry-simple;安装Du...
    七寸知架构阅读 13,970评论 0 88
  • 是太阳, 而,而, 那些肆意流传,那些随意建造, 沉寂在废墟和黄昏, 城市和骄燃。 夕阳是远的炽烈, 让夜会来, ...
    易安阅读 197评论 0 1
  • 本书的作者丹·斯科伯尔是《纽约时报》“自品牌专家”,千禧时代品牌公司的管理合伙人,同时是闻名世界的事业规划与职...
    杨泽阅读 293评论 0 0