首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

时序数据库Influx-IOx源码学习二(环境搭建)

欢迎关注微信公众号:atoildw (数据库技术研究) 上一篇介绍了InfluxDB IOx的一些项目背景及现有架构中存在的问题,详情见:https://my.oschina.net/u/3374539/blog/5015114 1.克隆仓库 git clone https://github.com/influxdata/influxdb_iox.git 2.安装基础语言依赖 根据readme文件中的的描述,项目依赖两个基础环境,分别是rust和clang。 rust是使用rustup来进行版本管理的。默认的情况下,会为你安装最后的stable版本,但是IOx项目为了使用不太稳定的SIMD特性,从而达到更高的性能,所以在rust-toolchain文件中指定了一个nightly的版本。 rust安装 脚本: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 测试版本号: rustc --version rustc 1.51.0 (2fd73fabe 2021-03-23) cd influxdb_iox rustc --version rustc 1.50.0-nightly (825637983 2020-11-18) clang安装 安装clang是为了编译croaring这个依赖(RoaringBitmap,根据查询语句进行逐列查询的时候使用),安装脚本根据系统的不同。 mac: xcode-select --install clang --version Apple clang version 12.0.0 (clang-1200.0.32.29) Target: x86_64-apple-darwin20.3.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin 3.IDE搭建 我个人使用的goland,感觉相比于IDEA要速度更快一些。 GoLand下载:https://www.jetbrains.com/go/ 安装Toml插件: https://plugins.jetbrains.com/plugin/8195-toml 安装Rust插件: https://plugins.jetbrains.com/plugin/8182-rust 4.导入工程 当全部完成后,你可以在IDE的右侧看到如下截图: 你也可以在命令行中执行: cargo build 具体速度快慢就要看命了,网络至少需要访问github、crates.io 5.在IDE中启动 打开src/main.rs文件,然后右键-->Run. 在运行之后,在命令行里会提示一个错误,然后退出。原因是我们并没有输入系统可以识别的启动命令。 打开启动配置页面,在command中贴入, run --package influxdb_iox --bin influxdb_iox run 然后就能看到程序启动成功的提示: 祝玩儿的开心!

优秀的个人博客,低调大师

时序数据库Influx-IOx源码学习一(项目背景)

