概述
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载 Dubbo 的配置即可,Dubbo基于Spring的 Schema扩展 进行加载。
在应用中使用Dubbo,常用的方式有中三种方法,一种是API的方式,一种是注解,一种是Spring的xml配置。
下面将使用Spring的xml配置的方式演示如何快速的在应用中使用Dubbo。
准备工作
- 环境
操作系统:Win10专业版
IDE:IDEA CE 2020.1
JDK:ORACLE JDK8
Maven :3.6.2
ZooKeeper:3.4.14
- 需求
提供对用户的增删改查的服务。用户信息只有姓名、性别,根据id对用户进行删改查。简单起见,这里忽略权限认证等步骤。
- 工程规划
根据微服务架构规划,定义三个工程,实际应用中,服务API和服务提供者,很多时候可能是合并在一起的。
服务API工程coffee-api
定义用户服务接口,由服务提供者实现,并由服务消费者引用。
服务提供者工程coffee-provider
实现用户服务,真正对外提供用户服务的应用。
服务消费者工程coffee-consumer
消费用户服务,实际应用中,可能是个人中心、也可能是登录认证中心等
搭建ZooKeeper注册中心
Dubbo可以是zookeeper也可以使用redis作为注册中心,这里使用zookeeper作为注册中心。
下面是在Win10专业版中使用Hyper-V管理器创建的centos7.5虚拟机中安装zookeeper的简单步骤,供参考。假设虚拟主机ip为192.168.8.156,下面配置时会用到
-- 下载zookeeper
sudo wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
--- 解压到/opt/apache目录下
sudo mkdir /opt/apache
sudo tar -vxzf zookeeper-3.4.14.tar.gz -C /opt/apache/
-- 添加配置文件
sudo cp /opt/apache/zookeeper-3.4.14/conf/zoo_sample.cfg /opt/apache/zookeeper-3.4.14/conf/zoo.cfg
-- 启动zookeeper
cd /opt/apache/zookeeper-3.4.14/bin
// -- 如果是window操作系统 直接运行zkServer.cmd即可
sudo sh zkServer.sh start
- Window安装zookeeper
下载zookeeper压缩包后,window系统安装的话,直接解压到某个目录下即可。然后使用命令行工具运行bin目录下的zkServer.cmd即可启动zookeeper
zkServer.cmdzkServer.cmd
搭建服务API工程coffee-api
使用IDEA创建Maven工程。由于工程只是定义用户服务API,也就是用户服务接口,所以并不需要引入Dubbo依赖。
- POM文件
<?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.fandou.coffee</groupId>
<artifactId>coffee-api</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
- 定义用户服务接口
用户服务接口如下
package com.fandou.coffee.api.user;
/**
* 用户服务接口
*/
public interface UserService {
// 创建新用户
void create(User user);
// 更新用户信息
void update(User user);
// 根据id获取用户信息
User get(int id);
// 根据id删除用户
void delete(int id);
}
还有一个用户信息接口
/**
* 基本用户信息接口
*/
public interface User {
// 唯一id
int getId();
void setId(int id);
// 姓名
String getName();
void setName(String name);
// 性别
int getSex();
void setSex(int sex);
}
另外,提供一个缺省的用户实现类
package com.fandou.coffee.api.user;
import java.io.Serializable;
/**
* 缺省用户实现类
*/
public class DefaultUser implements User, Serializable {
private int id;
private String name;
private int sex;
@Override
public int getId() {
return id;
}
@Override
public void setId(int id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public int getSex() {
return sex;
}
@Override
public void setSex(int sex) {
this.sex = sex;
}
@Override
public String toString() {
return "{" +
"id=" + id +
", name='" + name + '\'' +
", sex=" + sex +
'}';
}
}
搭建服务提供者工程coffee-provider
使用IDEA创建Maven工程。需要添加用户服务API和Dubbo、zookeeper客户端以及日志依赖。
<?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.fandou.coffee</groupId>
<artifactId>coffee-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- 依赖coffee-api -->
<dependency>
<groupId>com.fandou.coffee</groupId>
<artifactId>coffee-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 依赖dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.7</version>
</dependency>
<!-- zookeeper客户端依赖 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</project>
- 实现用户服务
package com.fandou.coffee.provider.user;
import com.fandou.coffee.api.user.User;
import com.fandou.coffee.api.user.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 用户服务实现类
*/
public class UserServiceImpl implements UserService {
// 日志
private static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
@Override
public void create(User user) {
// TODO 实际开发应保存到数据库,这里只是模拟
logger.info("创建用户成功 => {}",user);
}
@Override
public void update(User user) {
logger.info("更新用户成功 => {}",user);
}
@Override
public User get(int id) {
logger.info("查询用户信息 => {}",id);
return null;
}
@Override
public void delete(int id) {
logger.info("用户已删除 => {}",id);
}
}
- Spring配置
在工程资源resources目录下创建spring目录,并在spring目录下创建xml配置文件user-service-provider.xml,其内容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/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.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 服务提供方应用名称,方便用于依赖跟踪,另外,指定使用slf4j日志而非默认的log4j-->
<dubbo:application name="user-service-provider.xml" logger="slf4j"/>
<!-- 使用本地zookeeper作为注册中心 -->
<dubbo:registry address="zookeeper://192.168.8.156:2181"/>
<!-- 使用dubbo协议,不指定port属性,默认监听20880端口:协议可以不配置,默认dubbo协议及监听20880端口-->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 定义服务实现:通过xml方式配置userService的实现bean,让Spring托管和实例化 -->
<bean id="userService" class="com.fandou.coffee.provider.user.UserServiceImpl"/>
<!-- 定义要发布/提供的服务 -->
<dubbo:service interface="com.fandou.coffee.api.user.UserService" ref="userService"/>
</beans>
- 服务提供者容器启动类
package com.fandou.coffee.provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
/**
* 启动服务提供者容器
*/
public class Application {
// 日志
private static Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/user-service-provider.xml"});
context.start();
logger.info("用户服务提供者已启动...");
System.in.read();
}
}
- 日志文件
在工程资源resources目录下日志配置文件logback.xml,配置如下
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="DefaultConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%d{HH:mm:ss.SSS,GMT+8}] %p %t %c{0}#%M@%L - %m%n</pattern>
<charset class="java.nio.charset.Charset">UTF-8</charset>
</encoder>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="DefaultConsoleAppender"/>
</root>
<!-- 关闭某个包下的日志 level="OFF" -->
<logger name="io.netty" level="OFF" />
<logger name="org.springframework" level="ERROR" />
</configuration>
搭建服务消费者工程coffee-consumer
使用IDEA创建Maven工程。需要添加用户服务API和Dubbo、zookeeper客户端、日志、junit测试依赖,不需要依赖服务提供者。
- POM文件
<?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.fandou.coffee</groupId>
<artifactId>coffee-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- 依赖coffee-api -->
<dependency>
<groupId>com.fandou.coffee</groupId>
<artifactId>coffee-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 依赖dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.7</version>
</dependency>
<!-- zookeeper客户端依赖 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
消费用户服务
package com.fandou.coffee.consumer.user.controller;
import com.fandou.coffee.api.user.User;
import com.fandou.coffee.api.user.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 用户注册功能,将调用远程的用户服务来实现
* 这里假设是SpringMVC的一个Controller类
*/
public class UserController {
// 日志
private static Logger logger = LoggerFactory.getLogger(UserController.class);
// 引用用户服务
private UserService userService;
/**
* 注册一个新用户
*/
public void registerUser(User user){
logger.info("发起注册用户请求...");
// 像本地方法一样调用远程服务
userService.create(user);
logger.info("注册用户请求完成...");
}
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
Spring配置
在工程资源resources目录下创建spring目录,并在spring目录下创建xml配置文件user-service-consumer.xml,其内容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/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.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 服务消费方应用名称,方便用于依赖跟踪 -->
<dubbo:application name="user-service-consumer" logger="slf4j">
<dubbo:parameter key="qos.enable" value="true" />
<dubbo:parameter key="qos.accept.foreign.ip" value="false" />
<!-- 配置QOS端口,由于服务提供方端已经使用了默认的22222,这里需要改用以下,否则在同一个机器同时将出现端口占用问题 -->
<dubbo:parameter key="qos.port" value="33333" />
</dubbo:application>
<!-- 使用本地zookeeper作为注册中心 -->
<dubbo:registry address="zookeeper://192.168.8.156:2181"/>
<!-- 声明或指定要消费的服务 -->
<dubbo:reference id="userService" check="false" interface="com.fandou.coffee.api.user.UserService"/>
<!-- 本地服务中调用远程服务 -->
<bean id="userController" class="com.fandou.coffee.consumer.user.controller.UserController">
<property name="userService" ref="userService" />
</bean>
</beans>
日志文件
参考服务提供者工程coffee-provider。
运行测试
- 创建测试类
在服务消费者工程coffee-consumer创建测试类UserControllerTest
package com.fandou.coffee.consumer.user.controller;
import com.fandou.coffee.api.user.DefaultUser;
import com.fandou.coffee.api.user.User;
import com.fandou.coffee.api.user.UserService;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
class UserControllerTest {
// 日志
private static Logger logger = LoggerFactory.getLogger(UserControllerTest.class);
@Test
void testRegisterUser(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/echo-consumer.xml"});
context.start();
logger.info("用户服务消费方已启动...");
// 消费方其它服务调用用户服务
UserController userController = (UserController)context.getBean("userController");
User user = new DefaultUser();
user.setId(1);
user.setName("蕃豆咖啡");
user.setSex(1);
userController.registerUser(user);
// 任何地方都可以直接调用
UserService userService = (UserService)context.getBean("userService");
User anotherUser = new DefaultUser();
anotherUser.setId(2);
anotherUser.setName("Coffee");
anotherUser.setSex(2);
userService.create(anotherUser);
}
}
- 运行测试
首先,确保zookeeper正确启动,然后运行服务提供者容器启动类Application类(即启动服务),接着运行UserControllerTest测试,控制台正常打印如下信息,说明测试成功
-- 服务消费者控制台打印
...
[18:28:05.047] INFO main UserControllerTest#testRegisterUser@19 - 用户服务消费方已启动...
[18:28:05.047] INFO main UserController#registerUser@25 - 发起注册用户请求...
[18:28:05.372] INFO main UserController#registerUser@28 - 注册用户请求完成...
...
--服务提供者控制台打印
...
[18:27:41.703] INFO main Application#main@19 - 用户服务提供者已启动...
[18:28:04.797] INFO NettyServerWorker-5-1 NettyServerHandler#channelActive@76 - [DUBBO] The connection of /169.254.186.134:53913 -> /169.254.186.134:20880 is established., dubbo version: 2.7.7, current host: 192.168.8.100
[18:28:05.328] INFO DubboServerHandler-169.254.186.134:20880-thread-2 UserServiceImpl#create@18 - 创建用户成功 => {id=1, name='蕃豆咖啡', sex=1}
[18:28:05.372] INFO DubboServerHandler-169.254.186.134:20880-thread-3 UserServiceImpl#create@18 - 创建用户成功 => {id=2, name='Coffee', sex=2}
...
总结
在应用中集成Dubbo其实比较简单,特别和Spring一起使用,很快就可以上手,核心步骤就是规划好注册中心、定义好服务接口api、构建服务提供者、构建服务消费者。Dubbo还有很多高级特性,后续在使用过程中结合业务需要去熟悉和配置。