文档章节

DUBBO配置规则详解

Bieber
 Bieber
发布于 2015/02/14 18:31
字数 3834
阅读 16014
收藏 174
点赞 16
评论 9

#DUBBO配置规则详解#

欢迎加入DUBBO交流群:259566260

研究DUBBO也已经大半年了,对它的大部分源码进行了分析,以及对它的内部机制有了比较深入的了解,以及各个模块的实现。DUBBO包含很多内容,如果想了解DUBBO第一步就是启动它,从而可以很好的使用它,那么如何更好的使用呢?就需要知道DUBBO的各个配置项,以及它可以通过哪些途径进行配置。个人对配置的理解,就好比时对动物的驯服,如何很好的驯服一头猛兽,那就需要知道它各种习性,从而调整,已达到自己期望的结果。这篇不对DUBBO有哪些配置项可以配置,但是通过这篇文章,你应该能够知道DUBBO可以进行哪些配置。本文会通过分析DUBBO加载配置源码的分析,来使得大家对DUBBO的配置一块有更加深入的了解。从而达到“驯服”DUBBO,以使得它成为你们自己的DUBBO。

DUBBO在配置这一块做的确实很完美,提供很很多参数,以及提供了多种渠道。下面进入正题,看看DUBBO怎么加载配置的。在讲这些之前,先给大家介绍一下在DUBBO源码层面定义了哪些类来存储各个模块的配置项,从而了解DUBBO可以对哪些模块进行配置。 ##哪些东西可以配置## 由于大部分项目都会使用Spring,而且DUBBO也提供了通过Spring来进行配置,那么先从这里进行着手。DUBBO加载Spring的集成时在dubbo-config下面的dubbo-config-spring模块下面,其中有一个类DubboNamespaceHandler,它实现了Spring提供的接口NamespaceHandlerSupport。那么Spring怎么发现整个实现类的呢?在该模块的META-INF文件夹下有两个文件: spring.handlers和spring.schemas,这两个文件里面制定了dubbo的namespace的XSD文件的位置以及dubbo的namespace由DubboNamespaceHandler来处理解析。说了这么多废话,只是想说明Spring是怎么解析<dubbo:.../>配置的。

知道了DUBBO和Spring关于配置一块时怎么整合的之后,那么你应该就不会诧异Spring怎么那么聪明,能够解析dubbo的namespace。接下来看看DubboNamespaceHandler类里面有什么东西。

<!--lang:java-->
public class DubboNamespaceHandler extends NamespaceHandlerSupport {

	static {
		Version.checkDuplicate(DubboNamespaceHandler.class);
	}

	public void init() {
	    registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
    }

}

可以看到再init方法里面都是调用一个方法registerBeanDefinitionParser,但是参数略微有些不同。registerBeanDefinitionParser方法的第一个参数是dubbo的namespace下面节点名称,第二个参数时该节点由谁来进行解析。例如:registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));是解析<dubbo:application../>配置信息的,依此类推通过Spring可以配置<dubbo:module../>,<dubbo:registry../>等等,就不一一列举了。至于每个标签配置的作用,由于不是本篇的内容,所以这里就不做过多的介绍。

通过上面应该清楚知道DUBBO可以配置哪些?这个问题应该不会再困扰你了。下面看看DUBBO是怎么加载这些配置项的。 ##如何读取我们的配置## ###通过Spring的Bean配置读取### 在项目中,会配置Spring的XML(虽然DUBBO也支持注解形式,但是个人不是很推崇,因为这样会将DUBBO整合到你的项目源码里面,而我的建议是不要讲DUBBO和你的项目绑的太紧,我的建议是DUBBO的配置和项目隔离,从而方便管理,加入以后项目不使用DUBBO,而使用其他的分布式RPC框架,对项目的调整会比较小),比如经常会通过下面的配置项引用一个远程的服务:

<!--lang:xml-->
<dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" timeout="2000" check="false"/>

