咱们将这个接口单独抽取出来,打成jar包被多个服务锁依赖html
Provider工程的pom文件以下:算法
<properties>
<!--2.6.4版本的duboo依赖的Spring的版本-->
<spring-version>4.3.16.RELEASE</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>com.dubbo.test</groupId>
<artifactId>00-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo的依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.4</version>
</dependency>
<!--Spring的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
</dependencies>
spring-dubbo-provider.xml的配置以下所示:spring
这里须要注意的是xml文件头的问题,必定要注意,不然启动会报异常:数据库
Exception:通配符的匹配很全面, 但没法找到元素 'dubbo:application' 的声明;express
<?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="01-first-provider"/>
<!--注册service ,其就是真正的服务提供者-->
<bean id="service" class="com.test.service.someServiceImpl"/>
<!--将service的服务暴露 肯定接口,肯定实现,使用点对点的方式链接,暂时不是用Zookeeper-->
<dubbo:service interface="com.test.service.someService" ref="service" registry="N/A" />
</beans>
启动类 providerRun以下所示apache
/** * 启动类 */
public class providerRun { public static void main(String[] args) throws IOException { //在容器启动到时候,就把咱们的服务注册到注册中心,或者称之为暴露 //建立Spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-dubbo-provider.xml"); //Spring容器启动
((ClassPathXmlApplicationContext) ac).start(); //使当前主线程阻塞,以提供持续服务
System.in.read(); } }
pom.xml内容以下:缓存
<properties>
<!--2.6.4版本的duboo依赖的Spring的版本-->
<spring-version>4.3.16.RELEASE</spring-version>
</properties> <dependencies>
<dependency>
<groupId>com.dubbo.test</groupId>
<artifactId>00-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo的依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.4</version>
</dependency>
<!--Spring的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
</dependencies>
spring-dubbo-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="01-first-consumer"/>
<!--肯定服务接口,肯定链接方式-->
<dubbo:reference id="someService" interface="com.test.service.someService" url="dubbo://localhost:20880"/>
</beans>
启动类以下所示:网络
/** * consumer启动兼服务消费类 */
public class consumerRun { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("sprin-dubbo-consumer.xml"); someService service = (someService) ac.getBean("someService"); service.hello("Toney"); } }
咱们先启动服务提供者providerRun,再启动消费者consumerRun,观察到以下信息并发
咱们经过消费者consumer在本身工程的Spring容器中获取到的someService引用,成功调用了provider工程的hello方法
至于中途是怎么调用的,就要着重关注咱们的两个spring配置文件了
在上一个案列中,咱们使用的是直连的方式创建链接,如今咱们采用ZK做为咱们的注册中心
Dubbo的注册中心官方推荐的就是Zookeeper
工程的话,复制服务提供者和消费者,稍加改动便可
pom.xml文件 增添一个依赖便可:
<!-- ZK的客户端依赖:在进入到阿帕奇孵化器后由zkClient改成curator -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
配置文件以下所示:增改
使用的是集群的方式,集群机器的前后顺序没有影响
<!--声明ZK服务中心 (单机)-->
<!--<dubbo:registry address="zookeeper://192.168.159.159:2181"/>-->
<!--第二中方式声明ZK服务中心 (单机)-->
<!--<dubbo:registry protocol="zookeeper" address="192.68.159.159:2181" />-->
<!--声明ZK服务中心,ZK集群的方式-->
<dubbo:registry address="zookeeper://192.168.159.159:2181?backup=192.168.159.169:2181,192.168.159.179:2181"/>
<!--指定实列名,指定服务接口,不指定url,默认为ZK-->
<dubbo:reference id="someService" interface="com.test.service.someService"/>
pom.xml 添加一个依赖
<!-- ZK的客户端依赖:在进入到阿帕奇孵化器后由zkClient改成curator -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
配置文件以下所示: 增改
<!--声明ZK服务中心 (单机)-->
<!--<dubbo:registry address="zookeeper://192.168.159.159:2181"/>-->
<!--第二中方式声明ZK服务中心 (单机)-->
<!--<dubbo:registry protocol="zookeeper" address="192.68.159.159:2181" />-->
<!--声明ZK服务中心,ZK集群的方式-->
<dubbo:registry address="zookeeper://192.168.159.159:2181?backup=192.168.159.169:2181,192.168.159.179:2181"/>
<!--指定实列名,指定服务接口,不指定url,默认为ZK--> <dubbo:reference id="someService" interface="com.test.service.someService"/>
咱们指定了ip为192.168.159.159这台机器上的ZK,那咱们就启动之,
详情翻阅:http://www.javashuo.com/article/p-bjtwezeg-ek.html(ZK的单机&集群环境搭建)
首运行服务提供者。其次运行服务消费者,咱们观察控制台输出
再观察消费者的控制台,我作了点修改,获得了返回值并打印:
链接单机ZK,集群ZK都已测试经过,暂时就写到这儿吧,我要作一个被写代码耽误的中华小当家(煮夫!!)
缓存嘛?就是缓存嘛!为了减小服务提供者的压力,Dubbo提供了基于结果的声明式缓存,该缓存是基于消费者端的,只须要修改消费者配置文件便可,使用很简单。
咱们就使用ZK的这个工程作演示
修改消费者的配置文件,添加如上属性便可
咱们修改消费者的启动了,对同一个函数进行两次相同的访问,以下:
而后咱们看服务的提供者,打印了几回,若是是一次的话,则 说明第二次函数的调用并无通过服务的提供者的函数
——
经过上面的两张图,就能够知道,咱们的缓存起效果了,但在这里不得不了解了解Dubbo提供了三种结果缓存机制
固然下面三个就是cache属性的值,直接指定使用哪一种缓存机制,默认是lru
lru:服务级别缓存的默认机制,该机制能够默认缓存1000个结果集,若超过,采用最近最少使用原则抛出删除缓存,以保证新的结果被缓存
threadlocal:当前线程缓存,当多个线程要对当前线程进行某一操做时首先须要查询当前线程的某个信息,经过线程缓存,能够有效减小缓存
jcache:能够桥接第三方缓存产品
Dubbo的缓存是基于结果的,是在服务的消费方的主观能动控制的,通常用于查询结果不变的场景,由于他没有缓存失效时间控制这玩意儿,只有等缓存结果满了,pop出去最近最少使用的结果,若是一个数据是变更的,那么服务消费者获取到的永远都是没有更新的数据,除非该数据被POP
Dubbo的多版本控制指的是:服务名称(即接口名)相同的状况下提供不一样的服务(实现类不一样),为服务添加一个版本号,使用"服务名称"+"版本号"的方式来肯定一个服务
多版本控制主要的应用场景:当一个接口的实现类须要升级时,咱们能够是哟个版本号进行过渡,注意版本不一样的服务之间是不能相互引用的,设想这样一个环境,一个服务的一个版本须要升级,在生产环境中通常不会一次性所有进行升级,而是在访问最少的时候先升级一部分,而后下一次访问最少的时候再升级一部分,而这一部分又一部分就可使用版本号来进行过渡
以前someService的实现类只有一个,如今咱们增长一个,用做版本演示
咱们的服务提供者由一个实现类变为了两个实现类,各自都有不一样的实现,咱们首先对其进行注册,其次在暴露服务时,指定本身的版本号
而消费者在远程调用服务的时候,指定服务的版本便可调用指定了版本号的服务
——
直接在消费端修改版本号便可消费消费相同接口下不一样的服务实现
服务分组和多版本控制的使用方式基本都是同样的,知识将version改为group就行了,可是各自适用的环境有点不一样,使用版本控制是为了升级,新版本替代老版本,老版本再也不提供服务 : version="1.0.0" 、 version="2.0.0";
分组也是相同接口给出了不一样的实现类,可是这些实现类并无谁要替换掉谁的意思,针对不一样的需求调用不一样的服务接口,他们是并存的,就像支付服务的实现,能够有微信支付,能够有支付宝支付,还能够银联,服务并存想用那个服务消费者就指定该服务所对应的分组便可 :group="pay.weixin" 、 group="pay.zhifubao"
若是咱们的服务启动过程当中须要预热事件(再启动一段时间后性能才能到达最佳状态)好比初始化缓存,等待相关资源就位等,可使用deplay进行延迟暴露
如上所示:咱们只须要在服务的提供方的<dubbo:service />标签中添加delay属性,单位毫秒
若值为正数,则表示延迟暴露多少毫秒,在指定时间后再发布服务,
若值为-1,则表示在spring初始化完成后暴露服务
不少时候一个项目会有多个注册中心
同一个服务能够注册到多个不一样地域的注册中心,为多个不一样地域的服务提供服务
修改服务提供者的配置文件,多个注册中心之间使用逗号分割,以下:
固然第二个集群是假的,知道牛啃南瓜怎么下嘴就行?固然你也可使用ZK单机模式演示
一个项目中,不一样的服务能够注册不一样的注册中心:以下
同一个消费者须要调用两个注册中心的服务,而被调用的服务的接口名,版本号,分组等是相同的,不一样中心的这个相同名称的服务CURD的是不一样的数据库,即服务名相同,可是实现是不一样的,修改服务消费者以下:
在咱们前面的Demo中,服务提供者和服务的消费者是经过zookeepeer链接协议链接上Zookeeper注册中心的
为何服务的提供者和消费者链接上Zookeeper,消费者就能够消费服务了呢?
zookeeper协议:是提供者/消费者链接注册中心的链接协议,并非提供者和消费者之间的链接协议
当消费者链接上注册中心后,在消费服务以前,首先须要链接上这个服务的提供者,虽然服务的消费者能够经过注册中心获取到服务提供者,但提供者对于消费者来讲确实透明的,消费者并不知道真正的服务提供者是谁,不过不管服务的提供者是谁,消费者都须要链接上服务的提供者才能够获取到真正的服务,而这个链接也是须要专门的连接协议的,这个协议被称为服务的暴露协议
在咱们以前的Demo中并无看到服务暴露协议的相关配置,项目也是能够运行,由于Dubbo采用了默认的暴露协议,Dubbo服务暴露协议
Dubbo服务暴露协议,适用于小数据量大并发的服务调用,以及服务消费者主机数远远大于服务提供者主机的状况,服务提供少,需求多,单个主机应对高并发。
了解内容:除了Dubbo服务暴露协议,Dubbo框架还支持另外七种服务暴露协议,Hessian协议,Http协议,RMI协议,WebService协议,THrift协议,Memcached协议,Redis协议,在实际中使用最多的就是Dubbo服务暴露协议
下面咱们以Dubbo服务暴露协议做为列子来讲明服务暴露协议的用法
在服务的提供者的Spring配置文件中注册服务暴露协议,
而后在暴露服务时具体指定所使用的已经被注册的暴露协议
2、同一服务支持多种协议(修改服务提供者的配置文件)
3、不一样服务使用不一样的协议(修改服务提供者的配置文件)
牛啃南瓜知道怎么啃就行,这里我就没作过多的演示
使得Provider实现着一开始就考虑到Provider的服务特色、服务质量等问题,由于做为服务的提供者比服务的消费者更加清楚服务的性能参数,如调用的超时时间,合理的重试次数等,在Provider配置后,Consumer不配置则会默认使用Provider端的配置值,若是Consumer没有配置,Provider也没有配置,就会使用Consumer端的全局设置,这对于Provider而言是不可控的,也是不合理的
粒度到能够针对某一个服务也能够针对服务的同时针对某一个方法(hello方法)
timeout:远程服务调用超时的时限
retries:失败重试次数,默认为2
loadbalance:负载均衡算法,默认是随机random,还能够选择轮询(roundrobin)、最不活跃优先(leastactive)等
actives:消费者最大并发调用限制,达到上限后,新的调用会被阻塞直到超时,0表示不限制
threads:用于指定服务的线程池大小
executes:一个服务并行执行的请求上限,超过上限,新请求确定被阻塞,可能阻塞到超时,该属性在<dubbo:method/>则是针对指定的方法,配置在<dubbo:service />上则是针对整个服务
参数名 | 做用范围 | 默认值 | 说明 | 备注 |
threads | provider | 200 | 业务处理线程池大小 | |
iothreads | provider | CPU+1 | io线程池大小 | |
queues | provider | 0 | 线程池队列大小,当线程池满时,排队等待执行的队列大小, 建议不要设置,当线程程池时应当即失败, 重试其它服务提供机器,而不是排队,除非有特殊需求 |
|
connections | consumer | 0 | 对每一个提供者的最大链接数, rmi、http、hessian等短链接协议表示限制链接数, Dubbo等长链接协表示创建的长链接个数 |
Dubbo协议默认共享一个长链接 |
actives | consumer | 0 | 每服务消费者每服务每方法最大并发调用数 | 0表示不限制 |
acceptes | provider | 0 | 服务提供方最大可接受链接数 | 0表示不限制 |
executes | provider | 0 | 服务提供者每服务每方法最大可并行执行请求数 | 0表示不限制 |