为什么会发起IOx项目 原文请参见: https://www.influxdata.com/blog/announcing-influxdb-iox/ 1. 下一步的目标 原文中介绍到,过去的7年时间的发展中,InfluxDB 在 metrics 数据的处理上已经成为了非常出色的数据库,并且在 analytics 方面也很不错。但对于现有的架构来讲有一个限制就是不能处理非常大的基数 (significant cardinality),也就是说tags里不能设置太多的值。比如说:不能处理分布式追踪数据 (distributed tracing data) 的这种场景。 另外在开源方面,InfluxDB 仅仅支持单机版本的开源,对于分布式版本只有企业版本或者云上才会提供,这个决定给分布式时序数据库留下了很大一块空白的市场。 所以在大方向上,InfluxDB 定义了13个要求,大家可以在原文中找到,总结为: 从设计上减少对于用户的限制:比如 tag 或者 field. 交给用户更多的控制权:比如内存、分区、副本、读写、索引等 支持container的运行环境 大数据的倒入倒出 细粒度的订阅数据 兼容更多的生态,包括数据标准及分析等 可以运行在边缘或者数据中心 可以支持内嵌脚本(我理解为UDF这类) 2. 更开放的许可 InfluxDB对于分布式版本是闭源的,这使得它在市场上和其它产品相比存在很大的差距,使得过去的几年中出现了很多时序数据库。并且如果开源协议对商业是有限制的,那么一些大的公司就会再开发自己的数据库出来,或者是采用其它开源的数据库,这样就造成了大家相互之间的不兼容的。 如果开源的协议采用有限制的协议,那么很多开发者除了内部使用外,即便是已经拿到开源的代码都别无选择的需要重新再开发。 开源创造了一个寒武纪大爆发,会创造出一个非常大的价值。开源不是零和博弈,一个非常大的社区和生态会为所有人和供应商带来更多的机会。 如果InfluxDB想成为无数公司的传感器、监测、数据分析的基础方案,那么唯一的方法就是可扩展、可采用、任何人可以商业化。综上所述,InfluxDB选择了 MIT & Apache 2双重许可。 那么InfluxDB如何盈利呢?在分布式的版本中,可能需要一系列的运维、监控等外围的工具,作为盈利的点。这样无论是云产品还是开源版都是相同的代码,不产生fork。 3. 更新的设计 在现有的InfluxDB中,数据是这样: cpu,host=serverA,region=west user=23.2,system=53.2 1604944036000000000 意思是,存储的cpu这个measurement;他有两个tag,分别是host和region;有两个field,分别是user和system;最后是一个纳秒的时间戳。数据被存储和索引为: measurement, tag key/value pairs, field name 基于时间排序的(time-value)的键值对被存储为了一个单独的时间序列。measurement、tag (key-value)、field 被保存成了一个倒排索引。所以InfluxDB实际上是两个数据库,一个倒排索引和一个时间序列。这意味着,只要tag中存在里新的值,就必须存储在倒排索引中。比如在分布式追踪(distributed tracing ) 的场景里,每行数据都有一个唯一的id,这意味着二级索引比时序数据还要大,服务器就需要浪费大量的cpu和内存来处理索引数据。 有一个解决的方案就是使用field来存储,但是这样限制来用户的使用,必须考虑什么时候为标签、什么时候是字段,查询的时候也需要考虑是否能使用到索引。 如果修改成为无限的基数(cardinality),唯一的方式就是合并时序数据和倒排索引,这是数据库设计的核心。 文章中还提到了严格的内存控制,如果想做内存控制,就不能使用MMAP,所有的数据(索引和时序数据)在InfluxDB中使用到的内存都需要被计算。 对象存储作为持久性层和批量数据导入导出的需求很难通过InfluxDB构建的底层存储引擎来实现。现有的设计基本上假定是一个本地SSD,并且不允许将其中的数据导出到对象存储并在查询时导入。采用这种索引和时间序列数据分开的存储结构也难以实现大量数据的导入和导出。 这些潜在的问题导致无法让InfluxDB做的更好,所以需要从根本上重新思考数据库的存储结构及核心架构是该如何组织。 4. Rust, Arrow, 列式存储 在决定重构核心的功能时,就必须要考虑使用什么工具能够让这个重构的过程变得更快、更可靠、更面向社区。Rust作为系统级编程语言及Apache Arrow作为内存分析工具集,这两款开源工具在过去的几年中,取得了巨大的进步。 Rust可以为我们提供了运行时行为和内存管理的更细粒度控制。还有一个额外的好处就是并发编程更容易,消除了数据竞争。在Crates.io中又几乎包含了所有你需要用到的东西。 Apache Arrow定义了一个内存的列式数据结构并且可以对接Parquet(列式持久化文件格式)、Flight(一个client/server的通信协议框架,传输大数据集的高性能网络接口)。使用Rust和Arrow还有一个额外的好处就是DataFusion(为Apache Arrow提供Rust原生支持的SQL查询引擎)。使用DataFusion作为核心,意味着InfluxDB IOx将提供一个开箱即用的SQL子集。当然除了SQL之外,还会继续支持InfluxQL和Flux。 基于列式存储的数据模型: Measurements会变为Table(每一个measurement都是一张表) Tags和Fields会成为表中的列(这样就需要通过measurement来锁定一个范围) Tag和Field的Key在一个measurement中必须是唯一的 时间也会作为表中的列 除了scheme的组织,还选择了Parquet作为持久化文件格式。每个Parquet文件都包含了一张表中的部分数据,也就是每个Parquet文件只包含一个measurement的数据。实验表明,Parquet比InfluxDB自己的TSM引擎具有更好的压缩比。 另外是用户必须在创建数据库的时候指定分区策略(比如基于时间的每2个小时)。对于每个分区,可以存储一些摘要性的数据在内存中,包含分区都拥有哪些表,有什么列,这些列的最大最小值等。这意味着查询计划可以在执行前通过这个元数据排除大量的分区数据。同时这种分区方案更容易使用对象存储作为长期存储,并管理从内存到对象存储再到索引的Parquet文件的数据生命周期。 现有的列式数据库,并没有单独针对于时序数据做优化并且分离计算和存储,尤其是具有非常优秀的字典和窗口聚合查询。 最后文中提到了一点很有意思的研究方向,他说:我们需要一个能够在内存中保存压缩数据并对其执行查询的系统。所以正在积极扩展DataFusion使其能够处理更多的内存中的时序数据。 5.个人总结 整体看来,InfluxDB想把所有功能开源、分离计算和存储,支持对象存储的方式、精细的控制内存、并且可以在内存中处理压缩的数据。不是什么颠覆式创新,只是为了更好的处理时序数据。

