Dubbo快速入门

1. Dubbo概述


官网地址:https://cn.dubbo.apache.org/zh-cn/

image-20240622223431585

Apache Dubbo 是一款高性能的轻量级的Java RPC框架,可以和Spring框架无缝集成。

本地调用:本机调用,指同个JVM内部的方法调用,例如三层架构之间的方法调用。

RPC: 远程过程调用 ,相对于本地调用而言的另外一种调用方式。它并不是某一种具体的技术实现,而是泛指一切远程调用的技术。指跨进程、跨服务器的程序调用。

RPC分类:

  • 同步调用:调用之后必须得到结果才会继续处理其它事情,比较严谨但是效率低。
  • 异步调用:调用之后可以做任何事情而不会死等结果,效率更高但是不严谨。

实现RPC技术的框架:比如Dubbo、Feign、RestTemplate…


Dubb的三大核心能力:

  • 面向接口的远程调用:被调用的类必须要有接口。
  • 智能容错和负载均衡
  • 服务自动注册和发现

Dubbo的发展史:

  • 2012年,由淘宝团队开源的一款产品,受到了市场的欢迎,很多互联网公司都在使用了,淘宝团队发现吃力不讨好,就不再升级维护了…所以就由当当牵头搞了dubbox,继续进行维护…
  • 2015年,Spring家族推出了SpringCloud微服务架构(对netflix公司提供的一套产品再封装)
  • 2018年,阿里重拾Dubbo框架,并捐献给了Apache基金会,成为了顶级项目。(性能很强)
  • 2019年,阿里推出一套整合SpringCloud微服务架构的产品(SpringCloud Alibaba)

Dubbo的架构:

image-20240622225912787

Dubbo的架构角色:Registry:注册中心,服务治理中心Provider:服务提供者,提供服务的一方(被访问的)Consumer:服务消费者,使用服务的一方Monitor:监控中心,非必须的,用于统计调用的次数
Dubbo的启动运行过程:1. 先启动注册中心Registry2. 再启动服务提供者ProviderProvider启动时,dubbo框架会自动把服务的远程访问地址,上报给Registry3. 然后启动服务消费者ConsumerConsumer启动时,dubbo框架会自动去Registry里订阅一些服务Registry会把服务的地址推送给订阅者	4. Consumer根据地址,进行远程调用
集群和分布式的概念:1.集群:把一个系统部署多分作用:提高系统的可用性,提高系统的并发量2.分布式: 把一个系统拆成多个子系统,每个子系统提高不同的功能		作用:降低系统的耦合性

2. Dubbo准备工作


在使用dubbo框架之前,有一些必要的准备工作:

  • 安装启动zookeeper
  • 安装启动dubbo管理控制台(zookeeper的可视化管理界面,非必须,仅仅是方便查看zk里的服务信息)

2.1 启动zookeeper注册中心


Dubbo官方推荐使用 zookeeper 作为注册中心。注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。

Zookeeper 是 Apacahe Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为Dubbox 服务的注册中心,工业强度较高,可用于生产环境。

注意:zookeeper默认端口2181。可能也会占用8080。

环境要求:要求JDK版本1.8;需要配置好JDK环境变量。

1、下载zk:https://archive.apache.org/dist/zookeeper/zookeeper-3.5.8/apache-zookeeper-3.5.8-bin.tar.gz

2、把zookeeper安装包,解压到一个不含中文、空格、特殊字符的目录里。

image-20240622232921850

3、在zookeeper文件夹里新建个data文件夹。

image-20240622232948690

4、在conf文件夹里,复制zoo_sample.cfg文件并重命名为zoo.cfg

image-20240622233150914

修改zoo.cfg配置,将dataDir设置为data文件夹的路径:

image-20240622233443870


5、启动zookeeper服务:双击 bin/zkServer.cmd

在zookeeper的bin目录下,有两个命令文件:

  1. zkServer.cmd:用于启动zk服务
  2. zkCli.cmd:用于启动zk客户端,会自动连接到本机的zk服务。然后通过命令操作zk里的数据

image-20240622233635585

image-20240623062145042


2.2 启动dubbo-admin 管理控制台(非必须)

1、使用前需要下载项目然后打jar包,我们这里提供好了: https://www.alipan.com/s/N163HYbMTuG

2、双击dubboAdmin.cmd文件启动管理后台

image-20240622235749263

image-20240622235841597

启动失败,比如端口冲突,可以通过log文件排查问题。

3、访问dubbo管理控制台:http://localhost:7001/,账号/密码:root

image-20240623000138799

3. Dubbo入门(Spring方式)


需求:浏览器发请求到Controller,Controlleri通过dubbo远程调用service。查询id为1的用户。

dubbo入门项目架构:

image-20240623071828900


3.1 准备数据

执行sql脚本:

