从0到1搞一波dubbo
1、为什么需要dubbo?(为了解决什么问题?)
架构演变 |
1 单一应用架构 2 应用和数据库单独部署 3 应用和数据库集群部署 4 数据库压力变大,读写分离 5 使用缓存技术加快速度 6 数据库分库分表 7 应用分为不同的类型拆分 |
应用之间的关系已经十分复杂,产生了以下问题:
- 当服务越来越多,服务 URL 配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。
- 服务间依赖关系复杂,应用的启动顺序复杂、应用的架构关系复杂
- 服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
2、Dubbo是什么?(dubbo技术架构)
节点角色:
节点 |
角色说明 |
Provider |
暴露服务的服务提供方 |
Consumer |
调用远程服务的服务消费方 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
Container |
服务运行容器 |
Dubbo架构简单来说其实是生产者-消费者模型。进一步在这种模型上,加上了注册中心和监控中心,用于管理提供方提供的url,以及管理整个过程。
发布订阅过程:
- 启动容器,加载,运行服务提供者。
- 服务提供者在启动时,在注册中心发布注册自己提供的服务。
- 服务消费者在启动时,在注册中心订阅自己所需的服务。
如果考虑失败或变更的情况,就需要考虑下面的过程。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
3、Dubbo如何使用?
3.1 定义服务提供者
新建provider提供者模块,定义如下接口:
/** * xml方式服务提供者接口 */ public interface ProviderService { String SayHello(String word); } |
实现类
/** * xml方式服务提供者实现类 */ public class ProviderServiceImpl implements ProviderService{ public String SayHello(String word) { return word; } } |
3.2 服务暴露
导入maven依赖
<?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.test</groupId> <artifactId>dubbo-provider</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/dubbo --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.6</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.10</version> </dependency> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.5</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.32.Final</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.8.0</version> </dependency> </dependencies> </project> |
进行服务暴露:暴露接口(xml 配置方法)
首先,在项目 resource 目录下创建 META-INF.spring 包,然后再创建 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://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--> <dubbo:application name="provider" owner="cp"> <dubbo:parameter key="qos.enable" value="true"/> <dubbo:parameter key="qos.accept.foreign.ip" value="false"/> <dubbo:parameter key="qos.port" value="55555"/> </dubbo:application> <dubbo:monitor protocol="registry"/> <!--dubbo这个服务所要暴露的服务地址所对应的注册中心--> <!--<dubbo:registry address="N/A"/>--> <dubbo:registry address="N/A" /> <!--当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http--> <dubbo:protocol name="dubbo" port="20880"/> <!--服务发布的配置,需要暴露的服务接口--> <dubbo:service interface="com.dubbo.provider.service.ProviderService" ref="providerService"/> <!--Bean bean定义--> <bean id="providerService" class="com.dubbo.provider.service.ProviderServiceImpl"/> </beans> |
发布接口:通过 ClassPathXmlApplicationContext 拿到我们刚刚配置好的 xml ,然后调用 context.start() 方法启动
package com.dubbo.provider; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ProtocolConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.ServiceConfig; import com.alibaba.dubbo.container.Main; import com.dubbo.provider.service.ProviderService; import com.dubbo.provider.service.ProviderServiceImpl; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; /** * xml方式启动 * */ public class App { public static void main( String[] args ) throws IOException { //加载xml配置文件启动 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/provider.xml"); context.start(); System.in.read(); // 按任意键退出 } } |
3.2 定义消费消费者
新建消费者consumer模块,先通过点对点方式:
<?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://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--> <dubbo:application name="consumer" owner="cp"/> <!--dubbo这个服务所要暴露的服务地址所对应的注册中心--> <!--点对点的方式--> <dubbo:registry address="N/A" /> <!--<dubbo:registry address="zookeeper://localhost:2181" check="false"/>--> <!--生成一个远程服务的调用代理--> <!--点对点方式--> <dubbo:reference id="providerService" interface="com.dubbo.provider.service.ProviderService" url="dubbo://localhost:20880/com.dubbo.provider.service.ProviderService"/> <!--<dubbo:reference id="providerService" interface="com.dubbo.provider.service.ProviderService"/>--> </beans> |
导入maven依赖(同服务端类似)
<?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.test</groupId> <artifactId>dubbo-consumer</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.test</groupId> <artifactId>dubbo-provider</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/dubbo --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.6</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.10</version> </dependency> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.5</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.32.Final</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.8.0</version> </dependency> </dependencies> </project> |
调用服务
package com.dubbo.consumer; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ReferenceConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.dubbo.provider.service.ProviderService; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; /** * xml的方式调用 * */ public class App { public static void main( String[] args ) throws IOException { ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("consumer.xml"); context.start(); ProviderService providerService = (ProviderService) context.getBean("providerService"); String str = providerService.SayHello("hello"); System.out.println(str); System.in.read(); } } |
3.4 加入zookeeper作为注册中心
在前面的操作中没有使用任何注册中心,用一种直连的方式进行。实际都是使用 dubbo + zookeeper 的方式,使用 zookeeper 作为注册中心,这里介绍 zookeeper 作为注册中心的使用方法。对前面的案例进行改造:
3.4.1 服务提供者修改
修改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://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--> <dubbo:application name="provider" owner="cp"> <dubbo:parameter key="qos.enable" value="true"/> <dubbo:parameter key="qos.accept.foreign.ip" value="false"/> <dubbo:parameter key="qos.port" value="55555"/> </dubbo:application> <dubbo:monitor protocol="registry"/> <!--dubbo这个服务所要暴露的服务地址所对应的注册中心--> <!--<dubbo:registry address="N/A"/>--> <dubbo:registry address="zookeeper://localhost:2181" check="false"/> <!--当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http--> <dubbo:protocol name="dubbo" port="20880"/> <!--服务发布的配置,需要暴露的服务接口--> <dubbo:service interface="com.dubbo.provider.service.ProviderService" ref="providerService"/> <!--Bean bean定义--> <bean id="providerService" class="com.dubbo.provider.service.ProviderServiceImpl"/> </beans> |
3.4.2 服务消费者修改
修改 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://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--> <dubbo:application name="consumer" owner="cp"/> <!--dubbo这个服务所要暴露的服务地址所对应的注册中心--> <!--点对点的方式--> <!--<dubbo:registry address="N/A" />--> <dubbo:registry address="zookeeper://localhost:2181" check="false"/> <!--生成一个远程服务的调用代理--> <!--点对点方式--> <!--<dubbo:reference id="providerService" interface="com.dubbo.provider.service.ProviderService" url="dubbo://192.168.234.1:20880/com.dubbo.provider.service.ProviderService"/>--> <dubbo:reference id="providerService" interface="com.dubbo.provider.service.ProviderService"/> </beans> |
总结:加入zookeeper和直接点对点方式的区别就是:将 dubbo 发布的 url 注册到了 zookeeper,消费端从 zookeeper 消费,zookeeper 相当于一个中介,给消费者提供服务。
3.5注解配置方式
前面使用xml文件配置方式,这里使用注解配置方式,现在微服务都倾向于这种方式,这也是以后发展的趋势, 0配置是以后的趋势。那么如何对 dubbo 使用注解的方式呢?
3.5.1 服务提供者注解配置
接口:
package com.dubbo.provider.service.annotation; /** * 注解方式接口 */ public interface ProviderServiceAnnotation { String SayHelloAnnotation(String word); } |
实现类
package com.dubbo.provider.service.annotation; import com.alibaba.dubbo.config.annotation.Service; /** * 注解方式实现类 */ @Service(timeout = 5000) public class ProviderServiceImplAnnotation implements ProviderServiceAnnotation{ public String SayHelloAnnotation(String word) { return word; } } |
1
、
@Service
用来配置 Dubbo 的服务提供方。
2、通过 Spring 中 Java Config
的技术(@Configuration
)和 annotation 扫描(@EnableDubbo
)来发现、组装、并向外提供 Dubbo 的服务。
package com.dubbo.provider.configuration; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ProtocolConfig; import com.alibaba.dubbo.config.ProviderConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 注解方式配置 */ @Configuration @EnableDubbo(scanBasePackages = "com.dubbo.provider.service.annotation") public class DubboConfiguration { @Bean // #1 服务提供者信息配置 public ProviderConfig providerConfig() { ProviderConfig providerConfig = new ProviderConfig(); providerConfig.setTimeout(1000); return providerConfig; } @Bean // #2 分布式应用信息配置 public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("dubbo-annotation-provider"); return applicationConfig; } @Bean // #3 注册中心信息配置 public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setProtocol("zookeeper"); registryConfig.setAddress("localhost"); registryConfig.setPort(2181); return registryConfig; } @Bean // #4 使用协议配置,这里使用 dubbo public ProtocolConfig protocolConfig() { ProtocolConfig protocolConfig = new ProtocolConfig(); protocolConfig.setName("dubbo"); protocolConfig.setPort(20880); return protocolConfig; } } |
分析:通过 @EnableDubbo 指定在com.dubbo.provider.service.annotation 下扫描所有标注有 @Service 的类。
通过 @Configuration 将 DubboConfiguration 中所有的 @Bean 通过 Java Config 的方式组装出来并注入给 Dubbo 服务,也就是标注有 @Service 的类。这其中就包括了:
ProviderConfig:服务提供方配置
ApplicationConfig:应用配置
RegistryConfig:注册中心配置
ProtocolConfig:协议配置
启动服务:
package com.dubbo.provider; import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; import com.dubbo.provider.configuration.DubboConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import sun.applet.Main; import java.io.IOException; /** * 注解启动方式 */ public class AppAnnotation { public static void main(String[] args) throws IOException { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DubboConfiguration.class); context.start(); System.in.read(); } } |
3.5.2 服务消费者注解配置
引用服务
package com.dubbo.consumer.Annotation; import com.alibaba.dubbo.config.annotation.Reference; import com.dubbo.provider.service.annotation.ProviderServiceAnnotation; import org.springframework.stereotype.Component; /** * 注解方式的service */ @Component("annotatedConsumer") public class ConsumerAnnotationService { @Reference private ProviderServiceAnnotation providerServiceAnnotation; public String doSayHello(String name) { return providerServiceAnnotation.SayHelloAnnotation(name); } } |
引入依赖
<dependency> <groupId>com.test</groupId> <artifactId>dubbo-provider</artifactId> <version>1.0-SNAPSHOT</version> </dependency> |
组装服务端消费者
package com.dubbo.consumer.configuration; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ConsumerConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * 注解配置类 */ @Configuration @EnableDubbo(scanBasePackages = "com.dubbo.consumer.Annotation") @ComponentScan(value = {"com.dubbo.consumer.Annotation"}) public class ConsumerConfiguration { @Bean // 应用配置 public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("dubbo-annotation-consumer"); Map<String, String> stringStringMap = new HashMap<String, String>(); stringStringMap.put("qos.enable","true"); stringStringMap.put("qos.accept.foreign.ip","false"); stringStringMap.put("qos.port","33333"); applicationConfig.setParameters(stringStringMap); return applicationConfig; } @Bean // 服务消费者配置 public ConsumerConfig consumerConfig() { ConsumerConfig consumerConfig = new ConsumerConfig(); consumerConfig.setTimeout(3000); return consumerConfig; } @Bean // 配置注册中心 public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setProtocol("zookeeper"); registryConfig.setAddress("localhost"); registryConfig.setPort(2181); return registryConfig; } } |
发起调用
package com.dubbo.consumer; import com.dubbo.consumer.Annotation.ConsumerAnnotationService; import com.dubbo.consumer.configuration.ConsumerConfiguration; import com.dubbo.provider.service.ProviderService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; /** * 注解方式启动 * */ public class AppAnnotation { public static void main( String[] args ) throws IOException { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); context.start(); // 启动 ConsumerAnnotationService consumerAnnotationService = context.getBean(ConsumerAnnotationService.class); String hello = consumerAnnotationService.doSayHello("annotation"); // 调用方法 System.out.println("result: " + hello); // 输出结果 } } |
3.6 主要使用场景:
3.6.1 启动时检查
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 `check="true"。
3.6.2 集群容错
集群模式 |
说明 |
使用方法 |
Failover Cluster |
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。 |
cluster="xxx" xxx:集群模式名称 ,例如cluster="failover" |
Failfast Cluster |
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。 |
|
Failsafe Cluster |
失败安全,出现异常时,直接忽略。 |
|
Failback Cluster |
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。 |
|
Forking Cluster |
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。 |
|
Broadcast Cluster |
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。 |
3.6.3 直连服务提供者
直连就是点对点方式,绕过注册中心。在开发及测试环境下,只测试指定服务提供者,只需要直接连接服务端的地即可,这种方式简单。
从0到1搞一波dubbo相关推荐
- 即兴操作:详解Linux安装GCC方法-------------------------这操作很简单搞一波试试看
详解Linux安装GCC方法 起锅烧油先准备七个包配置文件以便于查看 上传http-2.4.25.tar.gz软件包到/opt目录下 解压压缩包 修改配置文件 修改配置文件并启动服务 inux中访问h ...
- 频繁爬取天涯的帖子会不会被抓_web爬虫-搞一波天涯论坛帖子练练手
今天我们将要学习如何使用BeautifulSoup库来抓取网站.BeautifulSoup是一个很好的工具,用于解析HTML代码并准确获取所需的信息.因此,无论您是从新闻网站,体育网站,还是在线商店的 ...
- 万向区块链蜂巢学院 | 关于ETH2.0路线图,搞研究的大脑在想什么?
以太坊2.0是2020年区块链行业最火热的话题之一.万向区块链蜂巢学院线上公开课第42期,邀请了以太坊爱好者社区负责人阿剑.链闻研究总监潘致雄.MYKEY研究部门负责人姚翔.HashKey Capit ...
- MVVM?继续搞一波
前言 又是好久不见了,真的不是因为我懒,是因为公司目前活确实有点着急,所以每天在忙公司的事情. 在五月下旬的时候写过一篇MVVM的文章:MVVM?瞎搞一波?.当时写的时候内心其实很慌,怕写的不好从而误 ...
- 【dubbo】No provider available from registry 127.0.0.1:2181 for service com.dubbo.api.service
页面访问:http://localhost:8062/add?a=111,报报错如下(消费者服务也是报这种错): Whitelabel Error Page This application has ...
- 先搞一波kotlin,看它怎么说
kotlin被谷歌正名都快两个月了,作为Android developer是时候学习一波了,kotlin优点有很多比如完全兼容java,空值处理,语法简洁,支持新特性等等... 废话不多说,直接开始配 ...
- 高并发架构系列:如何从0到1设计一个类Dubbo的RPC框架
优知学院 2019-01-22 18:43:51 之前持续分享的几十期阿里Java面试题中,几乎每次必问Dubbo,比如:"如何从0到1设计一个Dubbo的RPC框架",其实主要考 ...
- 【总结】最全1.5万字长文解读7大方向人脸数据集v2.0版,搞计算机视觉怎能不懂人脸...
人脸图像是计算机视觉领域中研究历史最久,也是应用最广泛的图像.从人脸检测.人脸识别.人脸的年龄表情等属性识别,到人脸的三维重建等,都有非常多的数据集被不断整理提出,极大地促进了该领域的发展. 本次,我 ...
- 0. 一字一句的搞懂vue-cli之vue webpack template配置
此篇文章地址: https://www.cnblogs.com/xyyt/p/9117361.html webpack--神一样的存在.无论写了多少次,再次相见,仍是初见.有的时候开发vue项目,对 ...
最新文章
- 对于数据库连接池的一些思考和MyBatis的集成与使用
- 关于ngOptions的键值对
- WindowManager如何被Android深度解析(1)
- SQL Server中行列转换 Pivot UnPivot (转载)
- 在vue中使用express-mock搭建mock服务
- JEECG第17期架构培训班15号开班啦!每期十个名额,想报名的抓紧时间啦!
- C语言预处理#line、#error
- UNIX环境高级编程——创建与打开IPC通道
- 计算机文化基础作品ppt,计算机文化基础PPT课件
- java poi jar包下载_poi.jar下载-poi.jar包 3.8/3.9/3.10 免费版 - 河东下载站
- html返回按钮 超链接,ppt中怎么添加超链接返回按钮
- volatile详解
- 启发式搜索解决八数码问题
- light动名词_英语语法(5)动名词
- 网购火车票全攻略(新手+进阶+高手级)
- 英文写作盲点-less than 和 fewer than 、only
- 7-3 求100以内的素数
- 判断设置了css省略号样式的元素是否出现了省略号
- 2020年的奋斗目标
- 如果我们真的发现了外星人?
热门文章
- 前端学习(1696):前端系列javascript之class和继承
- 前端学习(1306):node.js模块的加载机制
- 前端学习(46):页面导入样式时,使用link和@import有什么区别?
- git学习(6):删除github镜像
- mybatis学习(8):The server time zone value '???ú±ê×??±??' is unrecognized or represents more
- java学习(36):数组排序
- [Github项目推荐] 机器学习 Python 知识点速查表
- selenium定位元素的方法_selenium定位元素之冻结窗口
- Open-Falcon 监控系统监控 MySQL/Redis/MongoDB 状态监控
- POJ 4979 海贼王之伟大航路 【状压dp】【北大ACM/ICPC竞赛训练】