优秀的个人博客,低调大师

(十六) 跟我学习SpringCloud-Eureka的REST API及API扩展

本节我们讲解了一些经常用到的配置信息及 Eureka 的 REST API,通过 API 可以做一些扩展。 Eureka REST API Eureka 作为注册中心,其本质是存储了每个客户端的注册信息,Ribbon 在转发的时候会获取注册中心的服务列表,然后根据对应的路由规则来选择一个服务给 Feign 来进行调用。如果我们不是Spring Cloud技术选型,也想用 Eureka,可以吗?完全可以。 如果不是SpringCloud 技术栈,笔者推荐用 Zookeeper,这样会方便些,当然用 Eureka 也是可以的,这样的话就会涉及如何注册信息、如何获取注册信息等操作。其实 Eureka 也考虑到了这点,提供了很多 REST 接口来给我们调用。 我们举一个比较有用的案例来说明,比如对 Nginx 动态进行 upstream 的配置。 推荐分布式架构源码 在架构变成微服务之后,微服务是没有依赖的,可以独立部署,端口也可以随机分配,反正会注册到注册中心里面,调用方也无须关心提供方的 IP 和 Port,这些都可以从注册中心拿到。 但是有一个问题:API 网关的部署能这样吗?API 网关大部分会用 Nginx 作为负载,那么 Nginx 就必须知道 API 网关有哪几个节点,这样网关服务就不能随便启动了,需要固定。 当然网关是不会经常变动的,也不会经常发布,这样其实也没什么大问题,唯一不好的就是不能自动扩容了。 其实利用 Eureka 提供的 API 我们可以获取某个服务的实例信息,也就是说我们可以根据 Eureka 中的数据来动态配置 Nginx 的 upstream。 这样就可以做到网关的自动部署和扩容了。网上也有很多的方案,结合 Lua 脚本来做,或者自己写 Sheel 脚本都可以。 下面举例说明如何获取 Eureka 中注册的信息。具体的接口信息请查看官方文档“https://github.com/Netflix/eureka/wiki/Eureka-REST-operations“。 获取某个服务的注册信息,可以直接 GET 请求:http://localhost:8761/eureka/apps/eureka-client-user-service。其中,eureka-client-user-service 是应用名称,也就是 spring.application.name。 在浏览器中,数据的显示格式默认是 XML 格式的,如图 1 所示。 如果想返回 Json数据的格式,可以用一些接口测试工具来请求,比如 Postman,在请求头中添加下面两行代码即可。 Content-Type:application/json Accept:application/json 如果 Eureka 开启了认证,记得添加认证信息,用户名和密码必须是 Base64 编码过的 Authorization:Basic 用户名:密码,其余的接口就不做过多讲解了,大家可以自己去尝试。Postman 直接支持了 Basic 认证,将选项从 Headers 切换到 Authorization,选择认证方式为 Basic Auth 就可以填写用户信息了。 填写完之后,直接发起请求就可以了。我们切换到 Headers 选项中,就可以看到请求头中已经多了一个 Authorization 头。 元数据使用 Eureka 的元数据有两种类型,分别是框架定好了的标准元数据和用户自定义元数据。标准元数据指的是主机名、IP 地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。自定义元数据可以使用 eureka.instance.metadataMap 进行配置。 自定义元数据说得通俗点就是自定义配置,我们可以为每个 Eureka Client 定义一些属于自己的配置,这个配置不会影响 Eureka 的功能。 自定义元数据可以用来做一些扩展信息,比如灰度发布之类的功能,可以用元数据来存储灰度发布的状态数据,Ribbon 转发的时候就可以根据服务的元数据来做一些处理。当不需要灰度发布的时候可以调用 Eureka 提供的 REST API 将元数据清除掉。 下面我们来自定义一个简单的元数据,在属性文件中配置如下: eureka.instance.metadataMap.biancheng=zhangsan 上述代码定义了一个 key 为 biancheng 的配置,value 是 zhangsan。重启服务,然后通过 Eureka 提供的 REST API 来查看刚刚配置的元数据是否已经存在于 Eureka 中,如图 2 所示。 EurekaClient 使用 当我们的项目中集成了 Eureka 之后,可以通过 EurekaClient 来获取一些我们想要的数据,比如刚刚上面讲的元数据。我们就可以直接通过 EurekaClient 来获取(代码如下所示),不用再去调用 Eureka 提供的 REST API。 @Autowired private EurekaClient eurekaClient; @GetMapping("/article/infos") public Object serviceUrl() { return eurekaClient.getInstancesByVipAddress( "eureka-client-user-service", false); } 通过 PostMan 来调用接口看看有没有返回我们想要的数据。这时我们会发现,通过 EurekaClient 获取的数据跟我们自己去掉 API 获取的数据是一样的,从使用角度来说前者比较方便。 除了使用 EurekaClient,还可以使用 DiscoveryClient(代码如下所示),这个不是 Feign 自带的,是 Spring Cloud 重新封装的,类的路径为 org.springframework.cloud.client.discovery.DiscoveryClient。 @Autowired private DiscoveryClient discoveryClient; @GetMapping("/article/infos") public Object serviceUrl() { return discoveryClient.getInstances("eureka-client-user-service"); } 健康检查 默认情况下,Eureka 客户端是使用心跳和服务端通信来判断客户端是否存活,在某些场景下,比如MongoDB出现了异常,但你的应用进程还是存在的,这就意味着应用可以继续通过心跳上报,保持应用自己的信息在 Eureka 中不被剔除掉。 Spring Boot Actuator 提供了 /actuator/health 端点,该端点可展示应用程序的健康信息,当 MongoDB 异常时,/actuator/health 端点的状态会变成 DOWN,由于应用本身确实处于存活状态,但是 MongoDB 的异常会影响某些功能,当请求到达应用之后会发生操作失败的情况。 在这种情况下,我们希望可以将健康信息传递给 Eureka 服务端。这样 Eureka 中就能及时将应用的实例信息下线,隔离正常请求,防止出错。通过配置如下内容开启健康检查: eureka.client.healthcheck.enabled=true 我们可以通过扩展健康检查的端点来模拟异常情况,定义一个扩展端点,将状态设置为 DOWN,代码如下所示。 @Component public class CustomHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Builder builder) throws Exception { builder.down().withDetail("status", false); } } 扩展好后我们访问 /actuator/health 可以看到当前的状态是 DOWN,如图 3 所示。 Eureka 中的状态是 UP,这种情况下请求还是能转发到这个服务中,下面我们开启监控检查,再次查看 Eureka 中的状态,发现状态变为 DOWN(1)。 服务上下线监控 在某些特定的需求下,我们需要对服务的上下线进行监控,上线或下线都进行邮件通知,Eureka 中提供了事件监听的方式来扩展。 目前支持的事件如下: EurekaInstanceCanceledEvent 服务下线事件。 EurekaInstanceRegisteredEvent 服务注册事件。 EurekaInstanceRenewedEvent 服务续约事件。 EurekaRegistryAvailableEvent Eureka 注册中心启动事件。 EurekaServerStartedEvent Eureka Server 启动事件。 基于 Eureka 提供的事件机制,可以监控服务的上下线过程,在过程发生中可以发送邮件来进行通知。下面代码只是演示了监控的过程,并未发送邮件。 @Component public class EurekaStateChangeListener { @EventListener public void listen(EurekaInstanceCanceledEvent event) { System.err.println(event.getServerId() + "\t" + event.getAppName() + " 服务下线 "); } @EventListener public void listen(EurekaInstanceRegisteredEvent event) { InstanceInfo instanceInfo = event.getInstanceInfo(); System.err.println(instanceInfo.getAppName() + " 进行注册 "); } @EventListener public void listen(EurekaInstanceRenewedEvent event) { System.err.println(event.getServerId() + "\t" + event.getAppName() + " 服务进行续约 "); } @EventListener public void listen(EurekaRegistryAvailableEvent event) { System.err.println(" 注册中心启动 "); } @EventListener public void listen(EurekaServerStartedEvent event) { System.err.println("Eureka Server启动 "); } } 注意:在 Eureka 集群环境下,每个节点都会触发事件,这个时候需要控制下发送通知的行为,不控制的话每个节点都会发送通知。 推荐分布式架构源码

