概述
什么是 Dubbo
Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。
在云原生时代,Dubbo 相继衍生出了 Dubbo3、Proxyless Mesh 等架构与解决方案,在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级。
dubbo 官网
tio-boot 整合 Dubbo
- 笔者对在 jfinal-aop 框架使用 dubbo 做了支持,使得使用 dubbo 方便
所以使用是需要 添加 jfinal-aop 依赖
Introduction
Dubbo 作为一款微服务框架,最重要的是向用户提供跨进程的 RPC 远程调用能力。如上图所示,Dubbo 的服务消费者(Consumer)通过一系列的工作将请求发送给服务提供者(Provider)。
为了实现这样一个目标,Dubbo 引入了注册中心(Registry)组件,通过注册中心,服务消费者可以感知到服务提供者的连接方式,从而将请求发送给正确的服务提供者。
tio-boot 整合 jfinal-aop 依赖注入示例
添加依赖
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>tio-boot</artifactId>
<version>${tio-boot.version}</version>
</dependency>
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>jfinal-aop</artifactId>
<version>1.2.6</version>
</dependency>
整合示例
编写接口
package com.litongjava.tio.duboot.demo001.service;
public interface HelloService {
String sayHello(String name);
}
编写实现类
package com.litongjava.tio.duboot.demo001.service.impl;
import com.litongjava.jfinal.aop.annotation.AService;
import com.litongjava.tio.duboot.demo001.service.HelloService;
@AService
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "Hello " + name;
}
}
编写 Controller 调用接口
package com.litongjava.tio.duboot.demo001.controller;
import com.litongjava.jfinal.aop.annotation.AAutowired;
import com.litongjava.tio.duboot.demo001.service.HelloService;
import com.litongjava.tio.http.server.annotation.RequestPath;
@RequestPath("/")
public class IndexController {
@AAutowired
private HelloService helloService;
@RequestPath()
public String index() {
return helloService.sayHello("Tong Li");
}
}
编写启动类进行扫描,注入和启动
package com.litongjava.tio.duboot.demo001;
import com.litongjava.jfinal.aop.annotation.AComponentScan;
import com.litongjava.tio.boot.TioApplication;
@AComponentScan
public class ProviderApp {
public static void main(String[] args) {
long start = System.currentTimeMillis();
TioApplication.run(ProviderApp.class, args);
long end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
}
}
访问测试 http://localhost/返回如下
Hello Tong Li
注解解释
- @AService: 这是 JFinal AOP 的一个注解,用于标记一个类为服务类(Service),并且这个类可以被 JFinal 的 AOP 容器管理。
@AService
注解的作用类似于 Spring 中的@Service
注解,它告诉框架这是一个服务层的组件,需要被框架管理和依赖注入。 - @AAutowired: 这是 JFinal AOP 中的自动注入注解,类似于 Spring 中的
@Autowired
。它用于自动将接口类型的依赖注入到类中。使用这个注解,可以让 JFinal AOP 容器自动将对应的实现类注入到标注了@AAutowired
的属性中。 - @RequestPath: 这个注解来自于 Tio-boot 框架,用于定义 HTTP 请求的路径。标记在类上时,它定义了这个类处理的请求路径的前缀;标记在方法上时,它定义了具体方法处理的请求路径。如果方法上没有指定路径,那么它会使用类上的路径作为请求路径。
- @AComponentScan: 这个注解用于指定 JFinal AOP 需要扫描的包路径。通过这个注解,框架会自动扫描并注册指定包路径下的所有组件(如
@AService
标注的类),以便实现依赖注入。
注入流程
- 扫描服务类:
@AComponentScan
会扫描指定包下的所有类,找到带有@AService
注解的类(如HelloServiceImpl
),并将它们注册到 JFinal AOP 的容器中。 - 处理依赖注入: 在
IndexController
中,由于helloService
属性被标注了@AAutowired
,JFinal AOP 会查找容器中是否有HelloService
接口的实现类。如果找到,就将这个实现类的实例(即HelloServiceImpl
)注入到helloService
属性中。 - 启动 Tio-boot:
TioApplication.run(ProviderApp.class, args);
会启动 Tio-boot 应用。这个过程中,Tio-boot 会启动一个内嵌的 HTTP 服务器,在启动过程中,所有标记了注解的类都会被加载和初始化,确保依赖注入完成后,并加载所有的控制器(如IndexController
),准备处理客户端的 HTTP 请求。
访问结果
当你访问http://localhost/
时,HTTP 请求会被路由到IndexController
的index()
方法。由于helloService
已经被注入为HelloServiceImpl
的实例,因此helloService.sayHello("Tong Li")
会调用HelloServiceImpl
的sayHello
方法,并返回"Hello Tong Li"
。最终,这个字符串会作为 HTTP 响应返回给客户端。
安装 zookpper
dubbo 使用 zookpper 作为注册中心,所以需要安装 zookeeper
- 下载 ZooKeeper
你可以从 ZooKeeper 官方网站 下载最新版本的 ZooKeeper。
mkdir /opt/package/zookeeper -p &&cd /opt/package/zookeeper
wget https://downloads.apache.org/zookeeper/zookeeper-3.7.2/apache-zookeeper-3.7.2-bin.tar.gz
- 解压
tar -zxf apache-zookeeper-3.7.2-bin.tar.gz -C /opt/
- 进入解压后的目录
cd /opt/apache-zookeeper-3.7.2-bin
- 配置 ZooKeeper
在 conf
目录下复制 zoo_sample.cfg
并重命名为 zoo.cfg
。
cp conf/zoo_sample.cfg conf/zoo.cfg
编辑 zoo.cfg
配置文件:
vi conf/zoo.cfg
根据需要修改以下配置项:
tickTime = 2000
dataDir = /var/lib/zookeeper
clientPort = 2181
- 启动 ZooKeeper
bin/zkServer.sh start
- 检查 ZooKeeper 状态
bin/zkServer.sh status
如果 ZooKeeper 正常运行,你会看到类似如下输出:
Mode: standalone
- zookeerp 端口
8080
33125
2181
- 关闭 zookeeper
bin/zkServer.sh stop
- 开机自启
zkServer.sh 命令参数
Usage: ./bin/zkServer.sh [--config <conf-dir>] {start|start-foreground|stop|version|restart|status|print-cmd}
vi /lib/systemd/system/zookeeper.service
[Unit]
Description=zookeeper
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=5s
WorkingDirectory=/opt/apache-zookeeper-3.7.2-bin
Environment="JAVA_HOME=/usr/java/jdk1.8.0_211"
ExecStart=/opt/apache-zookeeper-3.7.2-bin/bin/zkServer.sh start-foreground
[Install]
WantedBy=multi-user.target
注意上面的环境变量 JAVA_HOME
systemctl start zookeeper
systemctl enable zookeeper
systemctl status zookeeper
tio-boot 整合 Dubbo 示例
创建工程
在本示例中,我们将创建三个独立的工程:
tio-boot-dubbo-2-6-0-demo01-api
:API 模块tio-boot-dubbo-2-6-0-demo01-provider
:服务提供者模块tio-boot-dubbo-2-6-0-demo01-consumer
:服务消费者模块
tio-boot-dubbo-2-6-0-demo01-api
这个模块仅包含服务的接口定义。例如:
package com.litongjava.tio.duboot.demo001.service;
public interface HelloService {
String sayHello(String name);
}
package com.litongjava.tio.dubbo.demo001.service;
public interface HiService {
String sayHi(String name);
}
tio-boot-dubbo-2-6-0-demo01-provider
添加依赖
在服务提供者模块中,我们需要添加以下依赖:
logback-classic
:日志框架tio-boot
jfinal-aop
dubbo
(移除与spring-boot
相关的依赖)zkclient
:zookeeper 客户端
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>tio-boot-dubbo-2-6-0-demo01-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>tio-boot</artifactId>
<version>${tio-boot.version}</version>
</dependency>
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>jfinal-aop</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.9</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
配置文件
在 app.properties
中添加如下配置:
server.port=8000
app.name=service-provider
ZOOKEEPER_URL=zookeeper://192.168.3.9:2181
服务实现类
编写 HelloService
和 HiService
的实现类:
package com.litongjava.tio.dubbo.demo001.service.impl;
import com.litongjava.jfinal.aop.annotation.AService;
import com.litongjava.tio.dubbo.demo001.service.HelloService;
@AService
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "Hello " + name;
}
}
package com.litongjava.tio.dubbo.demo001.service.impl;
import com.litongjava.tio.dubbo.demo001.service.HiService;
public class HiServiceImpl implements HiService {
@Override
public String sayHi(String name) {
return "Hi " + name;
}
}
Dubbo 配置
编写 DubboProviderConfig
类进行 Dubbo 配置:
package com.litongjava.tio.dubbo.demo001.config;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ProviderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.qos.common.Constants;
import com.alibaba.dubbo.qos.server.Server;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.jfinal.aop.annotation.AInitialization;
import com.litongjava.jfinal.dubbo.DubboProvider;
import com.litongjava.tio.boot.constatns.TioBootConfigKeys;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.tio.dubbo.demo001.service.HelloService;
import com.litongjava.tio.dubbo.demo001.service.HiService;
import com.litongjava.tio.dubbo.demo001.service.impl.HelloServiceImpl;
import com.litongjava.tio.dubbo.demo001.service.impl.HiServiceImpl;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.litongjava.tio.utils.thread.TioThreadUtils;
@AConfiguration
public class DubboProviderConfig {
@AInitialization
public void config() {
// 防止 QoS 端口冲突
System.setProperty("dubbo.application.logger", "slf4j");
System.setProperty(Constants.QOS_PORT, 2223 + "");
System.setProperty(Constants.ACCEPT_FOREIGN_IP, "false");
// 创建应用配置
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName(EnvUtils.get(TioBootConfigKeys.APP_NAME));
// 创建注册中心配置
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(EnvUtils.get(TioBootConfigKeys.ZOOKEEPER_URL));
// 创建服务提供者配置
ProviderConfig providerConfig = new ProviderConfig();
// 初始化
DubboProvider.init(applicationConfig, registryConfig, providerConfig);
// 添加服务
DubboProvider.add(HelloService.class, Aop.get(HelloServiceImpl.class));
DubboProvider.add(HiService.class, Aop.get(HiServiceImpl.class));
// 导出服务
TioThreadUtils.submit(() -> {
DubboProvider.export();
// 启动后关闭 QoS 服务
Server.getInstance().stop();
});
// 服务销毁时取消导出
TioBootServer.me().addDestroyMethod(() -> {
DubboProvider.unexport();
});
}
}
启动类
编写 ProviderApp
启动类:
package com.litongjava.tio.dubbo.demo001;
import com.litongjava.jfinal.aop.annotation.AComponentScan;
import com.litongjava.tio.boot.TioApplication;
@AComponentScan
public class ProviderApp {
public static void main(String[] args) {
long start = System.currentTimeMillis();
TioApplication.run(ProviderApp.class, args);
long end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
}
}
tio-boot-dubbo-2-6-0-demo01-consumer
配置文件
在 app.properties
中添加如下配置:
server.port=7000
app.name=service-consumer
ZOOKEEPER_URL=zookeeper://192.168.3.9:2181
Dubbo 配置
编写 DubboConsumerConfig
类进行 Dubbo 配置:
package com.litongjava.tio.web.hello.config;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.qos.common.Constants;
import com.alibaba.dubbo.qos.server.Server;
import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.jfinal.aop.annotation.AInitialization;
import com.litongjava.jfinal.dubbo.Dubbo;
import com.litongjava.tio.boot.constatns.TioBootConfigKeys;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.tio.dubbo.demo001.service.HelloService;
import com.litongjava.tio.dubbo.demo001.service.HiService;
import com.litongjava.tio.utils.environment.EnvUtils;
@AConfiguration
public class DubboConsumerConfig {
@AInitialization
public void config() {
// 配置日志系统
System.setProperty("dubbo.application.logger", "slf4j");
// 防止 QoS 端口冲突
System.setProperty(Constants.QOS_PORT, 2224 + "");
System.setProperty(Constants.ACCEPT_FOREIGN_IP, "false");
// 创建应用配置
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName(EnvUtils.get(TioBootConfigKeys.APP
_NAME));
// 创建注册中心配置
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(EnvUtils.get(TioBootConfigKeys.ZOOKEEPER_URL));
// 设置 Dubbo 配置
Dubbo.setApplication(applicationConfig);
Dubbo.setRegistry(registryConfig);
// 获取服务
Dubbo.get(HelloService.class);
Dubbo.get(HiService.class);
// 启动后关闭 QoS 服务
Server.getInstance().stop();
TioBootServer.me().addDestroyMethod(() -> {
Dubbo.clear();
});
}
}
控制器类
编写 IndexController
控制器类:
package com.litongjava.tio.web.hello.controller;
import com.litongjava.jfinal.dubbo.Dubbo;
import com.litongjava.tio.dubbo.demo001.service.HelloService;
import com.litongjava.tio.dubbo.demo001.service.HiService;
import com.litongjava.tio.http.server.annotation.RequestPath;
@RequestPath("/")
public class IndexController {
@RequestPath()
public String index() {
HelloService helloService = Dubbo.get(HelloService.class);
HiService hiService = Dubbo.get(HiService.class);
return helloService.sayHello("Tong Li") + "_" + hiService.sayHi("Tong Li");
}
}
启动类
编写 ConsumerApp
启动类:
package com.litongjava.tio.web.hello;
import com.litongjava.jfinal.aop.annotation.AComponentScan;
import com.litongjava.tio.boot.TioApplication;
@AComponentScan
public class ConsumerApp {
public static void main(String[] args) {
long start = System.currentTimeMillis();
TioApplication.run(ConsumerApp.class, args);
long end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
}
}
启动流程
启动服务提供者:
ProviderApp
启动时,TioApplication.run
方法会启动 Tio 框架的内嵌服务器,并扫描带有@AService
注解的类(如HelloServiceImpl
和HiServiceImpl
)。DubboProviderConfig
类中的config()
方法会配置 Dubbo 的应用、注册中心和服务提供者,并通过DubboProvider
类的export()
方法将服务发布到注册中心。
启动服务消费者:
ConsumerApp
启动时,TioApplication.run
会启动消费者模块,并通过DubboConsumerConfig
类的config()
方法配置 Dubbo 应用和注册中心。Dubbo.get(HelloService.class)
和Dubbo.get(HiService.class)
方法会从注册中心获取服务提供者的引用,以便在消费者中调用。
服务调用流程
- 服务消费者通过
Dubbo.get(HelloService.class)
获取HelloService
的远程服务引用。 - 当消费者调用
HelloService.sayHello("Tong Li")
时,Dubbo 框架会通过注册中心获取服务提供者的地址,并将请求发送到相应的服务提供者。 - 服务提供者接收到请求后,调用
HelloServiceImpl.sayHello("Tong Li")
方法,返回结果"Hello Tong Li"
。 - 最终,消费者接收到响应,并将结果返回给调用者。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。