CREATE DATABASE dubbo_db;
USE dubbo_db;CREATE TABLE `t_user` (`id` INT(11) NOT NULL AUTO_INCREMENT,`username` VARCHAR(20) DEFAULT NULL,`age` INT(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;INSERT INTO t_user (username, age) VALUES ('张三', 30);
INSERT INTO t_user (username, age) VALUES ('李四', 40);
INSERT INTO t_user (username, age) VALUES ('王五', 50);

3.2 创建Maven父工程

或者直接拉取我代码也可以:https://gitee.com/aopmin/dubbo-demo1-spring.git

  • 创建时不选择骨架构建
  • 创建好以后,删除多余的src目录
  • 然后在pom.xml中设置打包方式为pom,并锁定依赖如下:
<packaging>pom</packaging><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><spring.version>5.0.5.RELEASE</spring.version><dubbo.version>2.6.2</dubbo.version><zookeeper.version>3.4.7</zookeeper.version><curator.verion>4.0.1</curator.verion><mybatis.version>3.4.5</mybatis.version><mysql.version>5.1.47</mysql.version><mybatis-spring.version>1.3.2</mybatis-spring.version><druid.version>1.1.9</druid.version><log.version>1.2.17</log.version><slf4j.version>1.7.25</slf4j.version>
</properties>
<dependencyManagement><dependencies><!--SpringMVC--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!--dubbo+zk--><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>${dubbo.version}</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>${zookeeper.version}</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>${curator.verion}</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>${curator.verion}</version></dependency><!--持久层--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>${mybatis-spring.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!--日志--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency></dependencies>
</dependencyManagement>

3.3 创建公用实体类模块

  • 创建Module时,不选择骨架构建
  • 创建好以后在pom.xml中暂不需要添加依赖
  • 创建JavaBean:User类,注意:实体类要实现序列化接口
package cn.aopmin.domain;import java.io.Serializable;
// 实体类要实现序列化接口 不然远程调用会报错 
public class User implements Serializable {private Integer id;private String username;private Integer age;//get/set...
}

3.4 创建公用接口模块

image-20240623073647611

  • 创建Module时,不选择骨架构建
  • 创建好,修改pom.xml,添加依赖
<dependencies><!-- 依赖于dubbo-domain --><dependency><groupId>cn.aopmin</groupId><artifactId>dubbo1-domain</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>
  • 创建Service层接口
package cn.aopmin.service;import cn.aopmin.domain.User;public interface UserService {User findById(Integer id);
}

3.5 创建服务提供者

这个模块是服务提供者,需要在容器启动时,把服务注册到zk,所以要引入spring-webmvc 和 zookeeper,以及客户端的依赖。
在这里插入图片描述

步骤如下:

1、准备工作:创建Module,不选择骨架,然后修改pom.xml,添加依赖

<!--不配置打包方式默认就是jar--><dependencies><!--依赖于dubbo-interface--><dependency><groupId>cn.aopmin</groupId><artifactId>dubbo1-interface</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version></dependency><!--持久层的依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId></dependency><!--dubbo和zk--><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency>
</dependencies>

2、创建映射器UserDao接口,并创建映射配置文件,配置好findById功能

package cn.aopmin.mapper;import cn.aopmin.domain.User;
import org.apache.ibatis.annotations.Select;/*** @author aopmin* @date 2024/06/23*/
public interface UserMapper {@Select("select * from t_user where id = #{id}")User findById(Integer id);
}

3、创建UserServiceImpl类,实现UserService接口,使用dubbo的注解@Service注册到zk里

package cn.aopmin.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import cn.aopmin.domain.User;
import cn.aopmin.mapper.UserMapper;
import cn.aopmin.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;/*** 注意:Service层的注解,使用dubbo框架的@Service,而不是Spring的@Service*/
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic User findById(Integer id) {System.out.println("========20880============");return userMapper.findById(id);}
}

4、创建配置文件:

  • spring-dao.xml,主要配置dao层Spring和Mybatis的整合
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--1.配置数据源--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><!--设置bean的属性--><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///dubbo_db?useSSL=false"/><property name="username" value="root"/><property name="password" value="123456"/></bean><!--2.扫描映射器--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="cn.aopmin.mapper"/></bean><!--3.SqlSessionFactoryBean--><bean class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 注入数据源,ref表示引用id为dataSource的bean(引用类型)--><property name="dataSource" ref="dataSource"/><!--类型别名--><property name="typeAliasesPackage" value="cn.aopmin.domain"/></bean>
</beans>
  • spring-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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--开启组件扫描,它只扫描spring的注解--><context:component-scan base-package="cn.aopmin"/>
</beans>
  • spring-provider.xml,spring整合dubbo的配置文件,需要配置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:application name="dubbo1-provider"/><!--配置注册中心的地址:注册中心是zk--><dubbo:registry address="zookeeper://localhost:2181"/><!--配置注解扫描:扫描到一个dubbo的@Service注解,就把这个注解对应的服务暴露出去--><dubbo:annotation package="cn.aopmin.service"/>
</beans>
  • log4j.properties,日志配置文件
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=info, CONSOLE# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

5、启动服务提供者

启动服务提供者常用有两种方式:

  • 一:把提供者修改成war,然后部署到Tomcat,启动Tomcat后,IoC容器会始终存在,可以提供服务
  • 二:通过main方法直接创建IoC容器,加载所有配置文件。但需要保持容器不关闭、不销毁

我们这里采用第二种方式:创建主类并运行起来

package cn.aopmin;import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;public class ProviderApp {public static void main(String[] args) throws IOException {\//创建容器new ClassPathXmlApplicationContext("classpath:spring-*.xml");//保证容器不关闭:只要这个main方法不结束即可。可以把方法阻塞、也可以搞一个死循环//这个方法没有任何实际用处,仅仅是因为它是一个阻塞方法:如果在控制台不输出内容,方法就阻塞了->方法不会结束->容器会一直存在System.in.read();<---}
}

服务启动成功后,会把地址信息上报给注册中心:

注册中心:用于解决服务治理问题,因为微服务的地址可能是动态变化的,导致远程调用时获取地址不方便调用。

image-20240623080555288

image-20240623080607238


3.6 创建服务消费者

image-20240623111202558

此模块是服务消费者模块,是Web应用,需要引入spring-webmvc,并且在容器启动时,要去zookeeper注册中心订阅服务,需要引入zookeeper及客户端依赖。

步骤如下:

1、准备工作:创建Module,不选择骨架,修改pom.xml,设置打包方式为war,并添加依赖

<!-- 打包方式为war -->
<packaging>war</packaging><dependencies><!--依赖于dubbo-interface--><dependency><groupId>cn.aopmin</groupId><artifactId>dubbo1-interface</artifactId><version>1.0-SNAPSHOT</version></dependency><!--web层依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><!--dubbo和zk--><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency>
</dependencies>

2、创建UserController类,并添加注解:

package cn.aopmin.controller;import com.alibaba.dubbo.config.annotation.Reference;
import cn.aopmin.domain.User;
import cn.aopmin.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {/*** 注意:要使用dubbo框架的@Reference注解,而一定不能用Spring的@Autowired* 导入进来的是:com.alibaba.dubbo.config.annotation.Reference*/@Referenceprivate UserService userService;@GetMapping("/{id}")public User findById(@PathVariable("id") Integer id){return userService.findById(id);}
}

3、创建配置文件:

  • spring-consumer.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:application name="dubbo-consumer"/><!--设置注册中心的地址--><dubbo:registry address="zookeeper://localhost:2181"/><!--设置扫描的包:主要是扫描dubbo的@Service和@Reference--><dubbo:annotation package="cn.aopmin.controller"/>
    </beans>
    
  • log4j.properties,日志配置文件

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=info, CONSOLE# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
  • spring-web.xml,主要开启组件扫描,开启mvc注解驱动
<?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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--开启组件扫描--><context:component-scan base-package="cn.aopmin.controller"/><!--开启mvc注解驱动--><mvc:annotation-driven/><!--处理静态资源--><mvc:default-servlet-handler/>
</beans>

4、补全目录src\main\webapp, 在webapp里创建WEB-INF,在WEB-INF里创建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_3_1.xsd"version="3.1"><!--1.配置前端控制器--><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*:spring-*.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><!--2.配置编码过滤器:解决乱码问题--><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>

5、启动服务消费者

配置小猫:端口改成18080,访问路径改成/

image-20240623112216005

然后以debug方式启动消费者服务。

image-20240623112913196

我们的消费者服务也注册成功了:

image-20240623113211886


3.7 功能测试

测试接口:http://localhost:18080/user/1

image-20240623113634365


总结:

服务提供者:

  • Service类上加注解:dubbo框架的@Service注解
  • spring-provider.xml:
<!-- 设置应用名称:要求不重复 -->
<dubbo:application name="dubbo1-provider"/><!-- 设置注册中心的地址:zk的地址 -->
<dubbo:registry address="zookeeper://localhost:2181"/><!-- 设置扫描的包:Spring会扫描dubbo的@Service注解,扫到一个,就把它的地址向注册中心上报一下 -->
<dubbo:annotation package="cn.aopmin.service"/>

服务消费者:

  • Controller类里,要注入Service时,使用dubbo的@Reference
  • spring-consumer.xml:
<!-- 设置应用名称:要求不重复 -->
<dubbo:application name="dubbo1-consumer"/><!-- 设置注册中心的地址:zk的地址 -->
<dubbo:registry address="zookeeper://localhost:2181"/><!-- 设置扫描的包:Spring会扫描dubbo的@Reference和@Service -->
<dubbo:annotation package="cn.aopmin.controller"/>

4. Dubbo运行原理


服务暴露和服务订阅的过程。

dubbo是怎么运行的,为什么浏览器一访问,controller就可以远程调用这个service呢?

04.dubbo原理和rpc调用过程

dubbo一次RPC调用的过程:

分为四个角色:

  • Client:消费者
  • Client Stub:客户端存档,由框架实现
  • Server Stub:服务端存档,由框架实现
  • Server:提供者

image-20240623120102809·

调用过程:

  1. Client发起远程调用

    Client发起远程调用,实际上是由它的代理ClientStub实现的

    ClientStub把要调用目标类、目标方法、实参等等进行序列化,然后通过网络传递给ServerStub。

    ServerStub接收数据反序列化,再调用对应的目标类、目标方法,得到执行结果

    ServerStub把目标方法的结果进行序列化,通过网络返回给ClientStub

    ClientStub接收数据反序列化,得到结果。把这个结果返回给Client

  2. Client得到执行的结果


5. Dubbo配置详解


5.1 RPC协议和端口

配置示例:在服务提供者一方进行配置。

<!--  实际开发中,通常使用默认的dubbo协议name:协议名,写dubboport:端口,只要不冲突即可-->
<dubbo:protocol name="dubbo" port="20880"/>

5.1.1 rpc协议

rpc协议:一次RPC通信时,ClientStub和ServerStub双方必须遵循的一些格式、规范。

支持的协议有:dubbo、rmi、hessian、http。

dubbo协议:

dubbo协议:协议的名称就叫dubbo,是dubbo框架提供的,dubbo协议是dubbo框架默认使用的rpc协议。底层实现:单一长连接和NIO非阻塞通讯,传输数据采用hessian序列化方式。协议特性:适合小数据量、高并发的请求注意事项:不适合传输文件。如果要实现文件上传功能,要在服务消费者一方就直接保存文件(不要再rpc传输到提供者再保存了,会多一次rpc传输数据)

rmi协议:

rmi协议:jdk提供的底层实现:采用阻塞式短连接协议特性:比较消耗CPU资源,不适合于高并发的请求。适合请求次数很少、每次可以传输很大的数据注意事项:适合传输文件

hessian协议:

hessian协议:采用阻塞式短连接,使用Servlet暴露服务;传输数据采用hessian序列化方式使用的很少

http协议:

采用http协议进行通讯,使用json序列化方式。dubbo也可以用,但是需要额外的配置SpringCloud使用的是http作为rpc协议使用的:http协议数据冗余,传输的速度会慢一些。
实际开发中,通常使用默认的dubbo协议name:协议名,写dubboport:端口,只要不冲突即可

5.2 启动检查

配置示例:

<!--消费者配置check:表示是否开启"启动时检查"功能 true表示开启 false表示关闭。true 开启启动检查 按照顺序启动,先启动提供者后启动消费者false 关闭检查 先启动哪个都行 只要最终服务都启动就好
-->
<dubbo:consumer check="false"/>

启动检查的作用:

check属性默认值是true,它表示:

  • 当消费者启动时,立即检查依赖的服务提供者是否可用。
  • 如果服务不可用,就抛出异常,这样的话Spring初始化就会失败,报错 “No Provider” 找不到服务提供者。

image-20211119232122590


如何使用启动检查:

  • 在系统上线时,设置为true,可以帮我们尽早发现问题、解决问题;

    如果设置为true,必须先启动服务提供者,再启动服务消费者。

  • 在开发阶段时,建议设置为false,关闭检查

    如果设置为false,可以先启动提供者,也可以先启动消费者。只要最终都启动了就可以。


5.3 调用超时

配置示例:

<!--消费者配置timeout:一次rpc调用的超时时间,单位毫秒如果一次rpc调用超过这个时间了,就直接失败是服务容错的一种手段避免提供者不能及时响应、而造成资源的长时间占用如果不能及时响应,越早断开,越早释放资源
-->
<dubbo:consumer timeout="1000"/>

配置说明:

  • Dubbo在通信时,由于网络或服务端不可靠,会导致调用过程中出现不确定的阻塞状态(超时) 。为了避免超时导致客户端线程挂起处于一致等待状态,最终导致服务雪崩,我们必须要有一定的服务容错措施。
  • 设置超时时间就是服务容错的一种方式
  • dubbo的服务超时时间默认为1000ms
  • 可以在消费者一方,通过timeout属性来设置全局的超时时间,单位:毫秒;
  • 也可以提供者一方,在ServiceImpl类上通过@Service(timeout=3000)来指定某一个服务的超时时间

5.4 失败重试

配置示例:

<!--消费者配置retries:当rpc调用失败后,dubbo重试的次数有重试机制,可以提高程序的可用性但是需要注意:如果是一次插入功能,可能会重复插入第一次rpc调用:服务提供者插入保存成功了,但是因为某些原因,不能及时返回结果;第一次超时之后,dubbo会以为本次rpc调用失败,会尝试第二次rpc最终可能导致重复插入实际开发的时候,通常要开启重试机制,并且 需要开发人员保证 方法多次被调用,也不会重复插入、从而造成错误后果==>幂等性
-->
<dubbo:consumer retries="3"/>

配置说明:

  • 失败重试,其实也是服务容错的一种措施:当远程调用失败时进行重试;

  • Dubbo在通信时,客户端调用失败的话会自动切换并重试其它服务器,dubbo重试的默认值是2次,我们可以自行设置重试次数。注意:消费者第一次初始化连接不算重试次数。

image-20211119232524515

但是有时候,失败重试也会造成一些问题,例如:新增操作时调用失败重试,最终可能新增两条数据。

dubbo允许我们通过配置修改重试次数:设置为0表示只调用一次 即不再重试。


5.5 负载均衡

5.1 什么是负载均衡

负载均衡(Load Balance):其实就是将请求分摊到多个系统上进行执行,从而共同完成工作任务。我们可以有多个服务提供者共同组建一个集群来提供服务,这样的话,消费者多次调用时,会调用到哪个服务提供者呢?这就是负载均衡要解决的问题。


5.2 Dubbo的负载均衡策略

Dubbo 提供了多种均衡策略:

  • random,随机策略,是默认值
  • roundrobin,轮询策略
  • leastactive,最少活跃调用数策略
  • consistenthash,一致性Hash策略,相同参数的请求,调用同一个服务。

5.3 如何配置负载均衡策略
  • 可以在服务提供者一方,使用@Service(loadbalance="负载均衡方案")配置
  • 也可以在服务消费者一方,使用@Reference(loadbalance="负载均衡方案")配置

5.4 示例代码

下面以消费者一方配置负载均衡为例,做负载均衡效果的演示。

我们再创建一个服务提供者dubbo-provider2,里边的配置和dubbo-provider几乎完全相同,只要修改使用的rpc协议和端口,保证不冲突。

(1) 准备服务提供者集群

  1. 创建maven模块:dubbo-provider2
  2. 修改dubbo-provider2的pom.xml,从dubbo-provider里把依赖拷贝过来
  3. dubbo-provider里把src文件夹拷贝过来,粘贴到dubbo-provider2
  4. 修改dubbo-provider2里的spring-provider.xml,设置rpc的协议为dubbo、端口20881

image-20240623132703046

image-20240623131224642

  1. 运行dubbo-provider2里的DubboProviderMain2,启动服务提供者2

image-20240623131332396

  1. 为了能够区别到底哪个提供者的服务被调用到了,我们分别修改dubbo-providerdubbo-provider2里的UserServiceImpl如下:

image-20240623131519425

(2) 配置负载均衡方案

在消费者一方设置负载均衡方案,然后重启消费者服务:dubbo-consumer

image-20240623131752199

image-20240623132312522


(3)测试效果

客户端浏览器多次访问http://localhost/user/1,可以从idea控制台上看到dubbo-providerdubbo-provider2被轮流访问了。

image-20240623132331912

image-20240623132339525

总结:

dubbo的使用:

  • 准备工作:必须要启动zookeeper

  • 项目代码:

    • 服务提供者:

      一个注解:dubbo的@Service

      一个配置文件:

      <!--设置应用名称:向zk里注册时,会把这个应用名称也上报上去。这个名称和其它应用名称不重复即可-->
      <dubbo:application name="dubbo1-provider"/><!--设置注册中心的地址:要设置zk的地址。写法:zookeeper://ip:端口 -->
      <dubbo:registry address="zookeeper://localhost:2181"/><!--扫描组件:主要是扫描dubbo的@Service注解-->
      <dubbo:annotation package="com.itheima.service"/><!-- 配置rpc协议和端口:非必须,可以不配置。不配置的话就取默认的dubbo协议、20880端口-->
      <dubbo:protocol name="dubbo" port="20880"/>
      
    • 服务消费者:

      一个注解:dubbo的@Reference,可以设置负载均衡策略,默认就轮询。

      一个配置文件:

      <!--设置应用名称-->
      <dubbo:application name="dubbo1-consumer"/><!--设置注册中心的地址-->
      <dubbo:registry address="zookeeper://localhost:2181"/><!--设置扫描的包:主要是扫描dubbo的@Service和@Reference-->
      <dubbo:annotation package="com.itheima.controller"/><!--消费者的配置:非必须。如果不配置,全部都有默认值(默认值不可靠)check:是否开启“启动时检查”功能实际使用时:开启环境设置为false,生产环境设置为trueretries:当rpc调用失败后,dubbo重试的次数重试机制,可以提高程序的可用性timeout:一次rpc调用的超时时间,单位毫秒如果一次rpc调用超过这个时间了,就直接失败-->
      <dubbo:consumer check="true" retries="0" timeout="3000"/>
      

6. SpringBoot整合Dubbo


1、创建父工程dubbo-demo2-springboot:打包方式pom,引入SpringBoot父工程坐标,锁定依赖版本,删除src目录。

<packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version>
</parent><dependencyManagement><dependencies><!-- SpringBoot基础依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!--dubbo的起步依赖--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.5</version></dependency><!-- zookeeper的api管理依赖 --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version></dependency><!-- zookeeper依赖 --><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.12</version></dependency></dependencies>
</dependencyManagement>

2、创建公共子模块dubbo2-domain

  • 创建实体类User,注意:实体类要实现Serializable接口

package cn.aopmin.domain;

import java.io.Serializable;

public class User implements Serializable {

private Integer id;
private String username;
private Integer age;public Integer getId() {return id;
}public void setId(Integer id) {this.id = id;
}public String getUsername() {return username;
}public void setUsername(String username) {this.username = username;
}public Integer getAge() {return age;
}public void setAge(Integer age) {this.age = age;
}

}


<br>3、创建公共接口模块`dubbo2-interface`- 引入公共实体类模块```xml
<dependencies><dependency><groupId>cn.aopmin</groupId><artifactId>dubbo2-domain</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>
  • 创建公共接口UserService,接口里定义方法findById
package cn.aopmin.service;import cn.aopmin.domain.User;/*** @author aopmin* @date 2024/06/23*/
public interface UserService {User findById(Integer id);
}

4、创建服务提供者dubbo2-provider

  • 添加依赖:
<dependencies><!-- 引入dubbo2-interface --><dependency><groupId>cn.aopmin</groupId><artifactId>dubbo2-interface</artifactId><version>1.0-SNAPSHOT</version></dependency><!--MybatisPlus起步依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.2.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency><!--dubbo起步依赖--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><!-- zookeeper的api管理依赖 --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency><!-- zookeeper依赖 --><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></dependency>
</dependencies>
  • 配置application.yml:
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql:///dubbo_db?useSSL=falseusername: rootpassword: 123456
mybatis-plus:global-config:db-config:table-prefix: t_  #全局的表名称前缀。要求这个前缀+实体类名 要和 表名相同id-type: auto #主键策略,使用数据库自增
#dubbo服务提供者的配置:应用名称、注册中心地址、扫描的包;  可选配置:rpc协议和版本
dubbo:application:name: dubbo2-provider #应用名称,要求不重复registry:address: zookeeper://localhost:2181 #注册中心地址scan:base-packages: cn.aopmin.service #扫描的包protocol:name: dubbo  #rpc协议port: 20880  #rpc端口
  • 创建mapper接口
package cn.aopmin.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.aopmin.domain.User;/*** @author aopmin* @date 2024/06/23*/
public interface UserMapper extends BaseMapper<User> {
}
  • 创建接口实现UserServiceImpl,把服务注册到注册中心
package cn.aopmin.service.impl;import cn.aopmin.service.UserService;
import cn.aopmin.domain.User;
import cn.aopmin.mapper.UserMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;/*** @author aopmin* @date 2024/06/23*/
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic User findById(Integer id) {return userMapper.selectById(id);}
}
  • 创建引导类
package cn.aopmin;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author aopmin* @date 2024/06/23*/
@SpringBootApplication
@MapperScan("cn.aopmin.mapper")
public class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}
}

5、创建服务消费者dubbo2-consumer

  • 添加依赖
<dependencies><dependency><groupId>cn.aopmin</groupId><artifactId>dubbo2-interface</artifactId><version>1.0-SNAPSHOT</version></dependency><!--web起步依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--dubbo起步依赖--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><!-- zookeeper的api管理依赖 --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency><!-- zookeeper依赖 --><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></dependency>
</dependencies>
  • 修改配置
server:port: 80servlet:context-path: /
#dubbo的消费者配置:应用名称、注册中心地址、扫描的包; 可选配置:启动时检查、超时时间、重试次数
dubbo:application:name: dubbo2-consumer #应用名称registry:address: zookeeper://localhost:2181 #注册中心地址scan:base-packages: cn.aopmin.controller #扫描的包consumer:check: false #启动时检查timeout: 3000 #rpc调用的超时时间retries: 0 #调用失败后的生效次数
  • 编写引导类
package cn.aopmin;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author aopmin* @date 2024/06/23*/
@SpringBootApplication
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}
}
  • 创建UserController,远程调用UserService,根据id查询用户
package cn.aopmin.controller;import cn.aopmin.service.UserService;
import cn.aopmin.domain.User;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author aopmin* @date 2024/06/23*/
@RestController
@RequestMapping("/user")
public class UserController {@Referenceprivate UserService userService;@GetMapping("/{id}")public User findById(@PathVariable("id") Integer id) {return userService.findById(id);}
}

小结:

关于dubbo,需要记的内容:

  • 注意:实体类必须实现序列化接口

  • 两个注解:

    • dubbo的@Service:暴露服务的
    • dubbo的@Reference:订阅服务的
  • 两类配置:

    • 提供者配置,可以在idea里配置模板如下:
    dubbo:application:name: $applicationName$ #应用名称,要求不重复registry:address: $registryAddress$ #注册中心地址scan:base-packages: $scanPackage$ #扫描的包protocol:name: dubbo  #rpc协议port: 20880  #rpc端口
    
    • 消费者配置,可以在idea里配置模板如下:
    dubbo:application:name: $applicationName$ #应用名称registry:address: $registryAddress$ #注册中心地址scan:base-packages: $scanPackage$ #扫描的包consumer:check: false #启动时检查timeout: 3000 #rpc调用的超时时间retries: 0 #调用失败后的生效次数
    

7. 常见问题


1、实体类没有实现序列化接口

在控制台可以看到报错信息

image-20210120154058034

2、找不到服务提供者

去管理控制台dubbo-admin里检查一下有没有启动服务提供者。重启服务提供者和消费者,再测试

在控制台里会看到以下内容:

image-20210120111450285

在控制台看到以下内容:

image-20210120154259323

3、数据库驱动报错

说明数据库版本和驱动包版本不匹配。MySql软件用的是8.x版本,MySql驱动包用的5.x版本

MySql数据库用的5.7

数据库驱动包应该使用5.x

image-20210605143439297

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/357428.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机IP地址频繁变化的解决方法

勾八动态分配IP&#xff0c;让我在学习redis集群的时候&#xff0c;配置很多的IP地址&#xff0c;但是由于以下原因导致我IP频繁变动&#xff0c;报错让我烦恼&#xff01;&#xff01;&#xff01;&#xff01; 为什么虚拟机的IP地址会频繁变化&#xff1f; 虚拟机IP地址频繁…

NV-Embed论文阅读笔记

这是NVIDIA的一篇论文&#xff0c;LLM通常使用的是GPT的decoder范式作为一个生成模型&#xff0c;文章探讨如何利用这样的decoder生成模型来实现BERT这样的encoder的功能&#xff0c;即提取有效的embedding。现有的方法提取embedding的方式无非是 1 mean pooling&#xff1b; 2…

32 - 判断三角形(高频 SQL 50 题基础版)

32 - 判断三角形 select *,if(xy>z and xz>y and zy > x,Yes,No) triangle fromTriangle;

基于simulink的PEM燃料电池控制系统建模与仿真,对比PID,积分分离以及滑模控制器

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 PID控制器 4.2 积分分离PID控制器 4.3 滑模控制器 5.完整工程文件 1.课题概述 基于simulink的PEM燃料电池控制系统建模与仿真,对比PID,积分分离以及滑模控制器。 2.系统仿真结果 &#xff08;完…

2024全国高校名单发布,电子版下载!

今天&#xff0c;教育部网站发布了《全国高等学校名单》。截至2024年6月20日&#xff0c;全国高等学校共计3117所&#xff0c;其中&#xff1a;普通高等学校2868所&#xff0c;含本科学校1308所、高职&#xff08;专科&#xff09;学校1560所&#xff1b;成人高等学校249所。本…

Nikto一键扫描Web服务器(KALI工具系列三十)

目录 1、KALI LINUX 简介 2、Nikto工具简介 3、信息收集 3.1 目标IP&#xff08;服务器) 3.2kali的IP 4、操作实例 4.1 基本扫描 4.2 扫描特定端口 4.3 保存扫描结果 4.4 指定保存格式 4.5 连接尝试 4.6 仅扫描文件上传 5、总结 1、KALI LINUX 简介 Kali Linux 是一…

Django 模版变量

1&#xff0c;模版变量作用 模板变量使用“{{ 变量名 }}” 来表示模板变量前后可以有空格&#xff0c;模板变量名称&#xff0c;可以由数字&#xff0c;字母&#xff0c;下划线组成&#xff0c;不能包含空格模板变量还支持列表&#xff0c;字典&#xff0c;对象 2&#xff0c;…

平面设计软件PS/AI/ID/CDR怎么选怎么下载(附教程)

随着设计行业的普遍化&#xff0c;平面设计软件也越来越多且功能越来越强大。平面设计软件需要在电脑上运行使用&#xff0c;来进行平面画面、平面文字的设计工作。如大家所了解的&#xff0c;Adobe Photoshop、Adobe Illustrator、CorelDRAW、Adobe InDesign是平面设计中最常用…

playwright vscode 插件源码解析

Playwright vscode插件主要功能 Playwright是微软开发的一款主要用于UI自动化测试的工具&#xff0c;在vscode中上安装playwright vscode插件&#xff0c;可以运行&#xff0c;录制UI自动化测试。 playwright vscode插件主要包括两块功能&#xff0c;功能一是在Test Explorer中…

机器学习课程复习——奇异值分解

1. 三种奇异值分解 奇异值分解&#xff08;Singular Value Decomposition, SVD&#xff09;包含了&#xff1a; 完全奇异值分解&#xff08;Complete Singular Value Decomposition, CSVD&#xff09;紧奇异值分解&#xff08;Tight Singular Value Decomposition, TSVD&…

快速UDP网络连接之QUIC协议介绍

文章目录 一、QUIC协议历史1.1 问题&#xff1a;QUIC为什么在应用层实现1.2 QUIC协议相关术语1.3 QUIC和TCP对比1.4 QUIC报文格式1.4.1 QUIC报文格式-Stream帧11.4.2 QUIC报文格式-Stream帧2 二、QUIC的特点2.1 连接建立低时延&#xff0c;2.2 多路复用流复用-HTTP1.1流复用-HT…

ubuntu22.04笔记: 更换为阿里源

没有按照LTS 版本 会遇到下面问题&#xff1a; 参考&#xff1a;https://zhuanlan.zhihu.com/p/691625646 Ubuntu 22.04代号为&#xff1a;jammy Ubuntu 20.04代号为&#xff1a;focal Ubuntu 19.04代号为&#xff1a;disco Ubuntu 18.04代号为&#xff1a;bionic Ubuntu …

ReactNative和Android通信

初始化一个RN项目以后&#xff0c;接下来想要让Android与React Native通信 写一个继承自ReactContextBaseJavaModule类的子类&#xff0c;重写getName方法 package com.awesomeprojectimport android.util.Log import android.widget.Toast import com.facebook.react.bridge.…

Apache Doris 之 Docker 部署篇

前言 在现代数据驱动的商业环境中&#xff0c;实时数据分析和高并发查询能力是企业成功的关键因素之一。传统的数据仓库和分析工具在面对大规模数据处理和实时分析需求时&#xff0c;往往力不从心。Apache Doris 作为一个现代的 MPP 数据库管理系统&#xff0c;凭借其强大的查…

最新Sublime Text软件安装包分享(汉化版本)

Sublime Text 是一款广受欢迎的跨平台文本编辑器&#xff0c;专为代码、标记和散文编辑而设计。它以其简洁的用户界面、强大的功能和高性能而著称&#xff0c;深受开发者和写作者的喜爱。 一、下载地址 链接&#xff1a;https://pan.baidu.com/s/1kErSkvc7WnML7fljQZlcOg?pwdk…

监控 Prometheus源码安装实战和动态更新 Centos7

安装go环境 下载go安装包 #创建文件夹 mkdir /usr/local/software #进入文件夹 cd /usr/local/software #下载安装包 wget https://dl.google.com/go/go1.17.6.linux-amd64.tar.gz配置go环境变量 #解压 tar -zxvf go1.17.6.linux-amd64.tar.gz#配置环境变量 echo "exp…

【GD32】从零开始学兆易创新32位微处理器——RTC实时时钟+日历例程

1 简介 RTC实时时钟顾名思义作用和墙上挂的时钟差不多&#xff0c;都是用于记录时间和日历&#xff0c;同时也有闹钟的功能。从硬件实现上来说&#xff0c;其实它就是一个特殊的计时器&#xff0c;它内部有一个32位的寄存器用于计时。RTC在低功耗应用中可以说相当重要&#xf…

【调试笔记-20240619-Windows-Typescripts中类型不匹配的解决方法】

调试笔记-系列文章目录 调试笔记-20240619-Windows-Typescripts中类型不匹配的解决方法 文章目录 调试笔记-系列文章目录调试笔记-20240619-Windows-Typescripts中类型不匹配的解决方法 前言一、调试环境操作系统&#xff1a;Windows 10 专业版调试环境调试目标 二、调试步骤搜…

Linux 五种IO模型

注&#xff1a;还有一种信号驱动IO&#xff0c;使用较少暂不讨论&#xff1b; 一&#xff0c;区分阻塞、非阻塞和同步、异步 看了很多文章对这两组概念解释和对比&#xff0c;说的太复杂了&#xff0c;其实没必要&#xff0c;两句话就能说清楚。 首先&#xff0c;对于读数据rec…

Qt制作程序启动界面类QSplashScreen实例测试详解

目录 一、QSplashScreen的概述 二、QSplashScreen静态图片加载 1、主程序实现 2、mainwindow.h实现 3、mainwindows.cpp实现 三、QSplashScreen动态图片加载 1、主程序实现 2、mainwindow.h实现 3、mainwindows.cpp实现 一、QSplashScreen的概述 QSplashScreen&#x…