dubbo框架详细介绍
一、网站应用的演进
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
二、分布式架构存在的问题
分布式架构问题
分布式架构主要的难点是解决服务治理问题。
当服务越来越多将会存在如下问题:
- 服务 URL 配置管理变得非常困难,F5 硬件负载均衡器的单点压力也越来越大。
- 服务间依赖关系变得错踪复杂,分不清启动顺序和架构关系
- 服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
架构问题的解决方案
- 提供注册中心:需要一个服务注册中心,动态地注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和 Failover,降低对 F5 硬件负载均衡器的依赖,也能减少部分成本。
- 自动提供一个依赖关系图,缕清架构关系
- 实时监控:要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阈值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
三、dubbo架构
什么是dubbo?
Apache Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:
- 面向接口的远程方法调用
- 智能容错和负载均衡
- 服务自动注册和发现。
Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案、服务治理方案。
什么是RPC?
RPC 【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,是一种技术思想,而不是规范。它允许程序调用另一个地址空间(网络的另一台机器上)的过程或函数,而不用开发人员显式编码这个调用的细节。调用本地方法和调用远程方法一样。
RPC 的实现方式可以不同。例如 java 的 rmi, spring 远程调用等。
RPC 概念是在上世纪 80 年代由 Brue Jay Nelson(布鲁·杰伊·纳尔逊)提出。使用 PRC 可以将本地的调用扩展到远程调用(分布式系统的其他服务器)。
RPC 的特点
- 简单:使用简单,建立分布式应用更容易。
- 高效:调用过程看起来十分清晰,效率高。
- 通用:进程间通讯的方式,有通用的规则
RPC基本原理
PRC 调用过程:
- 调用方 client 要使用右侧 server 的功能(方法),发起对方法的调用
- client stub 是 PRC 中定义的存根,看做是 client 的助手。stub 把要调用的方法参数进行序
列化,方法名称和其他数据包装起来。 - 通过网络 socket(网络通信的技术),把方法调用的细节内容发送给右侧的 server
- server 端通过 socket 接收请求的方法名称,参数等数据,传给 stub。
- server 端接到的数据由 serverstub(server 的助手)处理,调用 server 的真正方法,处理业务
- server 方法处理完业务,把处理的结果对象(Object)交给了助手,助手把 Object 进行序
列化,对象转为二进制数据。 - server 助手二进制数据交给网络处理程序
- 通过网络将二进制数据,发送给 client。
- client 接数据,交给 client 助手。
- client 助手,接收数据通过反序列化为 java 对象(Object),作为远程方法调用结果。
dubbo的功能
面向接口的好处:
面向接口代理:调用接口的方法,在 A 服务器调用 B 服务器的方法,由 dubbo 实现对 B 的调用,无需关心实现的细节,就像 MyBatis 访问 Dao 的接口,可以操作数据库一样。不用关心 Dao 接口方法的实现。这样开发是方便,舒服的
dubbo基本架构
节点角色说明
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
调用关系说明
- 0.服务容器负责启动,加载,运行服务提供者。
- 1.服务提供者在启动时,向注册中心注册自己提供的服务。
- 2.服务消费者在启动时,向注册中心订阅自己所需的服务。
- 3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 4.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
dubbo支持的协议
支持多种协议:dubbo , hessian , rmi , http, webservice , thrift , memcached , redis。
dubbo 官方推荐使用 dubbo 协议。dubbo 协议默认端口 20880
dubbo的特点
Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。
四、dubbo实例
dubbo简单案例
实际生产应用中不会使用直连模式,此处只是为了演示dubbo的远程调用功能,实际生产中一般都要结合注册中心来使用,dubbo常用的注册中心为zookeeper注册 中心。
创建服务提供者
- 通过maven创建一个webapp应用:dubbo-direct-provider
结构如下图:
- pom文件中加入dubbo依赖
由于dubbo和spring无缝对接,所以可以使用spring直接整合dubbo使用
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>dubbo-direct-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
</dependencies>
</project>
- 创建service接口及其实现类:
接口类:SomeService.java
实现类:SomeServiceImpl.java
package org.example.service;
import org.springframework.stereotype.Service;
public interface SomeService {
public String hello(String msg);
}
package org.example.service.impl;
import org.example.service.SomeService;
public class SomeServiceImpl implements SomeService {
public String hello(String msg) {
return "hello "+msg;
}
}
- 在resources下新建dubbo的配置文件
dubbo-direct-provider.xml
配置dubbo相关参数
<?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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--声明dubbo 的服务名称,唯一应用标识-->
<dubbo:application name="dubbo-direct-provider"/>
<!--声明dubbo的协议和端口号-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--暴露服务(dubbo是基于接口提供服务的)
ref:实现类的引用
registry:由于是使用直连的方式,值为“N/A”
-->
<dubbo:service interface="org.example.service.SomeService" ref="someServiceImpl" registry="N/A"/>
<!--声明接口实现类-->
<bean id="someServiceImpl" class="org.example.service.impl.SomeServiceImpl"/>
</beans>
- 在web.xml文件中配置监听器
由于dubbo需要监听器,监控其服务动态
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--声明dubbo配置文件所在位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo-direct-provider.xml</param-value>
</context-param>
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
- 修改pom.xml文件中的打包类型为jar包,之后执行 maven 的clean和install,将服务提供者打包到maven仓库
(由于没有使用注册中心,打包到仓库是为了让服务消费者能够从仓库中依赖当前的服务提供者的接口)
<packaging>jar</packaging>
打包完成之后将打包类型还原成war包,因为我们需要启动服务提供者,为消费者提供服务。
<packaging>war</packaging>
创建服务消费者
- 通过maven创建一个webapp应用:dubbo-direct-consumer
结构如下图:
- pom文件中加入dubbo依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>dubbo-direct-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<!--添加服务提供者依赖-->
<dependency>
<groupId>org.example</groupId>
<artifactId>dubbo-direct-provider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 创建SomeController.java
package org.example.web;
import org.example.service.SomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SomeController {
@Autowired
private SomeService someService;
@RequestMapping("/hello")
public String hello(Model model) {
String word = someService.hello("word0000");
// String word = "测试";
model.addAttribute("word", word);
return "hello";
}
}
- 在resources下创建服务消费者的dubbo配置文件:
dubbo-direct-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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--配置dubbo应用名称-->
<dubbo:application name="dubbo-direct-consumer"/>
<!--配置dubbo服务-->
<!--
id:远程服务接口的bean id
interface:远程服务接口的全名
registry:由于没有使用注册中心,所以值依旧是"N/A"
url:dubbo服务路径,由于使用的是dubbo协议,所以值为:"dubbo://localhost:20880"
-->
<dubbo:reference id="someService" interface="org.example.service.SomeService" registry="N/A" url="dubbo://localhost:20880" />
</beans>
- 由于我们要使用jsp页面输出测试值,需要配置springmvc.xml
在resources下创建springmvc.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:context="http://www.springframework.org/schema/context"
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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="org.example.web"/>
<!--配置注解驱动-->
<mvc:annotation-driven/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 在web.xml文件中配置servlet映射
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置servlet映射-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置容器启动加载配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo-direct-consumer.xml,classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 创建hello.jsp文件
在webapp下创建 hello.jsp
<%--
Created by IntelliJ IDEA.
User: ghq
Date: 2021/6/19
Time: 13:41
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>${word}</h1>
</body>
</html>
配置tomcat ,启动服务
注意事项:
配置tomcat时,两个服务的HTTP port和JMX port不能一样,否则端口会被占用。
启动时注意启动顺序,先启动服务提供者,再启动服务消费者
dubbo-direct-provider
dubbo-direct-consumer
启动服务消费者之后出现如下所示,表明调用成功
dubbo直连案例
使用dubbo最基本的项目结构:
- 接口工程:业务接口和实体类
- 服务提供者工程:业务接口的实现类
- 服务消费者工程:消费业务接口
代码实现
- 新建一个maven java工程,用于提供业务接口和实体类
结构如下图所示:
- 在dubbo-interface中创建一个接口和一个实体类,用于定义接口和相关实体类
接口为:SomeService.java
实体类为:User.java
package com.guo.service;
import com.guo.pojo.User;
public interface SomeService {
public String hello(String msg);
public User userInfo();
}
package com.guo.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 创建一个服务提供者工程:dubbo-provider
项目结构如下:
- pom.xml文件中加入相关依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.guo</groupId>
<artifactId>dubbo-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--dubbo依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<!--webmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!--spring -context依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!--接口jar包-->
<dependency>
<groupId>com.guo</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 在当前工程中实现业务接口:
SomeServiceImpl.java
代码如下:
package com.guo.service;
import com.guo.pojo.User;
public class SomeServiceImpl implements SomeService {
@Override
public String hello(String msg) {
return msg;
}
@Override
public User userInfo() {
User user = new User();
user.setId(1);
user.setName("张三");
user.setAge(30);
return user;
}
}
- 在resource下新建dubbo服务提供者配置文件
dubbo-provider.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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--dubbo应用名-->
<dubbo:application name="dubbo-provider"/>
<!--声明dubbo使用协议和端口号-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--暴露公有接口-->
<dubbo:service interface="com.guo.service.SomeService"
ref="someServiceImpl"
registry="N/A"/>
<!--声明接口实现类-->
<bean id="someServiceImpl" class="com.guo.service.SomeServiceImpl"/>
</beans>
- 在web.xml配置文件中配置监听器
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置文件位置声明-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo-provider.xml</param-value>
</context-param>
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
- 创建服务消费者工程
结构如下:
- 在pom.xml文件中加入依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.guo</groupId>
<artifactId>dubbo-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<dependency>
<groupId>com.guo</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 在消费者工程中创建SomeController.java,用于消费服务,给页面返回用户数据
SomeController.java
package com.guo.web;
import com.guo.pojo.User;
import com.guo.service.SomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SomeController {
@Autowired
private SomeService someService;
@RequestMapping("/hello")
public String hello(Model model) {
String hello = someService.hello("dubbo的hello测试");
model.addAttribute("hello", hello);
return "hello";
}
@RequestMapping("/user")
public String userInfo(Model model) {
User user = someService.userInfo();
model.addAttribute("user", user);
return "user";
}
}
- 配置消费者工程的dubbo配置文件
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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--声明dubbo应用-->
<dubbo:application name="dubbo-consumer"/>
<!--声明dubbo调用接口-->
<dubbo:reference id="someService"
interface="com.guo.service.SomeService"
url="dubbo://localhost:20880"
registry="N/A"/>
</beans>
- 在springmvc.xml文件中配置视图解析器
springmvc.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:context="http://www.springframework.org/schema/context"
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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="com.guo.web"/>
<!--配置注解驱动-->
<mvc:annotation-driven/>
<!--配置试图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 配置web.xml文件
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置servlet-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo-consumer.xml,classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 部署工程:先启动服务提供者,再启动服务消费者工程
得到如图所示:
zookeeper注册中心
本案例使用zookeeper作为注册中心
zookeeper注册中心简介:
Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。
zookeeper树形结构图如下:
结合dubbo的流程说明:
- 服务提供者启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址
- 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
- 监控中心启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址。
zookeeper结合dubbo实现的功能
- 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息
- 当注册中心重启时,能自动恢复注册数据,以及订阅请求
- 当会话过期时,能自动恢复注册数据,以及订阅请求
- 当设置 <dubbo:registry check=“false” /> 时,记录失败注册和订阅请求,后台定时重试
- 可通过 <dubbo:registry username=“admin” password=“1234” /> 设置 zookeeper 登录信息
- 可通过 <dubbo:registry group=“dubbo” /> 设置 zookeeper 的根节点,不配置将使用默认的根节点。
- 支持 * 号通配符 <dubbo:reference group="" version="" />,可订阅服务的所有分组和所有版本的提供者
dubbo中使用zookeeper注册中心
在使用zookeeper时需要安装zookeeper:
zookeeper安装包下载:https://zookeeper.apache.org/
注意:zookeeper的linux安装包和windows安装包为同一个。
解压下载的安装包,进入conf 目录,复制zoo_sample.cfg
,并改名为:zoo.cfg
使用编辑器打开zoo.cfg
配置文件,原始内容如下:
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=\temp\data
# the port at which the clients will connect
clientPort=2181
admin.serverPort=8888
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
修改如下内容:
-
新增端口配置:
由于zookeeper 3.5以后的版本启动时会占用8080端口,在实际的开发中8080端口我们通常用作tomcat的服务端口,需要将zookeeper占用的此端口修改为其他端口,如修改为8888端口:
在zoo.cfg配置文件中加入如下配置
admin.serverPort=8888
-
将dataDir=\temp\data修改为自定义的路径,
比如:
dataDir=D:\apache-zookeeper-3.5.9-bin\data
-
增加日志文件路径:
dataLogDir=D:\apache-zookeeper-3.5.9-bin\log
-
在apache-zookeeper-3.5.9-bin根目录下新建
data
和log
这两个文件夹,
如图所示:
修改后的配置文件如下
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=D:\apache-zookeeper-3.5.9-bin\data
dataLogDir=D:\apache-zookeeper-3.5.9-bin\log
# the port at which the clients will connect
clientPort=2181
admin.serverPort=8888
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
修改完成之后,进入bin目录点击zkServer.cmd
,启动服务
启动完毕之后,启动客户端zkCli.cmd
检测是否启动成功,
客户端显示:Welcome to ZooKeeper! 说明启动成功,启动成功的客户端显示如下:
至此,zookeeper的成功安装,成功启动
注:zookeeper的服务端口号为2181
后面的zookeeper配置会用到此端口号,用于将服务注册到zookeeper.
dubbo+zookeeper案例(重要)
(重点案例,生产环境下使用的dubbo模式)
- 新建公用的接口工程,此工程为普通maven的jar工程,结构如下:
在工程中新建一个接口类和一个实体类:
接口类:SomeService.java
实体类:User.java
由于接口中的方法和参数有可能需要用到实体对象,一般会选择将业务所需要的实体类放在接口工程中,同时可以提供给其他业务实现工程使用。
代码如下:
接口类:SomeService.java
package com.guo.service;
import com.guo.pojo.User;
public interface SomeService {
public String hello(String msg);
public User userInfo();
}
实体类:User.java
package com.guo.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 新建服务提供者工程:用于实现接口工程中的业务功能。
结构如图所示:
- 在当前工程的
pom.xml
中引入所需依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.guo</groupId>
<artifactId>dubbo-zk-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--dubbo依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<!--spring-context依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE
</version>
</dependency>
<!--spring-webmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!--zookeeper注册中心客户端依赖-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
<!--接口工程jar包-->
<dependency>
<groupId>com.guo</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
zookeeper客户端说明:
- Dubbo 支持 zkclient 和 curator 两种 Zookeeper 客户端实现
- 从 2.2.0 版本开始缺省为 zkclient 实现,以提升 zookeeper 客户端的健壮性。zkclient 是 Datameer 开源的一个 Zookeeper 客户端实现。
- 注意:在2.7.x的版本中已经移除了zkclient的实现,如果要使用zkclient客户端,需要自行拓展
- 由于接口工程和业务实现提供者工程为两个工程,所以需要引入接口工程java包:
<!--接口工程jar包-->
<dependency>
<groupId>com.guo</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 本案例使用的dubbo版本2.7.3,所以使用curator客户端
- 创建接口业务实现类:
SomeServiceImpl.java
package com.guo.service;
import com.guo.pojo.User;
public class SomeServiceImpl implements SomeService {
@Override
public String hello(String msg) {
return msg;
}
@Override
public User userInfo() {
User user = new User();
user.setId(1);
user.setName("张三");
user.setAge(25);
return user;
}
}
- 在resources下新建dubbo配置文件
dubbo-zk-provider.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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--声明dubbo服务提供者-->
<dubbo:application name="dubbo-zk-provider"/>
<!--配置dubbo协议以及端口号-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--配置注册中心-->
<dubbo:registry address="zookeeper://localhost:2181" client="curator"/>
<!--配置需要暴露的接口-->
<dubbo:service interface="com.guo.service.SomeService" ref="someService"/>
<!--配置接口实现类-->
<bean id="someService" class="com.guo.service.SomeServiceImpl"/>
</beans>
- 在web.xml文件中配置监听器
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<!--加载配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo-zk-provider.xml</param-value>
</context-param>
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
- 创建服务消费者工程,结构如图所示:
- 在pom.xml文件中引入依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.guo</groupId>
<artifactId>dubbo-zk-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--dubbo依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<!--spring-webmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!--spring-context依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!--zookeeper注册中心客户端依赖-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
<!--业务接口依赖-->
<dependency>
<groupId>com.guo</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 创建消费者controller,用于调用服务提供者的业务实现
SomeController.java
package com.guo.web;
import com.guo.pojo.User;
import com.guo.service.SomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SomeController {
@Autowired
private SomeService someService;
@RequestMapping("/hello")
public String hello(Model model) {
String hello = someService.hello("zk-dubbo-测试");
model.addAttribute("hello", hello);
return "hello";
}
@RequestMapping("/user")
public String getUser(Model model) {
User user = someService.userInfo();
model.addAttribute("user", user);
return "user";
}
}
- 在resources下创建dubbo配置文件和springmvc配置文件
dubbo-zk-consumer.xml
springmvc.xml
在dubbo-zk-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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--配置服务消费者-->
<dubbo:application name="dubbo-zk-consumer"/>
<!--配置注册中心-->
<dubbo:registry address="zookeeper://localhost:2181" client="curator"/>
<!--配置服务接口-->
<dubbo:reference id="someService" interface="com.guo.service.SomeService"/>
</beans>
在springmvc.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:context="http://www.springframework.org/schema/context"
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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="com.guo.web"/>
<!--配置注解驱动-->
<mvc:annotation-driven/>
<!--配置试图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 配置web.xml
在web.xml中配置servlet路劲映射
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo-zk-consumer.xml,classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 创建jsp文件用于视图展现,显示我们的测试数据
hello.jsp
user.jsp
hello.jsp
内容如下:
<%--
Created by IntelliJ IDEA.
User: ghq
Date: 2021/6/20
Time: 0:13
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>${hello}</h1>
</body>
</html>
uer.jsp
内容如下:
<%--
Created by IntelliJ IDEA.
User: ghq
Date: 2021/6/20
Time: 0:13
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>${user.id}</h1>
<h1>${user.name}</h1>
<h1>${user.age}</h1>
</body>
</html>
至此,整个dubbo-zookeeper项目案例整合完毕,只需配置tomcat启动服务
注意:
- 在启动项目之前先启动zookeeper服务端
- 启动项目的时候需要先启动服务提供者工程,再启动服务消费者工程
- 更多的dubbo配置请参考dubbo官网的
[参考手册]
dubbo官网:https://dubbo.apache.org/zh/
参考手册:https://dubbo.apache.org/zh/docs/v2.7/user/references/