优秀的个人博客,低调大师

开源 Flink + 实时计算 Flink 版训练营学习资料汇总

Apache Flink:全球领先的开源大数据计算引擎 Apache Flink 是一个开源的分布式大数据处理引擎, 可对有限数据流和无限数据流进行有状态计算。作为 Apache 软件基金会 (ASF) 顶级项目之一,Flink 在流处理方面具有绝对的优势,提供高吞吐、低延时的计算能力, Exactly-once 语义保证数据的准确性,亚秒级别的处理延迟确保业务的快速响应。 作为快速发展的新一代大数据引擎,Flink 本身的架构优势也吸引着越来越多的开源爱好者投入到社区的建设来。 截止到 2020 年 7 月,社区的 star 数达到 13600+ ,contributor 数达到 718,有 22989 次 commits。伴随着社区的快速发展,Flink 也成为类似阿里巴巴、腾讯、字节跳动、滴滴、美团点评等知名公司建设流处理平台的首选。 【推荐阅读】 Flink 社区技术发展风向标 重磅!Apache Flink 1.11 功能前瞻抢先看! 更易用!Hive 集成弯道超车 Hive 终于等来了 Flink Flink PMC 联合各大厂用人主管助你升职加薪 Flink 面试指南 【企业案例】 • OPPO 实时数仓揭秘:从顶层设计实现离线与实时的平滑迁移:单日总数据处理量超 10 万亿,峰值超每秒 3 亿• bilibili 实时平台的架构与实践:基于 Flink 的 bilibili Saber 实时计算平台• 美团点评基于 Flink 的实时数仓平台实践:深度解析美团点评实时数仓案例 【电子书】 • 《零基础入门:从 0 到 1 学会 Apache Flink》:30 天成长为 Flink 大神• 《Apache Flink 年度最佳实践》:国内外一线大厂超大规模最佳实践案例合集 阿里云实时计算 Flink 版 实时计算 Flink版(Alibaba Cloud Realtime Compute for Apache Flink,Powered by Ververica))是阿里云提供的基于 Apache Flink 构建的企业级、高性能实时大数据处理系统,由Apache Flink创始团队官方出品。在 PB 级别的数据集上可以支持亚秒级别的处理延时,赋能用户标准实时数据处理流程和行业解决方案;在支持 Datastream API 作业开发的同时,提供了完整的SQL语义,使得 BI 场景下的开发变得更加简单;丰富的上下游 connector 保证了与用户已使用的大数据组件无缝对接;智能作业调优和诊断功能进一步简化了用户的开发和使用。 实时计算 Flink版在 Apache Flink 核心功能的基础上还增强了企业用户所关注的集群稳定、性能优化、安全控制、系统监控和作业管理等。阿里云实时计算团队目前是全球最大、拥有 Committer 数量最多、专业性最强的 Flink 团队,为实时计算用户提供企业级的管理和咨询服务。2019 年 6 月,由数据中心联盟发起的大数据产品能力评测结果权威发布,阿里云实时计算 Flink版通过最新制定的分布式流处理平台基础能力评测,成为国内首批通过流计算产品能力评测的产品,并被数据中心联盟圈定为国内大数据流计算基础平台第一梯队。2020 年在国际知名咨询调研公司Forrester 的测评中,实时计算 Flink版成为中国唯一进入Forrester象限的实时流计算产品。 【独享月度特惠】开通实时计算产品: master型号4核16GB+master数量1+slave型号4核16GB+slave数量2,计费周期1个月,详情: https://common-buy.aliyun.com/?spm=a2c0j.14094430.1053885.bnt1.307976feKRl1Au&commodityCode=blinkonecs#/buy Tips:开通成功算打卡成功 解决方案 实时计算 Flink:基于 Apache Flink 构建的大数据计算平台(附白皮书) Tips:完成PDF阅读,算打卡成功 最佳实践 实时计算 Flink 版 最佳实践 Tips:完成文章阅读,算打卡成功

