介绍Dubbo框架知识点
- 什么是RPC?
RPC(Remote Procedure Call)是一种远程调用协议,它允许一个应用程序调用另外一个应用程序的服务,而无需手动编写网络通信和协议代码。
- 什么是RESTful?
RESTful是一种架构风格,一组架构约束条件和原则。通过RESTful风格,可以建立分布式系统和Web服务,这些系统可以通过Internet进行互操作。
- Dubbo官网
Dubbo是一款高性能,轻量级的开源Java RPC框架,是阿里巴巴SOA服务化治理方案的核心框架。官网地址:http://dubbo.apache.org/zh-cn/index.html
- 如何学习Dubbo
学习Dubbo应首先了解Java语言和Spring框架,对RPC和SOA也应有一定的了解。可以通过Dubbo官网提供的文档、示例和视频教程进行学习。另外,实践应用也是学习框架的重要方式。
- Dubbo学习路线
Dubbo学习路线应该包含以下几个方面:
- RPC和SOA的基础概念和原理
- Dubbo的核心概念和特性
- 配置和使用Dubbo
- Dubbo整合Spring框架
- 与其他框架的整合
- Dubbo的源码分析和深入调优
- Dubbo优点
- 高性能、轻量级
- 支持集群、容错、负载均衡等特性
- 提供丰富的扩展点
- 配置灵活、易于使用
- 对Spring的支持友好
- Dubbo缺点
- 对高并发的性能调优需要一定的经验和技巧
- 社区活跃度相比其他框架有些不足
- 对于初学习者而言,学习门槛有些高
- Dubbo应用实例
下面以Dubbo官方提供的示例为例,讲述Dubbo的应用实例:
Dubbo服务提供端代码:
代码语言:java复制@Service(version = "1.0.0")
public class DemoServiceImpl implements DemoService {
public String sayHello(String name) {
return "Hello " name;
}
}
Dubbo服务消费端代码:
代码语言:java复制@RestController
public class DemoAction {
@Reference(version = "1.0.0")
private DemoService demoService;
@RequestMapping("/sayHello")
public String sayHello(String name) {
return demoService.sayHello(name);
}
}
- Dubbo集成Springboot
其中Springboot是一款基于Spring的开发框架,可以简化Spring应用的开发和部署等相关工作。Dubbo集成Springboot可以使得服务的管理变得简便,使开发人员更专注于业务逻辑的开发。
Dubbo集成Springboot的示例代码:
代码语言:java复制@SpringBootApplication
public class DubboApplication {
public static void main(String[] args) {
SpringApplication.run(DubboApplication.class, args);
}
@DubboComponentScan({"com.example.dubboservice"})
public class ConsumerConfiguration {
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-consumer");
return applicationConfig;
}
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://localhost:2181");
registryConfig.setClient("curator");
return registryConfig;
}
@Bean
public ConsumerConfig consumerConfig() {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setCheck(false);
return consumerConfig;
}
@Bean
public ReferenceConfig referenceConfig() {
ReferenceConfig referenceConfig = new ReferenceConfig();
referenceConfig.setInterface(DemoService.class);
referenceConfig.setVersion("1.0.0");
referenceConfig.setTimeout(3000);
return referenceConfig;
}
}
}
源码
Dubbo源码框架
Dubbo的源码框架大致如下:
其中必须掌握的内容包括:
- container: Dubbo容器的实现
- config: 加载和解析Dubbo配置文件
- exception: Dubbo错误码规范和异常处理
- filter: Dubbo中的过滤器实现
- protocol: Dubbo协议的实现
- registry: Dubbo注册中心的实现
- rpc: Dubbo中的RPC框架和代理实现
- serialize: Dubbo中网络传输所用到的序列化/反序列化实现
接下来介绍其中的几个核心模块。
- Rpc框架
Rpc框架提供了Dubbo的核心功能,属于Dubbo的基础部分。在Dubbo中,Rpc框架被设计为一个通讯抽象层。Dubbo中支持多种RPC框架,包括Dubbo自带的Netty框架、Hessian框架等。
下面展示一个使用Netty的Rpc框架的样例:
Dubbo中的RPC框架的实现。其中,服务提供方通过实现RpcServer接口,将服务注册到Dubbo容器中;服务消费方通过实现RpcClient接口,调用已注册的服务。该示例使用Netty框架实现了Rpc框架,Netty是一种基于NIO的客户端/服务器框架,以缓冲和异步的方式处理网络通讯,具有高并发和网络吞吐量的优势
代码语言:java复制public interface RpcServer {
void start() throws Throwable;
void stop();
boolean isRunning();
void register(Object service, Class serviceClass);
int getPort();
String getHost();
}
public interface RpcClient {
Object invoke(String serviceName, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
void close();
}
public class NettyServer implements RpcServer {
@Override
public void start() throws Throwable {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new RdTxDecode())
.addLast(new RdTxEncoder())
.addLast(new RdTxServerHandler(handlerMap, serverConfig));
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = bootstrap.bind(serverConfig.getHost(), serverConfig.getPort()).sync();
channel = f.channel();
channel.closeFuture().sync();
}
@Override
public void register(Object service, Class serviceClass) {
handlerMap.put(serviceClass.getName(), service);
LOG.info("register service: {} success!", serviceClass.getSimpleName());
}
@Override
public int getPort() {
return ((InetSocketAddress) channel.localAddress()).getPort();
}
@Override
public void stop() {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public class RpcNettyClient implements RpcClient {
private final Bootstrap bootstrap;
private final String host;
private final int port;
@Override
public Object invoke(String serviceName, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable {
FullHttpRequest request = createRequest(serviceName, methodName, parameterTypes, arguments);
ChannelFuture f = bootstrap.connect(host, port).sync();
f.channel().writeAndFlush(request).sync();
DefaultFullHttpResponse response = (DefaultFullHttpResponse) rpcResponseFuture.get(5, TimeUnit.SECONDS);
String responseContent = getResponseContent(response);
if (response.status().code() == STATUS_OK) {
return JSON.parseObject(responseContent, RPCResult.class).getResult();
} else {
throw new RpcException(String.format("response err code: %s, %s", response.status().code(), responseContent));
}
}
@Override
public void close() {
workerGroup.shutdownGracefully();
}
private FullHttpRequest createRequest(String serviceName, String methodName, Class<?>[] parameterTypes, Object[] arguments) {
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, METHOD_POST, "/");
String body = JSON.toJSONString(new RPCInvocation(serializerType, serviceName, methodName, parameterTypes, arguments));
request.headers()
.set(HttpHeaderNames.CONTENT_TYPE, APPLICATION_JSON_VALUE)
.set(HttpHeaderNames.CONTENT_LENGTH, body.length())
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
request.content().writeCharSequence(body, CharsetUtil.UTF_8);
return request;
}
}
- Registry组件
Registry组件提供了服务注册和订阅功能,是实现Dubbo分布式存储服务的核心代码。
Registry组件通常会将Dubbo服务的注册信息写入到zookeeper或Redis等专门用于存储服务信息的存储引擎中。具体实现过程中,Registry组件可以创建zookeeper或Redis临时节点,以保证当提供服务节点出现故障时,Registry组件能及时的将故障服务下线,同时给客户端推播刷新服务节点的消息,拉取健康的节点列表。
Dubbo注册中心的实现,使用zookeeper作为服务注册和订阅的存储引擎。服务提供方在注册时将自己的服务地址信息存储在zookeeper上;服务消费方通过查询zookeeper获取到可用的服务节点信息,从而实现服务调用。该示例中的ZookeeperRegistry实现了RpcRegistry接口,包括服务注册和订阅两个方法。其中register方法将服务地址信息存储在zookeeper上;discover方法从zookeeper上查询指定服务的节点列表。在实际使用时,需要引入Dubbo的zookeeper依赖才能使用Dubbo的注册中心功能
下面给出一个使用zookeeper进行服务注册和订阅的示例代码:
代码语言:java复制public interface RpcRegistry {
void register(String serviceName, String serviceAddress);
List<String> discover(String serviceName);
}
public class ZookeeperRegistry implements RpcRegistry, Watcher {
private ZooKeeper zooKeeper;
@Override
public void register(String serviceName, String serviceAddress) {
String servicePath = String.format("/%s/%s", RegistryConstants.ROOT_PATH, serviceName);
try {
if (zooKeeper.exists(servicePath, false) == null) {
zooKeeper.create(servicePath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
String addressPath = zooKeeper.create(String.format("%s/%s", servicePath, RegistryConstants.ADDRESS_PATH), serviceAddress.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
LOG.info("register service address: {} success!", addressPath);
} catch (Exception ex) {
LOG.error("register service address fail: {}", serviceName, ex);
}
}
@Override
public List<String> discover(String serviceName) {
String servicePath = String.format("/%s/%s", RegistryConstants.ROOT_PATH, serviceName);
try {
List<String> addressList = zooKeeper.getChildren(servicePath, true);
if (addressList.isEmpty()) {
LOG.warn("get no service: {}", serviceName);
return null;
}
List<String> resultList = new ArrayList<>();
for (String addressNode : addressList) {
byte[] addressData = zooKeeper.getData(String.format("%s/%s", servicePath, addressNode), true, null);
resultList.add(new String(addressData));
}
LOG.info("get service: {} success, address: {}", serviceName, resultList);
return resultList;
} catch (KeeperException | InterruptedException ex) {
LOG.error("get service fail: {}", serviceName, ex);
}
return null;
}
@Override
public void process(WatchedEvent event) {
LOG.info("Registry changed: {}", event.getState());
}
}
以上就是Dubbo框架的一些知识点的介绍,深入学习这些知识点对于我们理解Dubbo框架的应用和实践会有一定的帮助