Web基础之Dubbo
Dubbo
RPC即Remote Procedure Call,即为远程调用。这和Java的远程代理RMI有点类似,不过RMI只能在Java系统之间进行调用,并且是使用序列化对象的方式进行通信。相比之下,RPC模式的Dubbo性能更高一些,由于使用HTTP进行通信,因此可以在不同语言的服务之间进行调用。
快速入门
首先导入Spring以及Dubbo相关依赖:
maven依赖
<properties>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</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-webmvc</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-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.7</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
创建公共接口并安装到maven仓库:
公共接口单独打包
package cn.bilibili.dubbo.service;
public interface HellobilibiliService {
String sayHello(String name);
}
服务方开发:
打包为war包,并在web.xml中配置监听器:
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-service.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
引入公共接口依赖并对接口进行实现:
接口实现类
package cn.bilibili.dubbo.service.impl;
import cn.bilibili.dubbo.service.HelloService;
import com.alibaba.dubbo.config.annotation.Service;
//这个Service注解是dubbo的,不是spring的
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
System.out.println("-------HelloService运行了-----------");
return "hello " + name;
}
}
创建spring配置文件,并在其中配置dubbo:
applicationContext-service.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dubdo="http://code.alibabatech.com/schema/dubbo"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 当前应用名称,用于注册中心计算应用间依赖关系,消费者和提供者应用名不能一样 -->
<dubbo:application name="dubbo-service-provider" />
<!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 注册 协议和port 端口默认是20880 -->
<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
<!-- 扫描指定包,加入@Service注解的类会被发布为服务 -->
<dubbo:annotation package="cn.bilibili.dubbo.service.impl" />
</beans>
消费方开发
在web后台中,一般是web层依赖Service,因此直接使用Controller进行调用。
创建消费方工程并打war包,然后在web.xml中配置SpringMVC:
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-consumer.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
然后创建一个Controller:
具体调用对象
@Controller
@RequestMapping("/demo")
public class HelloController {
//这里的注解是Dubbo提供
@Reference
private HelloService helloService;
@RequestMapping("/hello")
@ResponseBody
public String getName(String name){
//远程调用
String result = helloService.sayHello(name);
return result;
}
}
然后在spring中配置dubbo参数:
applicationContext-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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 -->
<dubbo:application name="dubbo-service-consumer" />
<!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 扫描的方式controller -->
<dubbo:annotation package="cn.bilibili.dubbo.controller" />
</beans>
两个Tomcat和JMX端口号不能一样。
然后便可以在浏览器访问该Controller。
dubbo还有一个叫dubbo-admin的可视化后台管理工具,可以单独运行在一个Tomcat中。
Dubbo参数调整
配置方式调整
上面使用的是包扫描的方式,其实也可以使用xml直接配置bean:
<!-- 注册一个Bean -->
<bean id="helloService" class="cn.bilibili.dubbo.service.impl.HelloServiceImpl">
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="cn.bilibili.dubbo.service.HelloService" ref="helloService"/>
消费方也可以使用xml的方式配置:
<!-- 引用远程服务代理,可以和本地bean一样使用helloService -->
<dubbo:reference id="helloService" interface="cn.bilibili.dubbo.service.HelloService"/>
在Controller中改为自动注入:
@Controller
@RequestMapping("/demo")
public class HelloController {
@Autowired
private HelloService helloService;
}
服务协议:
<dubbo:protocol name="dubbo" port="20880"/>
Dubbo支持的协议有:dubbo、rmi、hessian、http、webservice、rest、redis等。推荐使用的是dubbo协议。dubbo 协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
同一个工程中可以配置不同的协议。
启动时检查
消费方在启动时默认会检查依赖的服务是否可用,可以使用下面的方式关闭启动检查(配置在消费方):
<dubbo:consumer check="false"/>
负载均衡
在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机(random)、轮询(roundrobin)、最少活跃调用数、一致性Hash),缺省为random随机调用。
负载均衡可以在消费方配置也可以在服务方配置:
消费方:
/**
* 使用轮询负载均衡策略
* check = false 启动时候不检查服务提供者
*/
@Reference(check = false, loadbalance = "roundrobin")
private DemoService demoService;
服务方:
//在服务提供者一方配置负载均衡
@Service(loadbalance = "roundrobin")
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello " + name;
}
}
和Dubbo其他的配置类似,多个配置是有覆盖关系的:
- 方法级优先,接口级次之,全局配置再次之。
- 如果级别一样,则消费方优先,提供方次之。
所以,4种配置的优先级是:
- 客户端方法级别配置。
- 客户端接口级别配置。
- 服务端方法级别配置。
- 服务端接口级别配置。
服务超时
超时机制:在设置的超时时间内,如果 consume 端没有接收到 provider 的返回值,认为本次调用失败。默认超时时间 1秒
消费端设置超时:
//设置整个服务的超时时间为5秒
@Reference(timeout = 5000)
private HelloService helloSerice;
xml形式:
<!-- 方式一:设置整个服务的超时时间为5秒 -->
<dubbo:reference id="helloService" interface="cn.bilibili.dubbo.service.HelloService" timeout="5000"/>
<!-- 方式二:设置服务的某个具体方法的超时时间 -->
<dubbo:reference id="helloService" interface="cn.bilibili.dubbo.service.HelloService">
<!-- 设置sayHello方法的超时时间为5秒 -->
<dubbo:method name="sayHello" timeout="5000"></dubbo:method>
</dubbo:reference>
服务端设置超时:
//设置整个服务的超时时间为5秒
@Service(timeout = 5000)
public class HelloServiceImpl implements HelloService {
}
xml形式:
<!--方式一:设置整个服务的超时时间为5秒-->
<dubbo:service interface="cn.bilibili.dubbo.service.HelloService" ref="helloService" timeout="5000"/>
<!--方式二:设置服务的某个具体方法的超时时间 -->
<dubbo:service interface="cn.bilibili.dubbo.service.HelloService" ref="helloService">
<!-- 设置sayHello方法的超时时间为5秒 -->
<dubbo:method name="sayHello" timeout="5000"></dubbo:method>
</dubbo:service>
优先在服务端配置超时。
服务重试
当调用某个服务的方法失败的后, dubbo默认重试2次(不包括默认的第一次调用),在设置的重试次数内,请求都失败,认为此次请求异常,抛出异常 。我们可以通过retries参数修改重试次数。
dubbo会在服务提供端出现异常进行再次重试调用。这个并不代表服务提供端完全执行失败了。所以不是所有接口都适合重试,如果一个服务是不等幂,那么不适合重试的机制,因为会存在重复提交的问题,否则是可以进行重试的。比如提交一个订单的接口是不能进行重试的,而查询类型的接口是可以重试的。(关于幂等性可以看看MDN和这篇博客)
服务重试需要慎重使用。
消费端重试设置:
//设置整个服务失败后的重试次数为3,实际调用是4次
@Reference(retries = 3)
private HelloService helloSerice;
xml形式
<!--方式一:设置整个服务失败后的重试次数为3,实际调用是4次-->
<dubbo:reference id="helloService" interface="cn.bilibili.dubbo.service.HelloService" retries="3"/>
<!--方式二:设置服务的某个具体方法的重试次数-->
<dubbo:reference id="helloService" interface="cn.bilibili.dubbo.service.HelloService">
<!-- 设置sayHello方法的重试次数为3,实际调用是4次 -->
<dubbo:method name="sayHello" retries="3"></dubbo:method>
</dubbo:reference>
服务端设置:
//设置整个服务失败后的重试次数为3,实际调用是4次
@Service(retries = 3)
public class HelloServiceImpl implements HelloService {
}
xml形式
<!--方式一:设置整个服务失败后的重试次数为3,实际调用是4次-->
<dubbo:service interface="cn.bilibli.dubbo.service.HelloService" ref="helloService" retries="3"/>
<!--方式二:设置服务的某个具体方法的重试次数-->
<dubbo:service interface="cn.bilibili.dubbo.service.HelloService" ref="helloService">
<!-- 设置sayHello方法的重试次数为3,实际调用是4次 -->
<dubbo:method name="sayHello" retries="3"></dubbo:method>
</dubbo:service>
事务
但是我们如果在服务提供者类上加入@Transactional事务控制注解后,服务就发布不成功了。原因是事务控制的底层原理是为服务提供者类创建代理对象,而默认情况下Spring是基于JDK动态代理方式创建代理对象,而此代理对象的完整类名为com.sun.proxy.$Proxy42(最后两位数字不是固定的),导致Dubbo在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。
解决方法:
开启事务时开启proxy-target-class,强制使用cglib代理:
proxy-target-class在spring事务、aop、缓存这几块都有设置,其作用都是一样的:
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<aop:config proxy-target-class="true">
<cache:annotation-driven proxy-target-class="true"/>
然后需要在服务提供者的接口上指定服务接口类型:
//指定服务接口类型
@Service(interfaceClass = HelloService.class)
@Transactional
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello " + name;
}
}
Web基础之Dubbo的更多相关文章
- Golang友团无闻Go语言Web基础视频教程
教程内容:GO语言资料Golang友团无闻Go语言编程基础Golang友团无闻Go语言Web基础教程 Go语言Web基础教程列表:[Go Web基础]12Go Web 扩展学习.mp4[Go Web基 ...
- HT for Web基础动画介绍
在上一篇<基于HT for Web矢量实现3D叶轮旋转>一文中,我略微提了下HT for Web基础动画的相关用法,但是讲得不深入,今天就来和大家分享下HT for Web基础动画的相关介 ...
- Web基础开发最核心要解决的问题
Web基础开发要解决的问题,往往也就是那些框架出现的目的 - 要解决问题. 1. 便捷的Db操作: 2. 高效的表单处理: 3. 灵活的Url路由: 4. 合理的代码组织结构: 5. 架构延伸 缓存. ...
- web基础--html
WebBasic 1.web应用体系 课程大纲 1.web基础:做网页 2.结构: a.html 勾勒网页结构及内容 b.css ...
- java web基础环境搭建
java web基础环境包括:(1)servlet容器也即tomcat(2)jre即java程序运行环境 环境变量配置:分别下载jdk和tomcat安装包. jdk环境变量配置: 第一步:系统环境变量 ...
- Web基础知识和技术
WEB是一个外延广泛的概念,不单单指网站,乌徒帮专注拥有WEB界面的网站开发,帮助初学者或已经进入开发的朋友们提供参考讨论平台,然而并不一定能将所有的WEB知识讲全讲透,只是能满足初涉者的建站需求,能 ...
- java web基础 --- URL重定向Filter
java web基础 --- URL重定向Filter httpRequest.getRequestDispatcher("/helloWorld").forward(httpRe ...
- (0)写给Web初学者的教案-----Web基础
0,Web基础 一. What is the Web? Can It Eat? 很多同学可能都听说过一个名词叫做“Web”,这个词隐隐约约好像和我们上网相关.但是呢,又很难说的清楚.我们今天每位 ...
- web基础系列(五)---https是如何实现安全通信的
https是如何实现安全通信的 如果有不正确的地方,还望指出! web基础系列目录 总结几种常见web攻击手段极其防御方式 总结几种常见的安全算法 回顾 总结几个概念(具体描述可以看上一篇文章) 数字 ...
随机推荐
- android 简单列表对话框(AlertDialog.Builder().setItems())
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ...
- android原始sqlite中query的复杂用法
android直接执行sql是execSQL(String sql). 这个方法可以执行任意sql语句.但是改变这个不够灵活. query这个方法可以很好的解决这个问题. 执行query查询指定的数据 ...
- 转--Spring MVC : Java模板引擎 Thymeleaf (三)
原文:http://www.csdn.com/html/topnews201408/49/1349.htm 下面以构造一个表单开始,讲解 Thymeleaf的用法.为了演示方便,还是以经典的注册为例. ...
- [CEOI 2004]锯木厂选址
Description 题库链接 从山顶上到山底下沿着一条直线种植了 \(n\) 棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂. 木材只能朝山下运.山脚下有一个 ...
- python3爬虫
1.爬虫的基本原理讲解 2.Urllib库的基本使用 3.Requests库的基本使用 4.正则的基本使用 5.BeautifulSoup库的使用 6.PyQuery库的使用 √ 7.Seleni ...
- 设计模式课程 设计模式精讲 15-2 桥接模式Coding
1 代码演练 1.1 代码演练1 1.2 代码演练2 1 代码演练 1.1 代码演练1 需求: 打印出从银行获取的账号类 优点: a 假如我只用用一个银行接口 去获取账号的内容,银行实现类要有定期 ...
- CSS - 定位(position),难点
元素的定位属性主要包括定位模式和边偏移两部分. 1. 边偏移 边偏移属性 描述 top 顶端偏移量,定义元素相对于其父元素上边线的距离 bottom 底部偏移量,定义元素相对于其父元素下边线的距离 l ...
- [转]ubuntu备份与恢复
在 使用Ubuntu之前,相信很多人都有过使用Windows系统的经历.如果你备份过Windows系统,那么你一定记忆犹新:首先需要找到一个备份工 具(通常都是私有软件),然后重启电脑进入备份工具提供 ...
- ajax Ajax处理下载文件response没有反应
参考:https://blog.csdn.net/wf632856695/article/details/52040034
- 【C++】【STL】【map】基础知识干货
1.map简介 map是一种关联式容器,主要用于对数据一对一的映射. 2.map的构造 (1)头文件:#include<map> (2)定义:map<第一关键字,第二关键字> ...