通过上面的内容,应该知道dubbo:reference将会由new DubboBeanDefinitionParser(ReferenceBean.class, false)来解析(虽然看上去貌似所有配置都是用DubboBeanDefinitionParser来解析,但是有很大的不同)。那看看类DubboBeanDefinitionParser里面做了什么事情。

<!--lang:java-->
public class DubboBeanDefinitionParser implements BeanDefinitionParser {

private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);

private final Class<?> beanClass;

private final boolean required;

public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
    this.beanClass = beanClass;
    this.required = required;
}

public BeanDefinition parse(Element element, ParserContext parserContext) {
    return parse(element, parserContext, beanClass, required);
}
@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {....}
}

首先看类的定义,DubboBeanDefinitionParser实现了Spring的BeanDefinitionParser接口,该接口时专门用来解析Bean的定义的(一看类名就应该知道),并且实现了public BeanDefinition parse(Element element, ParserContext parserContext)方法(别看整个方法返回了一个BeanDefinition对象,其实Spring并没有利用整个返回的对象,具体你可以看看Spring的源码,所以要把Bean的定义注入到Spring容器中,就需要手动的往Spring中注入,因为Spring没有给我们来做这件事请。),然后调用了静态方法private static BeanDefinition parse(...),那么该类主要就是在静态的方法parse上了。由于该方法内容实在是太长了,不便粘贴出全部内容,我只分析主要的部分。在DubboBeanDefinitionParser构造方法参数上有一个Class<?> beanClass参数,它就是指定讲当前标签配置内容转换成对应类的BeanDefinition并且注入到Spring容器中。