优秀的个人博客,低调大师

「2020最新」Spring最易学习教程—IOC 以及 整合Struts2

0 复习 工厂设计模式 使用工厂代替new模式创建对象,目的:解耦合 Spring工厂的使用 applicationContext.xml中配置 bean标签 编码:创建工厂,从工厂中获取对象 Spring中属性注入 简单类型(基本类型+包装类+String) <beanid="标识名"class="全类名"><propertyname="属性"><value>值</value></property><propertyname="属性"value="值"/></bean> 对象类型 <beanid="a"class="Address的全类名"><propertyname="属性1"value="值1"/><propertyname="属性2"value="值2"/></bean><beanid="p"class="Person全类名"><propertyname="addr"><refbean="a"/></property></bean><beanid="p2"class="Person全类名"><propertyname="addr"ref="a"/></bean> 数组+List+Set Map+Properties 1 注入补充 1.1 null值 当需要显式的为属性赋值为 null 时,通过 null标签完成。 <beanid="u"class="com.bcl.entity.User"><constructor-argvalue="1"index="0"/><constructor-argvalue="xiaohei"index="1"/><constructor-argindex="2"><null/></constructor-arg></bean> 1.2 内部bean <beanid="a"class="com.bcl.entity.Address"><propertyname="street"value="文化路"/><propertyname="city"value="硅谷"/></bean><beanid="p"class="com.bcl.entity.Person"><propertyname="personId"value="1"/><propertyname="personName"value="xiaohei"/><propertyname="addr"ref="a"/></bean>可以使用内部bean替换的写法<beanid="p"class="com.bcl.entity.Person"><propertyname="personId"value="1"/><propertyname="personName"value="xiaohei"/><propertyname="addr"><beanclass="com.bcl.entity.Address"><propertyname="city"value="郑州"/><propertyname="street"value="文化路"/></bean></property></bean> 2 FactoryBean技术(创建复杂对象) 2.1 FactoryBean引言 Spring工厂要管理程序中各种种类的对象。 image-20200601102514322 2.2 FactoryBean的开发步骤 编码 实现FactoryBean接口 publicclassConnectionFactoryBeanimplementsFactoryBean<Connection>{@Override//返回复杂对象publicConnectiongetObject()throwsException{//1加载驱动Class.forName("com.mysql.jdbc.Driver");//2建立连接Stringurl="jdbc:mysql://localhost:3306/bcl2002?useUnicode=true&characterEncoding=utf8";Stringusername="root";Stringpassword="root";Connectionconn=DriverManager.getConnection(url,username,password);returnconn;}@Override//返回复杂对象的类型publicClass<?>getObjectType(){returnConnection.class;}@Override//复杂对象是否单例 true:单例 false:多例publicbooleanisSingleton(){returntrue;}} 配置 <!--配置factoryBean的全类名,根据id:conn获取到是Connection对象--><beanid="conn"class="com.bcl.factory.ConnectionFactoryBean"/> 注意: 根据id获取到的复杂对象,不是FactoryBean 可以根据&id获取到FactoryBean 复杂对象的单例与否,只与isSingleton方法有关 3 Spring中对象的生命周期(了解) 生命周期: 从生到死的过程。 多例时 (scope="prototype") 对象在getBean时创建 单例时(scope="singleton") 对象在工厂创建时随之创建初始化:init-method:对象创建后,执行1次方法销毁:destroy-method:对象销毁时,执行1次的方法对象在工厂关闭时销毁 4 Spring配置文件分析 4.1 Spring配置文件的拆分 应用复杂时,需要将配置文件拆分成多个小的配置文件,放置到不同模块,最后在总配置文件中通过import标签引入其它的小配置文件。 <importresource="classpath:a/applicationContext-a.xml"/><importresource="classpath:b/applicationContext-b.xml"/> 4.2 Spring 中xsd文件 xsd(XML Schema Definition)文件,规定了一个xml可以使用哪些标签、哪些属性,以及它们的顺序。 xsd的基本使用 image-20200601113429666 使用xsd文件,要配置xsd的命名空间,以及文件路径对。 在一个xml中使用多个xsd image-20200601114026438 示例: image-20200601120115361 4.3 Spring配置文件中拆分jdbc.properties 抽取jdbc.properties jdbc.driverClassName=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/bcl2002?useUnicode=true&characterEncoding=utf8jdbc.username=rootjdbc.password=root 读取配置文件 <context:property-placeholderlocation="classpath:jdbc.properties"/> 使用jdbc.properties中的参数 <beanid="conn"class="com.bcl.factory.ConnectionFactoryBean"><propertyname="driverClassName"value="${jdbc.driverClassName}"/><propertyname="url"value="${jdbc.url}"/><propertyname="username"value="${jdbc.username}"/><propertyname="password"value="${jdbc.password}"/></bean> 注意:${username} 会优先读取操作系统用户名,可以给参数添加前缀进行区分。 5 Spring IOC和DI IOC(Inversion Of Control)控制反转 (思想) DI(Dependency Injection)依赖注入 (实现手段) 控制:对于对象属性赋值的控制权力。 image-20200601141742924 正向控制的问题:强耦合。 解决方案:控制反转。 image-20200601142542072 结论:要解耦合,就不要new,转为在spring配置文件中通过配置的方式由工厂创建对象。 6 Spring整合Struts2 准备工作:创建好一个可运行的struts2项目。 6.1 整合效果 image-20200601152503882 Spring整合Struts2的效果:由Spring工厂创建Struts2需要的Action和Service. 6.2 实战 导入spring-web 依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>4.3.26.RELEASE</version></dependency><dependency><groupId>org.apache.struts</groupId><artifactId>struts2-spring-plugin</artifactId><version>2.3.16.3</version></dependency> tomcat启动应用时,自动创建Spring工厂 web.xml <context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener> Struts2从Spring工厂中获取Action applicationContext.xml <beanid="userService"class="com.bcl.service.impl.UserServiceImpl"/><beanid="userAction"class="com.bcl.action.UserAction"scope="prototype"><propertyname="userService"ref="userService"/></bean> struts.xml <packagename="day02"extends="struts-default"namespace="/day02"><!--class配置的是spring配置文件中Action的id--><actionname="showAllUsers"class="userAction"method="showAllUsers"><resultname="success">/showAllUsers.jsp</result></action></package> 7 Spring整合JUnit 之前的JUnit测试Spring框架,每次都需要读取配置文件,创建工厂,测试繁琐。 解决方案:使用 spring-test 进行测试 准备工作: <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.3.26.RELEASE</version></dependency> 简化测试: @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")publicclassApplicationContextTest{@AutowiredprivateUseru;@TestpublicvoidtestUser(){System.out.println("u="+u);}} 8 Spring基于注解的配置方式 使用注解替换xml配置的好处:简化配置、提高开发效率。 注解的不足:不利于配置的管理。 8.1 使用注解的思路 image-20200601165433399 操作思路: 使用Component注解替换bean标签配置 使用Autowired注解替换property标签 8.2 注解开发的步骤 给类和属性添加注解 @Component("userService")publicclassUserServiceImplimplementsUserService{...}@Component("userAction")publicclassUserAction{@AutowiredprivateUserServiceuserService;publicvoidsetUserService(UserServiceuserService){this.userService=userService;}...} 查找注解:配置查找注解的起始包名 applicationContext.xml<!--<context:component-scanbase-package="com.bcl.action,com.bcl.service.impl"/>--><context:component-scanbase-package="com.bcl"/> 8.3 核心注解 @Component Component注解替换bean标签,创建对象。与其作用相同还有3个注解: @Controller 用在action层 @Service 用在service层 @Repository 用在dao层 注意事项: 后3个注解实际开发时使用频率更高,比Component有更高的辨识度 MyBatis框架中,Repository没有使用场景 4个注解在使用时,都可以省略id参数。会有默认id:类名首字母小写 UserAction==> userAction UserServiceImpl ==> userServiceImpl @Autowired 用于属性注入。 注意事项: 默认根据类型查找所需要的属性对象 Autowired 用于属性上,底层通过反射操作属性赋值 Autowired用在set方法上,底层通过调用set方法赋值 @Qualifier 当Autowired注入属性,Spring中有不止一个满足条件的对象,为了分辨使用哪个对象,可以通过@Qualifier("bean的id") 确定。 @Controller("userAction")publicclassUserAction{@Autowired@Qualifier("userServiceImpl2")privateUserServiceuserService;...} @Scope 决定是否单例。 @Controller("userAction")@Scope("prototype")publicclassUserAction{...} 业内标准: 对于自定义的类型,使用注解。比如:dao、service、action 第3方类型,使用xml。比如:数据库连接池、事务管理器 「❤️ 帅气的你又来看了我」 如果你觉得这篇内容对你挺有有帮助的话: 点赞支持下吧,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-) 欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。 觉得不错的话,也可以关注 编程鹿 的个人公众号看更多文章和讲解视频(感谢大家的鼓励与支持🌹🌹🌹) 本文分享自微信公众号 - 鹿小洋的Java笔记(lulaoshiJava)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Qt4中学习使用QtCharts绘图二:声波绘制

1、实例编写环境 操作系统:Windows 10 企业版开发工具:Visual Studio 2010 旗舰版开发环境:Qt4.8.6,QtCharts编程语言:C++ 2、实例涉及的内容 本实例主要是通过获取电脑的自带音频输入设备获取声音信息,然后通过使用QtCharts对声波进行绘制。涉及主要类有:QAudioDeviceInfo、QAudioInput、QAudioFormat、QIODevice。在使用Qt库进行开发时候,大家使用频率较高的多数为Qt的界面控件类,大家也就都比较熟悉了。QAudioDeviceInfo:该类提供了查询音频设备及其功能的接口。QAudioInput:该类提供用于从音频输入设备接收音频数据的接口。QAudioFormat:该类除了包含音频流的编码信息之外,还包含了其它参数信息。这些额外的参数进一步指明了:频率、通道数量、样本大小、样本类型和字节顺序等信息。QIODevice:该类是Qt中所有IO设备的基类接口(在笔者的实际工作中很少自己主动重写QIODevice类来实现某些功能,通常Qt中已经实现QFile、QTextStream、QDataStream等功能已经足够完善)。 3、实例效果 4、关键代码片段 void QtChartAudio::Initialize() { //创建并设置绘图要素// m_chart = ui.graphicsView->chart(); m_chart->setTheme(QChart::ChartThemeDark); m_series = new QLineSeries; m_chart->addSeries(m_series); m_axisX = new QValueAxis; m_axisX->setRange(0,DataSource::sampleCount); m_axisX->setLabelFormat("%g"); m_axisX->setTitleText(QString::fromLocal8Bit("采样率")); m_axisX->setLabelsColor(QColor(255,255,0)); m_axisY = new QValueAxis; m_axisY->setRange(-1,1); m_axisY->setTitleText(QString::fromLocal8Bit("音频水平")); m_axisY->setLabelsColor(QColor(255,255,0)); m_chart->addAxis(m_axisX,Qt::AlignBottom); m_series->attachAxis(m_axisX); m_chart->addAxis(m_axisY,Qt::AlignLeft); m_series->attachAxis(m_axisY); m_chart->legend()->hide(); m_chart->setTitleBrush(QBrush(QColor(0,255,255))); m_chart->setTitleFont(QFont(QString::fromLocal8Bit("宋体"),15)); m_chart->setTitle(QString::fromLocal8Bit("从麦克风采集数据绘制音频数据")); m_chart->setFont(QFont(QString::fromLocal8Bit("宋体"),19)); //设置音频格式// QAudioFormat formatAudio; formatAudio.setSampleRate(8000); formatAudio.setChannelCount(1); formatAudio.setSampleSize(8); formatAudio.setCodec("audio/pcm"); formatAudio.setByteOrder(QAudioFormat::LittleEndian); formatAudio.setSampleType(QAudioFormat::UnSignedInt); m_audioInput = new QAudioInput(QAudioDeviceInfo::defaultInputDevice(),formatAudio,this); //开始传输数据// m_dataSource = new DataSource(m_series,this); m_dataSource->open(QIODevice::WriteOnly); m_audioInput->start(m_dataSource); } qint64 DataSource::writeData(const char *data, qint64 len) { //更新麦克风采集的音频数据// int resolution = 4; if (m_buffer.isEmpty()) { m_buffer.reserve(sampleCount); for (int i = 0; i < sampleCount; ++i) m_buffer.append(QPointF(i, 0)); } int start = 0; const int availableSamples = int(len) / resolution; if (availableSamples < sampleCount) { start = sampleCount - availableSamples; for (int s = 0; s < start; ++s) m_buffer[s].setY(m_buffer.at(s + availableSamples).y()); } for (int s = start; s < sampleCount; ++s, data += resolution) m_buffer[s].setY(qreal(uchar(*data) -128) / qreal(128)); m_series->replace(m_buffer); return (sampleCount - start) * resolution; } 5、实例源码获取 完整的实例代码,请在在笔者的下载中心搜索下载(查找本博客同名标题资源进行下载)。如有任何发现任何问题或者疑问,可以留言或者联系作者进行反馈哦!

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册