<!--lang:java-->
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
    RootBeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClass(beanClass);
    beanDefinition.setLazyInit(false);
    String id = element.getAttribute("id");
    if ((id == null || id.length() == 0) && required) {
    	//构造一个Bean的ID
    }
    ....
    parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
    ....
     for (Method setter : beanClass.getMethods()) {
        String name = setter.getName();
        if (name.length() > 3 && name.startsWith("set")
                && Modifier.isPublic(setter.getModifiers())
                && setter.getParameterTypes().length == 1) {
            Class<?> type = setter.getParameterTypes()[0];
            String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
            props.add(property);
            Method getter = null;
            try {
                getter = beanClass.getMethod("get" + name.substring(3), new Class<?>[0]);
            } catch (NoSuchMethodException e) {
                try {
                    getter = beanClass.getMethod("is" + name.substring(3), new Class<?>[0]);
                } catch (NoSuchMethodException e2) {
                }
            }
            if (getter == null 
                    || ! Modifier.isPublic(getter.getModifiers())
                    || ! type.equals(getter.getReturnType())) {
                continue;
            }
            if ("parameters".equals(property)) {
                parameters = parseParameters(element.getChildNodes(), beanDefinition);
            } else if ("methods".equals(property)) {
                parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
            } else if ("arguments".equals(property)) {
                parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
            }
        .....
        beanDefinition.getPropertyValues().addPropertyValue(property, reference);
        ......

上面代码很显然看到是通过反射的形式获取类的get/set方法然,从而判断该参数是否可以通过Spring注入进去,最后添加到beanDefinition中,并且注入到Spring容器中。上面则是从Spring中加载配置的机制。 ###通过java运行命令-D以及properties中获取配置### 上面内容看到DUBBO可以对哪些模块进行配置,并且通过哪些类来存储这些配置信息,例如:ReferenceBean,RegistryConfig,ServiceBean等,如果进去看看这些类的定义会发现他们都继承了AbstractConfig抽象类,该抽象类中定义了protected static void appendProperties(AbstractConfig config)方法,参数时一个实现它自己的子类,接下来看看它做了什么:

<!--lang:java-->
protected static void appendProperties(AbstractConfig config) {
    if (config == null) {
        return;
    }
    String prefix = "dubbo." + getTagName(config.getClass()) + ".";
    Method[] methods = config.getClass().getMethods();
    for (Method method : methods) {
        try {
            String name = method.getName();
            if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers()) 
                    && method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) {
                String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");

                String value = null;
                if (config.getId() != null && config.getId().length() > 0) {
                    String pn = prefix + config.getId() + "." + property;
                    value = System.getProperty(pn);
                    if(! StringUtils.isBlank(value)) {
                        logger.info("Use System Property " + pn + " to config dubbo");
                    }
                }
                if (value == null || value.length() == 0) {
                    String pn = prefix + property;
                    value = System.getProperty(pn);
                    if(! StringUtils.isBlank(value)) {
                        logger.info("Use System Property " + pn + " to config dubbo");
                    }
                }
                if (value == null || value.length() == 0) {
                    Method getter;
                    try {
                        getter = config.getClass().getMethod("get" + name.substring(3), new Class<?>[0]);
                    } catch (NoSuchMethodException e) {
                        try {
                            getter = config.getClass().getMethod("is" + name.substring(3), new Class<?>[0]);
                        } catch (NoSuchMethodException e2) {
                            getter = null;
                        }
                    }
                    if (getter != null) {
                        if (getter.invoke(config, new Object[0]) == null) {
                            if (config.getId() != null && config.getId().length() > 0) {
                                value = ConfigUtils.getProperty(prefix + config.getId() + "." + property);
                            }
                            if (value == null || value.length() == 0) {
                                value = ConfigUtils.getProperty(prefix + property);
                            }
                            if (value == null || value.length() == 0) {
                                String legacyKey = legacyProperties.get(prefix + property);
                                if (legacyKey != null && legacyKey.length() > 0) {
                                    value = convertLegacyValue(legacyKey, ConfigUtils.getProperty(legacyKey));
                                }
                            }
                            
                        }
                    }
                }
                if (value != null && value.length() > 0) {
                    method.invoke(config, new Object[] {convertPrimitive(method.getParameterTypes()[0], value)});
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
}

上面方法一开始是生产当前配置的前缀String prefix = "dubbo." + getTagName(config.getClass()) + ".",此处可以看到dubbo的所有配置项都是以dubbo.开始的,接下来是通过getTagName方法生成当前配置类的配置名称,进去看看getTagName是怎么为各个配置类生成各自的配置名的。

<!--lang:java-->
private static final String[] SUFFIXS = new String[] {"Config", "Bean"};
private static String getTagName(Class<?> cls) {
    String tag = cls.getSimpleName();
    for (String suffix : SUFFIXS) {
        if (tag.endsWith(suffix)) {
            tag = tag.substring(0, tag.length() - suffix.length());
            break;
        }
    }
    tag = tag.toLowerCase();
    return tag;
}

分析上面的代码很清楚的知道是怎么生成各自配置类的配置名的,比如:ReferenceBean通过该方法会返回reference。所以关于引用远程Bean的配置都是以dubbo.reference.开头的。生成当前配置类的前缀之后,那么还是按照管理反射出当前类的所有set方法,接下来就是从System.getProperty中取,如果其中没有则会从ConfigUtils.getProperty中取。其中需要注意的是:从System.getProperty中取值并没有判断当前属性是否有值(通过spring注入的),而从ConfigUtils.getProperty中取会判断是否有值,如果没有才会从其中取,这里可以说明DUBBO配置项的优先级java -D优先于Spring配置,Spring配置优先于properties文件的配置,这也符合一般项目的规则。不知道大家注意到没,不管是System.getProperty还是ConfigUtils.getProperty都会取两次,一次是String pn = prefix + config.getId() + "." + property,另一次是String pn = prefix + property,这两种的区别就是多了一个config.getId(),可能会好奇config.getId()是什么内容呢?在介绍Spring加载配置的时候,应该知道config对象其实是Spring容器里面的,那么这里的getId,其实就是我们在配置Spring的Bean时候配置的ID。例如:

<!--lang:java-->
<dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" timeout="2000" check="false" />

该配置会产生一个ReferenceBean对象,那么此时的config.getId()就是demoService。所以String pn = prefix + config.getId() + "." + property配置的目的是有没有针对当前某个Bean的配置项。比如:配置dubbo消费端的超时时间,一般通过dubbo.reference.timeout,这其实是指定消费端所有Bean的超时时间。有时候我们需要指定某个Bean超时时间可以通过dubbo.reference.{beanId}.timeout来指定,例如上面的可以通过dubbo.reference.demoService.timeout来配置该Bean的超时时间。

到此对DUBBO所有配置途径以及其原理进行了分析和介绍,貌似还没说怎么取发现dubbo有哪些配置。这里教大家怎么去发现DUBBO有哪些配置。上面介绍过,DUBBO将配置项设置到各个配置类的实体中都是通过判断是否有get/set方法,到这里大家应该清楚怎么去发现了吧?就是如果想了解dubbo某个模块的配置,直接到对应的配置类中看它有哪些字段,知道它的字段名,以及确定你要配置的范围,是全局还是某个bean,还有你想通过什么途径来配置,按照dubbo提供的规则很好确定对应的字段怎么来进行配置。那么你可能会说,字段时一个单词知道是怎么配置,那么如果字段时多个单词组合的呢?由于java的编码风格一般时驼峰格式第:第一个单词首字母小写后面单词首字母大写,那么这种情况对应dubbo来说怎么获取该配置项呢?看下面:

<!--lang:java-->
  //name是get/set方法名
 String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");

不难发现对于驼峰,dubbo时通过-字符来分割各个单词。其实到这里基本上可以很好的配置DUBBO了,但是有一个上面的途径如果需要调整参数都需要重启应用,达不到动态调整,于是dubbo为了能够满足在项目不重启的情况下可以动态的调整配置参数。

###通过DUBBO管理应用添加动态配置### 这种方式主要原理就是通过管理器将动态参数发布到注册中心(zookeeper)中,然后各个节点可以获得最新的配置变更,然后进行动态调整。想知道这一块内容,需要取看看类RegistryDirectory的实现,该类它实现了NotifyListener。那么它就可以监听到注册中心的任何变更。再了解RegistryDirectory之前,先看看DUBBO对每个服务在注册中心存储了哪些信息?如果用的时zookeeper,那么你会在每个服务节点目录下面看到一下几个目录consumers,providers,configurators,routers。其中动态配置时放在configurators节点目录下。服务消费端会监听configurators目录变更,如果变更则会调用RegistryDirectoryvoid notify(List<URL> urls)方法。监听configurators目录变更触发的void notify(List<URL> urls)方法时,urls的是类似override://...,表示将覆盖调用该服务的某些配置(dubbo中对所有的调用配置都是通过URL的形式来展示的),讲这些URL上面的参数信息替换到调用服务端的URL上面取,并且重新构造该服务的Invoke对象,从而达到更新参数的目的。

###可以给接口的方法配置参数### 整个场景在实际项目中是存在的,比如一个接口存在多个方法,有时候讲参数配置现在再接口层面还是不够的,需要精确到方法级别,例如对接口调用的超时时间设置。dubbo对与方法级别的配置提供了两种途径。 ####Spring Bean的方式配置#### 如下进行配置:

<!--lang:xml-->
<dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" timeout="2000" check="false" >
        <dubbo:method name="sayHello" timeout="1000"/>
</dubbo:reference>

通过多嵌套一个dubbo:method标签来实现。

####动态配置#### 在DUBBO的管理器提供了动态配置的功能,通过添加动态配置,以及指定通知的消费端来指定某个服务的某个方法调整参数。它那里配置的规则时方法名加配置项的名称,例如:key配置成:sayHello.timeout,value="10000"。那么管理器会在注册中心的对应服务的configurators添加一条override://...?sayHello.timeout=10000节点,指定消费端会监听到这个变更,执行上面内容的流程。

到此关于DUBBO配置已经介绍完毕,可能有一些地方还时没说明清楚,存在疑虑。如果有疑问欢迎提问或者自己取看看相关的DUBBO源码,那一定会了解更加清楚。

© 著作权归作者所有

共有 人打赏支持
Bieber
粉丝 205
博文 36
码字总数 83312
作品 1
杭州
高级程序员
加载中

评论(9)

Bieber
Bieber

引用来自“daishuli”的评论

请问,路由规则只能单个服务配置,我想提供端限制服务端的ip地址,请问该如何操作?
下面是一个javascript脚本路由规则 function route(invokers,invocation,context) { var result = new java.util.ArrayList(invokers.size()); for (i = 0; i < invokers.size(); i ++) { if ("http://10.20.160.198/wiki/display/dubbo/10.20.153.10".equals(invokers.get(i).getUrl().getHost())) { result.add(invokers.get(i)); } } return result; } (invokers,invocation,context); // 表示立即执行方法
Bieber
Bieber

引用来自“daishuli”的评论

请问,路由规则只能单个服务配置,我想提供端限制服务端的ip地址,请问该如何操作?
dubbo路由规则支持两种风格,一种是dubbo自定义表达式,这个需要了解它的表达式规则,表示不熟悉的不太好用,这个实现是在ConditionRouter里面。另一种是第三方脚本(javascript),通过用脚本定义一个路由方法,方法参数invokers(当前某个服务所有提供者的调用引用,里面包含服务信息,比如地址端口,Invoker对象集合),invocation(当前触发调用方法信息,包含方法名,方法参数,Invocation对象),context(调用上下文RpcContext对象),在脚本方法中获取这三个参数你可以做任何路由实现,比如你对方法,对接口,对服务提供者ip都可以,方法返回的值是Invoker数组(这个路由实现是在ScriptRouter里面)
daishuli
daishuli
请问,路由规则只能单个服务配置,我想提供端限制服务端的ip地址,请问该如何操作?
w
wuhao_5418
github上的最新更新时间都是2~3年前的了。
chencliff
chencliff
dubbo已经不维护了吧。我上他们网站,最新的一个版本还是2012年的,要是在项目中使用还是比较担心的。。。
老姜头
老姜头
mark
在途
在途
1
喵小强
喵小强
13马克下,年后回来看
Dubbo基本用法-Dubbo Provider配置

Dubbo基本用法 本章节主要讲述如何配置dubbo,按照配置方式上分,可以分为:XML配置,properties方式配置,注解方式配置,API调用方式配置。 按照功能角度进行划分,可以分为Dubbo Provider和...

中间件小哥
06/12
0
0
Spring+Dubbo+Zookeeper简单框架与使用

例子参考地址:http://www.cnblogs.com/Javame/p/3632473.html 一、实例搭建 1、搭建框架前先下载Zookeeper(http://mirrors.cnnic.cn/apache/zookeeper/zookeeper-3.3.6/zookeeper-3.3.6.ta......

阿阿阿阿阿局
2016/09/25
1K
1
泥沙砖瓦浆木匠/springboot-learning-example

springboot-learning-example spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践。 推荐 springcloud-learning-example spring cloud 实践学习案例 https://github...

泥沙砖瓦浆木匠
2017/03/29
0
0
高性能 RPC 框架 Dubbo 从入门到深入-服务注册中心搭建(详细)

一、前言 整体来说,一个公司业务系统的演进流程基本都是从单体应用到多应用。在单体应用时,不同业务模块相互调用直接在本地 JVM 进程内就可以完成,而变为多个应用时,相互之间进行通信的方...

加多
01/26
0
0
有经验JAVA程序员如何提升自己?

具有一到五年开发经验 需要学习内容很多 JVM/分布式/高并发/性能优化/Spring MVC/Spring Boot/Spring Cloud/MyBatis/Netty源码分析等等等 01、透彻理解Tomcat原理手写动静态资源的实现 02、分...

阿阳啊啊
2017/11/29
0
0
Dubbo 新编程模型之外部化配置

外部化配置(External Configuration) 在Dubbo 注解驱动例子中,无论是服务提供方,还是服务消费方,均需要转配相关配置Bean: @Beanpublic ApplicationConfig applicationConfig() {Appli...

田心双木
01/12
0
0
深入浅出微服务框架dubbo(二):配置篇

二、 配置篇 2.1 spring dubbo schema配置 官网文档已经很全,这里只做用途补充和实现说明。 Provider的有些配置虽然配在provider端但是需要通过注册中心传递到consumer,在consumer起作用,...

格_鲁
01/09
0
0
dubbo配置详解

一、dubbo配置之间的关系: 左边是服务提供方的相关配置,右边是服务消费方的相关配置。中间是两方的共享配置。下边是方法和方法参数的相关配置。 ReferenceConfig继承ConsumerConfig,Servi...

qq_26545305
2017/12/01
0
0
spring boot 实践学习案例--springboot-learning-example

springboot-learning-example 是 spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践。 「Spring Boot 那些事」:传送门 a. 基础 springboot 版本 1.5.1.RELEASE sp...

泥沙砖瓦浆木匠
2017/03/29
3.1K
7
MyBatis相关文档

MyBatis Generator 详解 http://blog.csdn.net/isea533/article/details/42102297 Mybatis Generator最完整配置详解 http://www.jianshu.com/p/e09d2370b796 generatorConfiguration http://......

3kqing
2016/06/22
21
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JavaEE——JavaScript

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 JavaScript 内置对象 String对象方法: date对象...

凯哥学堂
5分钟前
0
0
Git 远程代码回滚master

方式一(推荐): git revert commit-id 方式二(不推荐):不推荐原因:推送到线上后,其它开发人员需要重新clone git reset --hard commit-id git push origin HEAD --force...

浮躁的码农
5分钟前
0
0
Elasticesearch学习(7)—— ES查询与Java API的对应关系

1、普通查询 类型 ES查询语句 Java查询实现 结果 查询格式 { "query": { "bool": { "must": [], "must_not": [], "should": [], "filter": [] } }, "from": 0, "size": 10, "sort": [] } Que......

叶枫啦啦
6分钟前
4
0
getElementsByClassName()与getElementById()区别

1.document.getElementsByClassName() 返回的是数组 使用:document.getElementsByClassName("className")[0].innerText='具体内容' 2.document.getElementById() 返回的是单个元素 使用:d......

botkenni
17分钟前
0
0
MyBatis入门

一、安装 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version></dependency> 二、从 XML 中构建 SqlSessionFactory String r......

一个yuanbeth
17分钟前
0
0
聊聊spring cloud的LoadBalancerAutoConfiguration

序 本文主要研究一下spring cloud的LoadBalancerAutoConfiguration RibbonAutoConfiguration spring-cloud-netflix-ribbon-2.0.0.RC2-sources.jar!/org/springframework/cloud/netflix/ribb......

go4it
20分钟前
0
0
【转】使用Lombok来优雅的编码

前言 Lombok 是一种 Java™ 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注解实现这一目的。 正文 添加依赖 在 pom.xml 文件中添加相关依赖:...

HAVENT
22分钟前
0
0
Dubbo 源码解读 —— 可支持序列化及自定义扩展

一、概述 从源码中,我们可以看出来。目前,Dubbo 内部提供了 5 种序列化的方式,分别为 fastjson、Hessian2、Kryo、fst 及 Java原生支持的方式 。 针对不同的序列化方式,对比内容如下: 名...

Ryan-瑞恩
30分钟前
0
0
MySQL内存设置—— MySQL server has gone away

set global max_allowed_packet=268435456

一梦心草
39分钟前
0
0
推导式

列表、集合和字典推导式 列表推导式是Python最受喜爱的特性之一。它允许用户方便的从一个集合过滤元素,形成列表,在传递参数的过程中还可以修改元素。形式如下: [expr for val in collect...

火力全開
44分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部