-
查看CPU相关命令#限制某个线程的cpu使用率sudo cpulimit -p pid -l 50ps -eo %cpu,args | grep -m1 PROCESS | awk '{print $1}'#将当前进程按照memory和cpu排序ps aux --sort=%mem,%cpu#按照cpu使用率排序ps -e -o pcpu,cpu,nice,state,cputime,args --sort pcpu | sed "/^ 0.0 /d"#查看当前系统的物理cpu个数grep "processor" /proc/cpuinfo | wc -l grep -c -e '^cpu[0-9]\+' /proc/stat#查看当前cpu型号grep "model name" /proc/cpuinfo#查看当前cpu信息cat /proc/cpuinfo#查看当前系统的位数grep -q '\<lm\>' /proc/cpuinfo && echo 64 bits || echo 32 bitsgetconf LONG_BIT | grep '64'java -version#查看当前系统的cpu频率awk -F": " '/cpu MHz\ */ { print "Processor (or core) running speed is: " $2 }' /proc/cpuinfo ; dmidecode | awk -F": " '/Current Speed/ { print "Processor real speed is: " $2 }'#查看每个cpu每个进程的cpu使用率ps ax -L -o pid,tid,psr,pcpu,args | sort -nr -k4| head -15 | cut -c 1-90#查看当前中断cat /proc/interrupts#查看多个处理器的使用率相关信息mpstat –P ALL 1#每个物理CPU中Core的个数:cat /proc/cpuinfo | grep "cpu cores" | uniq | awk -F: '{print $2}'#是否为超线程?#如果有两个逻辑CPU具有相同的”core id”,那么超线程是打开的。#每个物理CPU中逻辑CPU(可能是core, threads或both)的个数:cat /proc/cpuinfo | grep "siblings"#/proc/stat 文件中有一行记录的机器从启动依赖,各个中断序号发生中断的次数。#这一行以intr开头,接下来的第一个数字是总的中断数目,之后就是分别的中断数目,从0开始。cat /proc/stat | grep intr查找文件相关命令#按照目录大小排序战士最前面15个目录或者文件du -xB M --max-depth=2 /var | sort -rn | head -n 15#列出当前所有子目录的文件大小du -h --max-depth=1#列出当前文件或者目录最大的10个du -s * | sort -n | tail#按照目录大小从大到小排序du -b --max-depth 1 | sort -nr | perl -pe 's{([0-9]+)}{sprintf "%.1f%s", $1>=2**30? ($1/2**30, "G"): $1>=2**20? ($1/2**20, "M"): $1>=2**10? ($1/2**10, "K"): ($1, "")}e'#列出path这个目录的文件树du -h /path | sort -h#每隔60s监控对应目录的文件大小变化watch -n60 du /var/log/messages#递归删除当前目录下所有子目录中的.svn目录find . -type d -name '.svn' -print0 | xargs -0 rm -rdf#列出当前磁盘的使用情况df -P | column -t#监控磁盘的使用情况watch -d -n 5 df#列出当前inode的使用情况df -i <partition>#按照每个磁盘使用量从高到低排序df -h | grep -v ^none | ( read header ; echo "$header" ; sort -rn -k 5)#查看物理磁盘的使用情况df -x tmpfs | grep -vE "(gvfs|procbususb|rootfs)"#查看当前所有磁盘的大小和使用量df -H#查看所有分区使用情况fdisk -l /dev/sda# 显示系统所有的分区或给定的分区fdisk -l # 显示时,显示的是扇区数不是柱面数 fdisk -u # 显示指定partition的block数 fdisk -s partition #查看磁盘的读写容量iostat -m -d /dev/sda1#测试磁盘的读写速度hdparm -t /dev/sda#查看某个文件的所有链接find -L / -samefile /path/to/file -exec ls -ld {} +#查看最大的5个文件find . -type f -exec ls -s {} \; | sort -n -r | head -5#查看365天前的文件并删除find ./ -type f -mtime +365 -exec rm -f {} \;#查看大于100M的文件find . -type f -size +100M
-
Flume是一种可靠、可扩展、分布式的日志收集、聚合和传输系统。它主要用于以下几个应用场景:1、日志收集:Flume能够从多个源头(例如服务器、应用程序、设备等)收集大量的日志数据,并将其中转到集中式存储系统(如Hadoop HDFS)或消息队列系统(如Kafka)中。这种集中式收集机制可以帮助企业对日志数据进行集中管理和分析。2、数据聚合:Flume可以将多个源头的数据聚合到一起,并将其传输到统一的目标系统。例如,在分布式计算中,可以使用Flume将不同节点上的数据聚合并传输到计算节点或结果节点。3、流式数据传输:Flume支持实时的、可靠的数据传输,因此被广泛用于构建数据流水线,以实现流数据的实时处理和分析。4、网络日志分析:Flume可以用于抓取并分析网络设备、服务器和应用程序产生的日志数据。通过配置适当的源和目标,Flume能够将日志数据从各个设备中收集、存储并进行分析。DataX CDC(Change Data Capture)的主要应用场景有以下几个:1、数据同步:将源数据库中的数据变更(增、删、改)实时同步到目标数据库,确保两个数据库中的数据保持一致。2、数据仓库加载:将源数据库中的增量数据加载到数据仓库或数据湖中,用于数据分析、报表生成等业务需求。3、数据备份与恢复:通过记录数据变更,实时备份源数据库中的增量数据,以防止数据库故障或数据丢失,同时可以快速恢复到指定的时间点。4、实时数据分析:将源数据库中的增量数据实时传输给大数据平台,用于实时数据分析、实时监控等业务场景。5、数据集成和ETL:将多个数据源中的数据变更集成到一个目标数据库中,实现数据的统一管理和分析。需要注意的是,DataX CDC是一款开源数据同步工具,能够实现增量数据的抽取和传输,但并不负责处理数据转换和清洗的任务。Flink CDC(Change Data Capture)的主要应用场景有以下几个:1、实时数据分析:Flink CDC可以将源数据库中的增量数据实时传输到Flink流处理引擎中,使得实时数据分析和实时计算成为可能。通过实时处理增量数据,可以进行实时指标计算、实时报表生成、实时业务监控等。2、数据协同与集成:Flink CDC可以将多个不同数据源的增量数据集成到一个目标系统中,实现不同数据源之间的数据协同和集成。比如将多个数据库中的数据变更实时同步到数据仓库或数据湖,以实现统一的数据分析和报表生成。3、数据流转与传输:Flink CDC可以将源数据库中的增量数据转换成数据流,并实时传输到指定的目标位置。这在数据实时传输和数据交换场景中非常有用,比如将数据传输到消息队列、实时推送数据给其他系统等。4、实时数据湖建设:通过Flink CDC将源数据库中的增量数据实时写入数据湖中,可以建立起一个实时的数据湖,进而支持实时分析、实时机器学习等高价值数据应用。5、实时数据缓存和缓冲:Flink CDC可以实时捕获和缓冲源数据库中的增量数据,并加快其它系统对数据的访问速度,减少对数据库的直接查询和压力。Kettle(也称为Pentaho Data Integration)是一个开源的ETL工具,主要用于数据抽取(Extract)、转换(Transform)和加载(Load)操作。下面是Kettle主要的应用场景:1、数据同步:Kettle可以将不同数据源(如关系型数据库、文件、Web服务等)中的数据进行抽取和同步,实现数据的一致性和更新。2、数据仓库加载:Kettle可以将数据从各种数据源加载到数据仓库(如数据仓库、数据湖等),并进行数据清洗、转换和映射操作,以支持后续的分析和报告需求。3、实时数据分析:Kettle可以实时抽取和转换数据,将其加载到实时数据分析平台中,实现实时监控、实时分析和实时决策。4、数据质量管理:Kettle提供了各种数据清洗和校验的功能,可以帮助用户识别和修复数据质量问题,提高数据的准确性和完整性。 以下是相关同步工具的功能对比:转载自https://www.studyjava.cn/post/2029
-
Kettle,也被称为Pentaho Data Integration(PDI),是一款开源的ETL工具,用于提取、转换和加载数据。它的工作原理可以简单概括为以下几个步骤:1、设计和配置:在Kettle的图形化界面中,通过拖拽和连接各个组件,设计数据转换和加载的流程。每个组件代表不同的任务,如数据抽取、数据清洗、数据转换、数据加载等。为每个组件配置相应的参数,定义数据输入输出的连接和转换规则。2、读取数据:Kettle支持多种数据来源,如关系型数据库、文件、Web服务等。根据配置的数据源和查询条件,Kettle会读取数据源中的数据。3、数据转换和清洗:通过在转换和清洗组件中定义规则和函数,对读取的数据进行处理和转换。可以进行各种操作,如过滤、排序、合并、聚合、计算等,以满足数据处理的需求。4、加载数据:将经过转换和清洗的数据加载到目标数据源中。可以是关系型数据库、文件、数据仓库等。Kettle提供了各种输出组件,用于将数据写入到目标数据源中。5、执行和调度:完成数据处理流程的配置后,可以手动执行该流程。也可以使用Kettle内置的调度器,按照预定的时间和频率自动运行任务。总的来说,Kettle通过可视化的方式,串联和配置多个数据处理和转换组件,实现数据的提取、转换和加载。它具有强大的扩展性和灵活性,能够满足各种数据集成和处理的需求。优势:1、强大的可视化设计和配置:Kettle提供了一个易于使用的图形化界面,使用户可以轻松设计和配置ETL工作流程,而无需编写复杂的代码。2、多种数据源和目标的支持:Kettle可以与各种数据源(例如数据库、文件、Web服务等)以及数据目标(例如数据库、文件、Data Warehouse等)进行无缝集成,方便数据的抽取和加载。3、强大的数据转换和清洗功能:Kettle提供了丰富的数据转换和清洗步骤,如字段映射、数据过滤、数据合并、数据拆分、数据排序等,可以灵活地处理和转换数据。4、插件扩展机制:Kettle支持插件机制,用户可以通过自定义插件扩展Kettle的功能,满足特定需求。5、支持任务调度和并行处理:Kettle可以根据需求进行任务调度和并行处理,提高ETL工作的效率和可靠性。劣势:1、学习曲线较陡峭:尽管Kettle提供了图形化界面,但对于没有经验的用户来说,学习和掌握Kettle的各种功能和操作仍然需要一定的时间和精力。2、对大规模数据处理的限制:由于Kettle是基于Java开发的,对于大规模数据的处理和性能可能存在一些限制,特别是在并行处理和集群环境下。3、对于复杂数据处理场景的限制:尽管Kettle提供了丰富的数据转换和清洗步骤,但在处理复杂数据处理场景时,可能需要编写自定义的脚本或插件来实现。Kettle 支持的实时采集数据源类型:转载自https://www.studyjava.cn/post/2029
-
DataX CDC基于DataX框架,为用户提供了一种灵活、高效的数据同步解决方案。它通过监视源数据库的事务日志或数据库增量日志来捕获源数据库中的变更操作,并将这些操作应用于目标数据库,以保持两者之间的数据同步。这种增量方式可以大大减少数据传输的时间和成本,并提供更及时的数据更新。DataX CDC 是基于 CDC(Change Data Capture)技术实现的数据同步工具,其工作原理如下:1、数据源监控:DataX CDC 首先会监控数据源(如 Oracle 数据库)的事务日志。事务日志是数据库记录每个操作(如插入、更新、删除)的日志文件。2、数据解析:一旦有新的事务日志生成,DataX CDC 会解析事务日志,提取出新增、更新和删除的数据。3、数据同步:经过解析后,DataX CDC 将提取到的数据进行转换和转发,将其同步到目标数据源(如 HDFS、MySQL 等)。4、数据应用:目标数据源接收到同步的数据后,可以被应用程序直接使用或者进行进一步的处理和分析。具体举例来说,DataX CDC 监控 Oracle 事务日志的步骤如下:1、配置数据库连接:首先,需要在 DataX CDC 中配置 Oracle 数据库的连接信息,包括数据库地址、用户名、密码等。2、开启 CDC 日志模式:在 Oracle 数据库中,需要将数据库的日志模式设置为 CDC 日志模式。这可以通过在 Oracle 数据库中执行相应的 SQL 命令来完成,例如执行 ALTER DATABASE ADD SUPPLEMENTAL LOG DATA 命令。3、配置 Change Data Capture:在 DataX CDC 中,需要配置相应的 Change Data Capture 模块,以便能够捕获 Oracle 数据库中的变更事件。这包括指定表的 CDC 规则、列的映射关系等。4、监控事务日志:一旦配置完成,DataX CDC 将自动监控 Oracle 数据库的事务日志,捕获其中的数据变更事件。5、数据同步:捕获到的数据变更事件将会被传递给目标系统或者工具,以完成数据同步操作。注意,在使用 DataX CDC 监控 Oracle 事务日志时,需要确保数据库的参数正确配置,并且有足够的权限执行相关的 SQL 命令。此外,由于监控事务日志可能会带来额外的性能开销,因此需要根据实际情况进行调整和优化。优势:1、实时同步:DataX CDC 可以实时监控和同步数据源的变更,能够及时将数据更新到目标数据源,提供高实时性的数据同步。2、高性能:DataX CDC 使用 CDC 技术,只同步变更数据,避免了全量数据的传输和处理,能够提供高效的数据同步性能。3、精确同步:DataX CDC 可以精确捕获和同步数据源的每一次变更操作,保证了数据的一致性和准确性。4、灵活配置:DataX CDC 提供了灵活的配置选项,可以根据具体需求选择要同步的数据源、目标数据源等,并支持多种数据源类型。劣势:1、复杂性:DataX CDC 的配置和使用相对复杂,需要熟悉 CDC 技术和相关的配置知识。2、依赖数据库事务日志:DataX CDC 的工作原理是基于数据库事务日志的,因此需要确保数据源开启了事务日志功能,并且保证事务日志的稳定性和完整性。3、对数据库性能有影响:在进行实时同步的过程中,DataX CDC 需要读取和解析数据库的事务日志,可能会对源数据库的性能产生一定影响。DataX CDC 支持的实时采集数据源类型:转载自https://www.studyjava.cn/post/2029
-
Flink CDC通过与数据库进行交互,实时捕获数据库中的变更操作。它的工作原理可以分为以下几个步骤:1. 数据库连接和监控:首先,Flink CDC需要与目标数据库建立连接,并监控数据库的变更操作。它可以通过监听数据库的事务日志或者使用数据库引擎的内部机制来实现。2. 变更事件解析:一旦数据库发生变更操作,Flink CDC会解析这些变更事件。它会将变更事件转化为对应的数据结构,例如INSERT、UPDATE或DELETE操作。3. 数据转换和格式化:解析后的变更事件需要经过数据转换和格式化,以便能够被Flink进行处理。Flink CDC会将变更事件转化为Flink支持的数据格式,例如JSON、Avro等。4. 事件流生成:经过转换和格式化后,Flink CDC会将变更事件转化为数据流。这个数据流可以被Flink的流处理任务进行消费和处理。5. 数据同步和传输:生成的数据流可以被传输到不同的目的地,例如Flink的流处理任务、消息队列或者其他外部系统。这样,我们就可以对变更事件进行实时分析和处理。需要注意的是,Flink CDC并非直接支持所有数据库。它的可用性取决于数据库本身是否提供了事务日志的访问接口。目前,Flink CDC支持的数据库包括MySQL、PostgreSQL、Oracle等。优势:1. 实时性:Flink CDC能够实时捕获数据库中的变更操作,并将其转化为实时的数据流。这使得我们能够及时地对数据库中的数据变动进行响应和处理。2. 精确性:Flink CDC通过解析数据库的事务日志或者内部机制,能够准确地捕获数据库中的变更操作。这保证了数据的准确性和一致性。3. 可靠性:Flink CDC能够处理数据库中的变更操作,并将其转化为可靠的数据流。它具有容错机制,能够处理故障和数据丢失的情况。4. 扩展性:Flink CDC支持水平扩展,能够处理大规模的数据变更。它可以与Flink的流处理任务无缝集成,实现高效的数据处理和分析。劣势:1.对于非关系型数据库(如MongoDB、HBase等)的支持相对较弱。Flink CDC主要面向关系型数据库,对于非关系型数据库的支持相对有限。2.对于大规模数据变更的处理可能存在延迟。由于Flink CDC通过读取事务日志来捕获数据变化,如果有大量的数据变更发生,可能会造成读取和处理的延迟。3.需要访问数据库的主从部署。为了保持数据一致性,Flink CDC需要访问数据库的主库以读取事务日志,这可能会对数据库的性能产生一定影响,尤其是在高并发的情况下。4.需要数据库的binlog开启。Flink CDC依赖数据库的binlog来捕获数据变化,如果数据库的binlog没有开启,就无法正常使用Flink CDC。需要注意的是,这些劣势并不是Flink CDC本身的问题,而是基于流式数据捕获的一般限制。如果你的应用场景不适合流式数据捕获,可能需要考虑其他的数据同步方案。Flink CDC 支持的实时采集数据源类型:转载自https://www.studyjava.cn/post/2029
-
Flume的原理是将数据从源头(source)采集,经过一个或多个中间节点(channel)进行传输,最终发送到目的地(sink)。下面是Flume的工作原理的详细解释:1、Source(数据源):Source负责从数据源(如日志文件、网络流、消息队列等)采集数据,并将数据发送到Channel。2、Channel(通道):Channel是数据传输的中间节点,它负责暂存Source采集到的数据。Channel可以是内存、磁盘或者其他存储介质,可以按照事务或批量的方式传输数据。3、Sink(数据目的地):Sink从Channel中获取数据,并将数据发送到指定的目的地(如HDFS、关系型数据库、消息队列等)进行存储和分析。4、Agent(代理):Agent是Flume的一个独立运行实例,它由Source、Channel和Sink组成,负责管理整个数据流的采集、传输和存储。Flume的工作流程如下:1、Source采集数据,将数据发送到Channel。2、Channel将数据暂存,并等待Sink的消费。3、Sink从Channel中获取数据,发送到目的地进行存储和分析。Flume的可靠性和容错性体现在以下几个方面:1、消息确认:Channel会对消息进行确认,确保数据在传输过程中不会丢失。2、事务机制:Flume使用事务机制来确保数据的可靠传输,如果发送失败,会进行回滚和重试操作。3、失败处理:Flume提供了失败处理机制,可以配置重试策略、错误日志记录等来处理发送失败的情况。总的来说,Flume通过源头采集数据,经过中间节点传输,最后发送到目的地实现数据的收集和传输。通过可靠的机制和丰富的配置选项,可以保证数据的安全和可靠传输。优势:1、可靠性高:Flume 采用了可靠性机制,包括数据重传、事件推送确认机制等,确保数据不会丢失。2、扩展性强:Flume 可以通过添加多个代理节点实现横向扩展,使其可以处理大规模的数据流。3、灵活性:Flume 可以根据不同的需求进行配置,支持多种收集器、聚合器和传输器,可以满足不同场景的需求。4、实时数据传输:Flume 支持实时数据传输,可以以流式方式处理和传输数据,适用于需要实时数据处理和分析的场景。5、分布式流处理:Flume 支持分布式架构,可以将数据流分发到多个节点上进行并行处理和传输。劣势:1、复杂性:Flume 的配置和部署相对复杂,需要一定的技术功底和经验。2、依赖性:Flume 依赖于其他组件,比如 Hadoop、HBase 等,如果没有这些组件的支持,应用可能会受到限制。3、部署和维护成本:由于 Flume 的复杂性和依赖性,部署和维护的成本可能较高。Flume支持的实时采集数据源类型:转载自https://www.studyjava.cn/post/2029
-
copyManager文本导入数据有\r\n导致文本里的一条数据却分成了多行,其实实际就是一条数据,因为\r\n影响导致。请问要怎么处理 用的copyIn方法,能否回答具体点,新手,第一次用copyManager,很不熟悉,能贴出代码最好,感谢。。是不是copy xxx from STDIN后面得跟什么参数配置?
-
Stream介绍Java Stream 的主要作用有以下几个方面:简化集合操作:使用传统的 for 循环或迭代器来处理集合数据可能会导致冗长而复杂的代码。延迟计算:流式操作允许你在处理数据之前定义一系列的操作步骤,但只在需要结果时才会实际执行。这种延迟计算的特性意味着可以根据需要动态调整数据处理的操作流程,提升效率。并行处理:Java Stream 提供了并行流的支持,可以将数据分成多个块进行并行处理,从而充分利用多核处理器的性能优势,提高代码的执行速度。函数式编程风格:流式编程鼓励使用函数式编程的思想,通过传递函数作为参数或使用 Lambda 表达式来实现代码的简化和灵活性。为什么使用流式编程可以提高代码可读性和简洁性声明式编程风格:流式编程采用了一种声明式的编程风格,你只需描述你想要对数据执行的操作,而不需要显式地编写迭代和控制流语句。链式调用:流式编程使用方法链式调用的方式,将多个操作链接在一起。每个方法都返回一个新的流对象,这样你可以像“流水线”一样在代码中顺序地写下各种操作,使代码逻辑清晰明了。操作的组合:流式编程提供了一系列的操作方法,如过滤、映射、排序、聚合等,这些方法可以按照需要进行组合使用。你可以根据具体的业务需求将这些操作串联起来,形成一个复杂的处理流程,而不需要编写大量的循环和条件语句。减少中间状态:传统的迭代方式通常需要引入中间变量来保存中间结果,这样会增加代码的复杂度和维护成本。而流式编程将多个操作链接在一起,通过流对象本身来传递数据,避免了中间状态的引入。减少循环和条件:流式编程可以替代传统的循环和条件语句的使用。什么是 Stream?Stream(流)是一个来自数据源的元素队列并支持聚合操作元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。不可变性:Stream 是不可变的,它不会修改原始数据源,也不会产生中间状态或副作用。每个操作都会返回一个新的流对象,以保证数据的不可变性。 和以前的Collection操作不同, Stream操作还有两个基础的特征:Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。Stream中的操作大体可以分为两类中间操作:将流一层层的进行处理,并向下一层进行传递,如 filter map sorted等。 中间操作又分为有状态(stateful)及无状态(stateless)有状态:必须等上一步操作完拿到全部元素后才可操作,如sorted无状态:该操作的数据不收上一步操作的影响,如filter map终止操作:触发数据的流动,并收集结果,如collect findFirst forEach等。终止操作又分为短路操作(short-circuiting)及非短路操作(non-short-circuiting)短路操作:会在适当的时刻终止遍历,类似于break,如anyMatch findFirst等非短路操作:会遍历所有元素,如collect max等Stream中间操作过滤操作(filter)过滤操作(filter),它接受一个 Predicate 函数作为参数,用于过滤 Stream 中的元素。只有满足 Predicate 条件的元素会被保留下来,而不满足条件的元素将被过滤掉。过滤操作的语法如下Stream<T> filter(Predicate<? super T> predicate)其中,T 表示 Stream 元素的类型,predicate 是一个函数式接口 Predicate 的实例,它的泛型参数和 Stream 元素类型一致,并且predicate返回的值必须是boolean类型,因为需要通过真假值判断是否要过滤该值。使用过滤操作可以根据自定义的条件来筛选出符合要求的元素,从而对 Stream 进行精确的数据过滤。下面是一个示例,演示如何使用过滤操作筛选出一个整数流中的大于三的数: List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 生成流式对象 // Stream<Integer> stream = numbers.stream(); List<Integer> list=numbers.stream().filter( (x)->{return x>3;} //lambda表达式 可简化成下面的写法 // x->x>3 ).toList(); System.out.println("number中大于3的数: "+list.toString());映射操作(map)映射操作(map),它接受一个 Function 函数作为参数,用于对 Stream 中的每个元素进行映射转换,生成一个新的 Stream。映射操作的语法如下:<R> Stream<R> map(Function<? super T, ? extends R> mapper)其中,T 表示原始 Stream 的元素类型,R 表示映射后的 Stream 的元素类型,mapper 是一个函数式接口 Function 的实例,可以进行不同的映射操作.下面是一个示例,演示如何使用映射操作将一个字符串流中的每个字符串转换为其长度: List<String> numbers = Arrays.asList("apple", "banana", "cherry"); // 生成流式对象 // Stream<Integer> stream = numbers.stream(); numbers.stream().map( String::length ).forEach(System.out::println);在这个示例中,我们首先创建了一个包含字符串的 Stream,并调用 map() 方法传入String::length,表示要将每个字符串转换为其长度。然后通过 forEach() 方法遍历输出结果。注意: 映射操作可能引发空指针异常(NullPointerException),因此在执行映射操作时,应确保原始 Stream 中不包含空值,并根据具体情况进行空值处理。排序操作(sorted)排序操作(sorted)是 Stream API 中的一种常用操作方法,它用于对 Stream 中的元素进行排序。排序操作可以按照自然顺序或者使用自定义的比较器进行排序。排序操作的语法如下:Stream<T> sorted() Stream<T> sorted(Comparator<? super T> comparator)第一种语法形式中,sorted() 方法会根据元素的自然顺序进行排序。如果元素实现了 Comparable 接口并且具备自然顺序,那么可以直接调用该方法进行排序。第二种语法形式中,sorted(Comparator<? super T> comparator) 方法接受一个比较器(Comparator)作为参数,用于指定元素的排序规则。通过自定义比较器,可以对非 Comparable 类型的对象进行排序。下面是一个示例,演示如何使用排序操作对一个字符串流进行排序: List<String> numbers = Arrays.asList("apple", "banana", "cherry"); // 生成流式对象 // Stream<Integer> stream = numbers.stream(); numbers.stream().sorted().forEach(System.out::println);输出apple banana cherry注意: 排序操作可能会影响程序的性能,特别是对于大型数据流或者复杂的排序规则。因此,在实际应用中,需要根据具体情况进行权衡和优化,选择合适的算法和数据结构来提高排序的效率。截断操作(limit 和 skip)截断操作(limit和skip),用于在处理流的过程中对元素进行截断。limit(n):保留流中的前n个元素,返回一个包含最多n个元素的新流。如果流中元素少于n个,则返回原始流。skip(n):跳过流中的前n个元素,返回一个包含剩余元素的新流。如果流中元素少于n个,则返回一个空流。 下面分别详细介绍这两个方法的使用。注意: 在使用截断操作时需要注意流的有界性。如果流是无界的(例如 Stream.generate()),那么使用 limit() 方法可能导致程序陷入无限循环,而使用 skip() 方法则没有意义。Stream 的终止操作forEach 和 peekforEach和peek都是Stream API中用于遍历流中元素的操作方法,它们在处理流的过程中提供了不同的功能和使用场景。forEach: forEach是一个终端操作方法,它接受一个Consumer函数作为参数,对流中的每个元素执行该函数。forEach会遍历整个流,对每个元素执行相同的操作。示例代码:List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream() .forEach(System.out::println);peek: peek是一个中间操作方法,它接受一个Consumer函数作为参数,对流中的每个元素执行该函数。与forEach不同的是,peek方法会返回一个新的流,该流中的元素和原始流中的元素相同。示例代码:List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); List<String> upperCaseNames = names.stream() .map(String::toUpperCase) .peek(System.out::println) .toList();聚合操作(reduce)reduce和collect都是Stream API中用于聚合操作的方法,它们可以将流中的元素进行汇总、计算和收集。reduce: reduce是一个终端操作方法,它接受一个BinaryOperator函数作为参数,对流中的元素逐个进行合并操作,最终得到一个结果。该方法会将流中的第一个元素作为初始值,然后将初始值与下一个元素传递给BinaryOperator函数进行计算,得到的结果再与下一个元素进行计算,以此类推,直到遍历完所有元素。示例代码: List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.stream().reduce(Integer::sum).ifPresent(System.out::println);//输出结果15在这个示例中,我们创建了一个包含整数的List,并通过stream()方法将其转换为流。然后使用reduce方法对流中的元素进行求和操作,将每个元素依次相加,得到结果15。匹配操作(allMatch、anyMatch 和 noneMatch)在 Stream API 中,allMatch、anyMatch 和 noneMatch 是用于进行匹配操作的方法,它们可以用来检查流中的元素是否满足特定的条件。allMatch: allMatch 方法用于判断流中的所有元素是否都满足给定的条件。当流中的所有元素都满足条件时,返回 true;如果存在一个元素不满足条件,则返回 false。anyMatch: anyMatch 方法用于判断流中是否存在至少一个元素满足给定的条件。当流中至少有一个元素满足条件时,返回 true;如果没有元素满足条件,则返回 false。在这个示例中,我们创建了一个包含整数的 List,并通过 stream() 方法将其转换为流。然后使用 anyMatch 方法判断流中是否存在偶数。由于列表中存在偶数,所以返回 true。noneMatch: noneMatch 方法用于判断流中的所有元素是否都不满足给定的条件。当流中没有元素满足条件时,返回 true;如果存在一个元素满足条件,则返回 false。示例代码:List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); boolean allEven = numbers.stream() .allMatch(n -> n % 2 == 0); System.out.println(allEven); // 输出结果: false boolean hasEven = numbers.stream() .anyMatch(n -> n % 2 == 0); System.out.println(hasEven); // 输出结果: true boolean noneNegative = numbers.stream() .noneMatch(n -> n < 0); System.out.println(noneNegative); // 输出结果: true查找操作(findFirst 和 findAny)在 Stream API 中,findFirst 和 findAny 是用于查找操作的方法,它们可以用来从流中获取满足特定条件的元素。findFirst: findFirst 方法用于返回流中的第一个元素。它返回一个 Optional 对象,如果流为空,则返回一个空的 Optional;如果流非空,则返回流中的第一个元素的 Optional。findAny: findAny 方法用于返回流中的任意一个元素。它返回一个 Optional 对象,如果流为空,则返回一个空的 Optional;如果流非空,则返回流中的任意一个元素的 Optional。在顺序流中,通常会返回第一个元素;而在并行流中,由于多线程的处理,可能返回不同的元素。示例代码:List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); Optional<String> first = names.stream() .findFirst(); first.ifPresent(System.out::println); // 输出结果: Alice List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Optional<Integer> any = numbers.stream() .filter(n -> n % 2 == 0) .findAny(); any.ifPresent(System.out::println); // 输出结果: 2 或 4(取决于并行处理的结果)统计操作(count、max 和 min)在 Stream API 中,count、max 和 min 是用于统计操作的方法,它们可以用来获取流中元素的数量、最大值和最小值。count: count 方法用于返回流中元素的数量。它返回一个 long 类型的值,表示流中的元素个数。max: max 方法用于返回流中的最大值。min: min 方法用于返回流中的最小值。它返回一个 Optional 对象,如果流为空,则返回一个空的 Optional;如果流非空,则返回流中的最小值的 Optional。示例代码:List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); long count = numbers.stream() .count(); System.out.println(count); // 输出结果: 5 Optional<Integer> max = numbers.stream() .max(Integer::compareTo); max.ifPresent(System.out::println); // 输出结果: 5 Optional<Integer> min = numbers.stream() .min(Integer::compareTo); min.ifPresent(System.out::println); // 输出结果: 1
-
前言 物联网是在互联网的基础上延伸和扩展的一种网络,其用户端延伸和扩展到了任何物品之间,彼此进行信息交换和通信,目的是实现所有物品与网络的连接,从而方便识别、管理和控制。 无线物联网的特点包括:全面感知、实时准确传递物品信息、利用智能计算技术对海量数据进行分析和处理,以实现智能化控制。 由于物联网中的很多设备都是资源受限型的,即只有少量的内存空间和有限的计算能力,所以传统的 HTTP 协议应用在物联网上就显得过于庞大而不适用。 MQTT 协议和 CoAP 协议都是物联网中比较流行的协议,都对传输量做了很大的精简,传输开销小,以适应物理网的网络环境。 内容 CoAP(Constrained Application Protocol 受限应用协议) CoAP 是 6LowPAN 协议栈中的应用层协议。COAP 协议网络传输层由 TCP 改为 UDP。 COAP 是二进制格式的,HTTP 是文本格式的,COAP 比 HTTP 更加紧凑。 轻量化,COAP 最小长度仅仅 4B,一个 HTTP 的头都几十个 B 了。 支持可靠传输,数据重传,块传输。 确保数据可靠到达。 支持 IP 多播,即可以同时向多个设备发送请求。 非长连接通信,适用于低功耗物联网场景。 MQTT(Message Queuing Telemetry Transport 消息队列遥测传输) 为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布 / 订阅型消息协议。轻量、简单、开放和易于实现。 1. 使用发布 / 订阅消息模式,提供一对多的消息发布,解除应用程序耦合 2. 使用 TCP/IP 提供网络连接 3. 小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量 这些特点使它适用于受限环境。例如,但不仅限于此: ・特别适合于网络代价昂贵,带宽低、不可靠的环境 ・能在处理器和内存资源有限的嵌入式设备中运行 ・使用发布 / 订阅消息模式,提供一对多的消息发布,从而解除应用程序耦合 ・使用 TCP/IP 提供网络连接 ・提供 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制 哪种协议?从应用场景要求的层面分析如何选用 1、服务端主动发送给客户端的数据(反控)的时效性(如通过 APP 控制硬件动作) 因 MQTT 协议是保持连接的,所以及时性相对很好;CoAP 协议是无连接响应式通讯,因此不能主动推送,要等客户端访问才可以携带回去,及时性相对较差。 2、设备环境对底层协议的要求或限制 MQTT 协议是建立在 TCP 协议基础之上的,因此他也具备 TCP 协议的优缺点;CoAP 协议是建立在 UDP 协议基础之上的,因此他也具备 UDP 协议的优缺点。 3、在 NAT 网络环境中是否需要调整 因 MQTT 协议是保持长连接的,所以在 NAT(Network Address Translation,网络地址转换)下没有问题;CoAP 协议因是无连接方式,需要使用 NAT 穿透性手段。 NAT NAT(Network Address Translation,网络地址转换)是 1994 年提出的。当在专用网内部的一些主机本来已经分配到了本地 IP 地址(即仅在本专用网内使用的专用地址),但现在又想和因特网上的主机通信(并不需要加密)时,可使用 NAT 方法。这种方法需要在专用网连接到因特网的路由器上安装 NAT 软件。装有 NAT 软件的路由器叫做 NAT 路由器,它至少有一个有效的外部全球 IP 地址。这样,所有使用本地地址的主机在和外界通信时,都要在 NAT 路由器上将其本地地址转换成全球 IP 地址,才能和因特网连接。 4、实现多对多的通信还是单对单通信 因 MQTT 协议的消息模型是发布/订阅式的,所以是可以多对多通信的;CoAP 协议的消息模型是请求 / 响应式的,所以是单对单通信。 5、服务质量等级及自动重连重发 因 MQTT 协议有 QoS 配置,支持服务质量等级和自动重连重发机制;CoAP 本身不具备,需要应用层自己来写这个逻辑。 6、对网络稳定性要求 MQTT 协议利用自动重连重发机制解决网络不稳定问题,断网就会触发重连;CoAP 协议只有客户端发送的时候需要保证网络连接正常,其他时段无需连接。 7、对硬件设备的功耗影响 MQTT 协议因有保持连接,所以功耗略高于 CoAP 协议。 ———————————————— 版权声明:本文为CSDN博主「YF云飞」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/flyTie/article/details/126186579
-
在Java中,类加载器(Class Loader)根据其加载类的来源和工作方式可以分为不同的分类。主要的类加载器分类如下: 启动类加载器(Bootstrap Class Loader): 启动类加载器是Java虚拟机的一部分,它负责加载Java平台核心库(Java API的一部分,如java.lang、java.util等)。 它是虚拟机本身的一部分,通常由C++编写,不是一个Java对象,也不继承java.lang.ClassLoader。 扩展类加载器(Extension Class Loader): 扩展类加载器负责加载Java的扩展库(Java标准库之外的一些功能,位于jre/lib/ext目录下)。 通常使用Java编写,是标准的ClassLoader的子类。 应用程序类加载器(Application Class Loader): 应用程序类加载器是最常用的加载器,负责加载应用程序的类,包括应用程序自身的类和第三方类库。 通常是系统类加载器的子类,由Java编写。 自定义类加载器: 开发者可以创建自定义类加载器,以实现特定的需求,例如从网络加载类、加密类文件等。 自定义类加载器需要继承java.lang.ClassLoader类,并覆盖其中的方法,例如findClass和loadClass。 另外,还可以根据加载类的顺序将类加载器分为以下三个主要类别: 双亲委派模型: Java类加载器遵循双亲委派模型,即每个类加载器在尝试加载一个类之前,会先委派给其父加载器。这种模型有助于确保类加载的一致性和安全性。 如果父加载器找不到类,子加载器才会尝试加载。这意味着一些核心库类由启动类加载器加载,而应用程序类由应用程序类加载器加载。 扩展类加载器和应用程序类加载器: 扩展类加载器和应用程序类加载器通常是系统类加载器的子类,它们负责加载Java类库和应用程序的类。 这两个加载器通常是自定义类加载器的父加载器,因此开发者可以扩展它们以实现自定义加载行为。 自定义类加载器: 自定义类加载器允许开发者根据需要实现特定的加载行为,可以加载网络上的类、加密的类文件等。 自定义类加载器通常不是双亲委派模型中的一部分,开发者需要自行实现加载逻辑。 这些类加载器的分类和加载机制在Java应用程序的类加载过程中起到重要的作用,确保类能够正确加载和协同工作。 ———————————————— 版权声明:本文为CSDN博主「边境矢梦°」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/dandelionl_/article/details/133934828
-
一、微服务介绍 1️⃣系统架构演变 随着互联网的发展,网站应用的规模也在不断的扩大,进而导致系统架构也在不断的进行变化。 从互联网早起到现在,系统架构大体经历了下面几个过程: 单体应用架构—>垂直应用架构—>分布 式架构—>SOA架构—>微服务架构,当然还有悄然兴起的Service Mesh(服务网格化)。 接下来我们就来了解一下每种系统架构是什么样子的, 以及各有什么优缺点。 🍀(1)单体应用架构 互联网早期,一般的网站应用流量较小,只需一个应用,将所有功能代码都部署在一起就可以,这样可以减少开发、部署和维护的成本。 比如说一个电商系统,里面会包含很多用户管理,商品管理,订单管理,物流管理等等很多模块,我们会把它们做成一个web项目,然后部署到一台tomcat服务器上。 优点: 项目架构简单,小型项目的话, 开发成本低 项目部署在一个节点上, 维护方便 缺点: 全部功能集成在一个工程中,对于大型项目来讲不易开发和维护 项目模块之间紧密耦合,单点容错率低 无法针对不同模块进行针对性优化和水平扩展 🍀(2)垂直应用架构 随着访问量的逐渐增大,单一应用只能依靠增加节点来应对,但是这时候会发现并不是所有的模块都会有比较大的访问 量. 还是以上面的电商为例子, 用户访问量的增加可能影响的只是用户和订单模块, 但是对消息模块的影响就比较小. 那么此时我们希望只多增加几个订单模块, 而不增加消息模块. 此时单体应用就做不到了, 垂直应用就应运而生了. 所谓的垂直应用架构,就是将原来的一个应用拆成互不相干的几个应用,以提升效率。比如我们可以将上面电商的单体 应用拆分成: 电商系统(用户管理 商品管理 订单管理) 后台系统(用户管理 订单管理 客户管理) CMS系统(广告管理 营销管理) 这样拆分完毕之后,一旦用户访问量变大,只需要增加电商系统的节点就可以了,而无需增加后台和CMS的节点。 优点: 系统拆分实现了流量分担,解决了并发问题,而且可以针对不同模块进行优化和水扩展 一个系统的问题不会影响到其他系统,提高容错率 缺点: 系统之间相互独立, 无法进行相互调用 系统之间相互独立, 会有重复的开发任务 🍀(3)分布式架构 当垂直应用越来越多,重复的业务代码就会越来越多。这时候,我们就思考可不可以将重复的代码抽取出来,做成统一的业务层作为独立的服务,然后由前端控制层调用不同的业务层服务呢? 这就产生了新的分布式系统架构。它将把工程拆分成表现层和服务层两个部分,服务层中包含业务逻辑。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。 优点: 抽取公共的功能为服务层,提高代码复用性 缺点: 系统间耦合度变高,调用关系错综复杂,难以维护 🍀(4)SOA架构 在分布式架构下,当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心对集群进行实时管理。此时,用于资源调度和治理中心(SOA Service Oriented Architecture)是关键。 优点: 使用治理中心(ESB\dubbo)解决了服务间调用关系的自动调节 缺点: 服务间会有依赖关系,一旦某个环节出错会影响较大( 服务雪崩 ) 服务关系复杂,运维、测试部署困难 🍀(5)微服务架构 微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步,它更加强调服务的"彻底拆分"。 微服务架构与SOA架构的不同 微服务架构比 SOA架构粒度会更加精细,让专业的人去做专业的事情(专注),目的提高效率,每个服务于服务之间互不影响,微服务架构中,每个服务必须独立部署,微服务架构更加轻巧,轻量级。 SOA 架构中可能数据库存储会发生共享,微服务强调独每个服务都是单独数据库,保证每个服务于服务之间互不影响。 项目体现特征微服务架构比 SOA 架构更加适合与互联网公司敏捷开发、快速迭代版本,因为粒度非常精细。 优点: 服务原子化拆分,独立打包、部署和升级,保证每个微服务清晰的任务划分,利于扩展 微服务之间采用Restful等轻量级http协议相互调用 缺点: 分布式系统开发的技术成本高(容错、分布式事务等) 复杂性更高。各个微服务进行分布式独立部署,当进行模块调用的时候,分布式将会变得更加麻烦。 2️⃣微服务架构介绍 作者: Martin Fowler 论文原文:https://martinfowler.com/articles/microservices.html 论文翻译:http://blog.cuicc.com/blog/2015/07/22/microservices 他说微服务其实是一种架构风格,我们在开发一个应用的时候这个应用应该是由一组小型服务组成,每个小型服务都运行在自己的进程内;小服务之间通过HTTP的方式进行互联互通。 微服务架构的常见问题 一旦采用微服务系统架构,就势必会遇到这样几个问题: 这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除]) nacos 这么多小服务,他们之间如何通讯?(restful rpc dubbo feign) httpclient(“url”,参数), springBoot restTemplate(“url”,参数) , feign 这么多小服务,客户端怎么访问他们?(网关) gateway 这么多小服务,一旦出现问题了,应该如何自处理?(容错) sentinel 这么多小服务,一旦出现问题了,应该如何排错? (链路追踪) skywalking 对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。 3️⃣常见微服务架构 🍀(1)dubbo: zookeeper +dubbo + SpringMVC/SpringBoot 配套 通信方式:rpc 注册中心:zookeeper / redis 配置中心:diamond 🍀(2)SpringCloud:全家桶+轻松嵌入第三方组件(Netflix) 配套 通信方式:http restful 注册中心:eruka / consul 配置中心:config 断路器:hystrix 网关:zuul 分布式追踪系统:sleuth + zipkin 🍀(3)SpringCloud Alibaba Spring Cloud 以微服务为核心的分布式系统构建标准 “分布式系统中的常见模式”给了 Spring Cloud 一个清晰的定位,即“模式”。也就是说 Spring Cloud 是针对分布式系统开发所做的通用抽象,是标准模式的实现。这个定义非常抽象,看完之后并不能知道 Spring Cloud 具体包含什么内容。再来看一下 Spring 官方给出的一个 High Light 的架构图,就可以对这套模式有更清晰的认识: 可以看到这个图中间就是各个 Microservice,也就是我们的这个微服务的实现,周边周围的话就是去围绕这个微服务来去做各种辅助的信息事情。例如分布式追踪、服务注册、配置服务等,都绕微服务运行时所依赖的必不可少的的支持性功能。我们可以得出这样一个结论:Spring Cloud 是以微服务为核心的分布式系统的一个构建标准。 二、Spring Cloud Alibaba介绍 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发微服务架构的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发微服务架构。 依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。 根据 Jakarta 2019 年的调研报告,Spring Boot 拥有非常高的占比。熟悉 Java 语言的同学,应该对 Spring 框架都不会陌生。其倡导的依赖倒置、面向切面编程等特性已经形成了 Java 语言的事实标准,几乎所有三方框架都会提供对 Spring 框架的支持。 1️⃣Spring Cloud Alibaba 的定位 既然说 Spring Cloud 是标准,那么自然少不了针对标准的实现。这里,为大家介绍下 Spring Cloud Alibaba 这套实现。先给出下面这张图帮助大家理解 Spring Cloud Alibaba 的定位: 这里给大家这么一个公式,这个叫做:“3 加 2”。 3 指的就是图中深色的部分,其实它就是 Spring Cloud 标准,一共有 3 层。中间颜色最深的部分就是及整个微服务最核心的内容,包括了“ RPC调用”以及“服务注册与发现”。第二层,也就是围绕着核心的这一圈,是一些辅助微服务更好的工作功能,包括了负载均衡、路由、网关、断路器,还有就是追踪等等这些内容。再外层的话,主要是一些分布式云环境里通用能力。 2 指的就是上图中最外面这一圈。这一部分就是这个我们 Spring Cloud Alibaba 的一个定义,它其实包含两个部分的内容:右上部分是对于 Spring Cloud 标准的实现。例如,我们通过 Dubbo 实现了 RPC 调用功能,通过 Nacos 实现了“服务注册与发现”、“分布式配置”,通过 Sentinel 实现了断路器等等,这里就不一一列举了。 左下部分是我们 Spring Cloud Alibaba 对阿里云各种服务的集成。可能很多小伙伴会有这样的一个问题:为什么要加上这一部分呢?此时回头审视一下 Spring Cloud ,它仅仅是一个微服务的一个框架。但是在实际生产过程中,单独使用微服务框架其实并不足以支撑我们去构建一个完整的系统。所以这部分是用阿里帮助开发者完成微服务以外的云产品集成的功能。 这里可能会很多小伙伴会有这么一个担心:是不是使用了 Spring Cloud Alibaba,就会被阿里云平台绑定呢?这是不会的。为什么这么说呢?如上面说的,“3 加 2”中的 2 是被分为两个部分的。其中对 Spring Cloud 的实现是完全独立的,开发者可以只是用这部分实现运行在任何云平台中。当然,另一部分,由于天然是对阿里云服务的集成,这部分是和平台相关的。这里给开发者充分的自由,选择只是用其中的部分还是全部产品。当然,我们也非常欢迎开发者选择使用阿里云的全套服务,我们也会尽量保证使用整套产品时的连贯性与开发的便利性。 2️⃣Spring Cloud 各套实现对比 Spring Cloud 作为一套标准,它的实现肯定不止一套,那么各套实现都有什么区别呢?我们来一起看一下下面这张图: 可以发现 Spring Cloud Alibaba 是所有的实现方案中功能最齐全的。尤其是在 Netflix 停止更新了以后,Spring Cloud Alibaba 依然在持续更新和迭代。 从 18 年 7 月份 Spring Cloud Alibaba 正式提交代码开始,就得到了大家广泛的关注。截止今天,Spring Cloud Alibaba 一共获得了超过了 1.5 万的 star 数,已经的领先于所有其他实现的总和。 3️⃣Spring Cloud Alibaba 生态 可以看到除了围绕着 Spring Cloud 的标准实现以外,还有包括的数据、资源、消息、缓存等各种类型的服务。在不同类型的服务下,也有很多具体的产品可供用户选择。 这里罗列典型而非全部产品。更多的内容,可以参考阿里云官网。 三、Spring Cloud Alibaba环境搭建 SpringCloud Alibaba 依赖 Java 环境来运行。还需要为此配置 Maven环境,请确保是在以下版本环境中安装使用: 64 bit JDK 1.8+;下载 & 配置。 1.8.0_131 Maven 3.2.x+;下载 & 配置。 3.6.1 (1)基于SpringBoot的父maven项目 (2)创建2个服务(订单服务和库存服务) 版本说明:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E Spring Cloud Alibaba:2.2.5.RELEASE Spring Boot :2.3.2.RELEASE Spring Cloud:Hoxton.SR8 父pom如下: <?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 https://maven.apache.org/xsd/maven‐4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> <!‐‐ lookup parent from repository ‐‐> </parent> <groupId>com.tuling.mall</groupId> <artifactId>vip‐spring‐cloud‐alibaba</artifactId> <version>0.0.1‐SNAPSHOT</version> <name>vip‐spring‐cloud‐alibaba</name> <packaging>pom</packaging> <description>Demo project for Spring Cloud Alibaba</description> <properties> <java.version>1.8</java.version> <spring‐cloud.version>Hoxton.SR8</spring‐cloud.version> <spring‐cloud‐alibaba.version>2.2.5.RELEASE</spring‐cloud‐alibaba.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring‐cloud‐dependencies</artifactId> <version>${spring‐cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring‐cloud‐alibaba‐dependencies</artifactId> <version>${spring‐cloud‐alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project> ———————————————— 版权声明:本文为CSDN博主「小新要变强」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_42146402/article/details/129207664
-
🍊数据类型 在Java中数据类型主要分为两类:基本数据类型和引用数据类型。本文来介绍基本数据类型。 基本数据类型有:整型、浮点型、字符型以及布尔型 (这看起来和C语言一样,还挺亲切的) 🍌整型 Java中的整型有:byte,short,int,long 与C语言相比,short和int没啥变化。 有变化的点在于,多了一个byte,叫做字节型,它占一个字节,很像C语言中的char,它的范围也是从-128~127。(待会下面会对这个范围作一些说明) 同时我们不难发现,Java没有long long,因为它的long(长整型)的大小就是8个字节了,不像C语言的long有时是4个字节,而有时是8。这也正引出一个重要的点:Java的数据类型在32位和64位环境下的大小都是一样的,这保证了在不同平台的可移植性。 🥝byte的范围 (其实我之前学C语言的时候char的取值范围没有完全弄懂hhh) 我们以前学过:数据在内存中的存储是补码。数据的二进制序列中最高位是符号位。因为C语言和Java只是语言不同而已,所以它们在数据存储方面其实是大同小异的。 Java中的基本数据类型没有“无符号”这一概念,也就是说都是有符号的,必定有符号位。 先来看正数的情况,易知只要数值位都是1就可以取到最大值127。 负数的情况有点小复杂,按理来说负数最小值是-127,即11111111。至于-128,其实是人为规定的,怎么规定呢?127的源码和1的源码相加就是1000 0000,规定这个数就是-128(就最高位的1同时作为数值位和符号位这样子) 然后还有两件事: 第一,我们判定一个数的大小(这里指的是十进制大小)可以看源码,也可以看补码,但是看源码会比较直观,因为你可以直接算出来。 第二,计算机中各种运算主要是以补码参与运算。 🍌浮点型 Java浮点型也是float和double。float大小为4个字节;double为8个字节。 我们在写代码的时候如果写 float a = 0.5; 1 那编译器会报错,因为Java中浮点数默认是double类型的,而a是float,自然报错了(而C语言就不会这样,这也体现了Java的严谨)。如果你要让a就是float类型的话,就在后面加个f: float a = 0.5f; 1 🥝浮点数相关运算 这部分的规则也是和C语言的差不多,在此不多赘述(其实是我懒得写 )。但仍要补充一些要点: ①对于整型的除法运算,若想转化为浮点数的除法运算,则在分子or分母乘0.1就ok了。 ②Java中的小数并没有精确的位数,哪怕你在初始化一个浮点数变量时给它一个有限位数的初始值,比如float a = 1.1,是两位小数,但是你去打印a*a,会发现结果不是1.21。 🍊字符类型 计算机中的字符本质上是一个整数。 C 语言中使用 ASCII 表示字符,而 Java 中使用 Unicode 表示字符。因此一个字符占用两个字节,表示的字符种类更多,包括中文。 char c1 = 'A'; // 大写字母 char c2 = '1'; // 数字字符 System.out.println(c1); System.out.println(c2); char c3 = '帅'; System.out.println(c3); 1 2 3 4 5 6 7 8 这里先简单介绍一下,后续会有专门的章节来讲字符和字符串的。 🍊布尔类型 布尔类型(boolean)常用来表示真假,它只有两种取值,true 表示真,false 表示假。 Java 的 boolean 类型和 int 不能相互转换,不存在1表示 true,0表示false这样的用法!!! 然后值得注意的是,Java虚拟机规范中,并没有明确规定boolean占几个字节。 🍊类型转换 (Java 作为一门强类型编程语言,当不同类型之间的变量相互赋值的时候,会有比较严格的校验。) 在Java中,当参与运算数据类型不一致时,就会进行类型转换。Java中类型转换主要分为两类:自动类型转换(隐式)和强制类型转换(显式)。 🍌自动类型转换(隐式) 代码不需要经过任何处理,在代码编译时,编译器会自动进行处理。 特点:数据范围小的转为数据范围大的时会自动进行。 int a = 100; long b = 10L; b = a; // a和b都是整形,a的范围小,b的范围大,当将a赋值给b时,编译器会自动将a提升为long类型,然后赋值 a = b; // 编译报错,long的范围比int范围大,会有数据丢失,不安全 1 2 3 4 ❓然后不知道你有没有发现这样一个问题,为啥我把byte或short赋为整型值的时候编译器不会报错呢?比如byte = 11; short = 20。 因为Java规定:对于byte,short这两种大小小于4个字节的类型,你对这两种类型的变量进行赋值的时候,只要赋的值的大小不超过这个类型的范围,那么这个值就不会被解析为整型。 比如byte a = 300,因为300已经超过byte的范围,那么此时300就会被当做整型,就会报错了。 🍌强制类型转换(显式) 这个和C语言的差不多,打个比方,强制类型转换就像你现在有一条2米的杆子,你要放进一个1米长的箱子,就只能把它砍短咯。举一些例子让你回忆一下: int a = 10; long b = 100L; b = a; // int-->long,数据范围由小到大,隐式转换 a = (int)b; // long-->int, 数据范围由大到小,需要强转,否则编译失败 float f = 3.14F; double d = 5.12; d = f; // float-->double,数据范围由小到大,隐式转换 f = (float)d; // double-->float, 数据范围由大到小,需要强转,否则编译失败 a = d; // 报错,类型不兼容 a = (int)d; // int没有double表示的数据范围大,需要强转,小数点之后全部丢弃 byte b1 = 100; // 100默认为int,没有超过byte范围,隐式转换 byte b2 = (byte)257; // 257默认为int,超过byte范围,需要显示转换,否则报错 boolean flag = true; a = flag; // 编译失败:类型不兼容 flag = a; // 编译失败:类型不兼容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 总结一下就是: 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型 如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失 将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查 强制类型转换不一定能成功,不相干的类型不能互相转换 🍊类型提升 不同类型的数据之间相互运算时,数据类型小的会被提升到数据类型大的。 ①int与long之间:int会被提升为long int a = 10; long b = 20; int c = a + b; // 编译出错: a + b==>int + long--> long + long 赋值给int时会丢失数据 long d = a + b; // 编译成功:a + b==>int + long--->long + long 赋值给long 1 2 3 4 第三行代码中,a类型提升之后变为long类型,此时long+long结果为long,不能用int类型接收。 ②byte与byte的运算 byte a = 10; byte b = 20; byte c = a + b; System.out.println(c); 1 2 3 4 这段代码编译也会报错,a和b虽然都是byte,但是计算 a + b 会先将 a和b 都提升成 int,再进行计算,得到的结果也是 int,此时赋给c,就会出错。 byte和short这种低于4个字节的类型,会先提升成 int,再参与计算。 原因:计算机的 CPU 通常是按照4个字节为单位从内存中读写数据,为了硬件上实现方便,所以在计算时把它们给提升了。 🍡写在最后 如果你觉得本文写得还不错,不妨点赞收藏关注三连呗! 如果发现本文有不足或不妥之处,欢迎指出,我将第一时间改正。 ———————————————— 版权声明:本文为CSDN博主「Ice_Sugar_7」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/Ice_Sugar_7/article/details/134015650
-
一、实验目的 本实验的目的是让学生使用类来封装对象的属性和功能。 三、实验要求 编写一个简单的Java应用程序,该程序有两个类:Vehicle(用于刻画机动车)和User(主类)。具体要求如下: Vehicle类有个double类型的变量speed,用于刻画机动车的速度,一个int型变量power,用于刻画机动车的功率。类中定义了speedUp(int s)方法,体现机动车有加速功能;定义了speedDown(int d)方法,体现机动车有减速功能;定义了setPower(int p)方法,用于设置机动车的功率;定义了getPower()方法,用于获取机动车的功率。机动车的UML图如图4.2所示。 在主类User的 main()方法中用Vehicle为创建对象,并让该对象调用方法设置功率,演示加速和减速功能。 四、程序效果示例 程序运行效果如图4.3所示。 图4.3 Vehicle类创建对象 运行结果如下: 五、程序模板 请按模板要求,将【代码】替换为Java程序代码。 【Vehicle.java】 public class Vehicle { double speed;//声明double型变量speed,刻画速度 int power; //声明int型变量power,刻画功率 void speedUp(int s) { speed = s+speed;//将参数s的值与成员变量speed的和赋值给成员变量speed } void speedDown(int d) { speed= speed-d; //将成员变量speed与参数d的差赋值给成员变量speed } void setPower(int p) { power = p; //将参数p的值赋值给成员变量power } int getPower() { return power; //返回成员变量power的值 } double getSpeed() { return speed; } } 【User.java】 public class User { public static void main(String args[]) { Vehicle car1, car2; car1 = new Vehicle(); //使用new运算符和默认的构造方法创建对象car1 car2 = new Vehicle();//使用new运算符和默认的构造方法创建对象car2 car1.setPower(128); car2.setPower(76); System.out.println("car1的功率是:"+car1.getPower()); System.out.println("car2的功率是:"+car2.getPower()); car1.speedUp(80);//car1调用speedUp()方法将自己的speed的值增加80 car2.speedUp(80);//car2调用speedUp()方法将自己的speed的值增加80 System.out.println("car1目前的速度:"+car1.getSpeed()); System.out.println("car2目前的速度:"+car2.getSpeed()); car1.speedDown(10); car2.speedDown(20); System.out.println("car1目前的速度:"+car1.getSpeed()); System.out.println("car2目前的速度:"+car2.getSpeed()); } } 五、实验后的练习 (1)改进speedUp()方法,使得Vehicle类的对象在加速时不能将speed值超过200。 void speedUp(int s) { if (s+speed > 200){ this.speed = 200; }else { this.speed = s+speed; };//将参数s的值与成员变量speed的和赋值给成员变量speed } 2. 改进speedDown()方法,使得Vehicle类的对象在减速时不能将speed值小于0。 (4)void speedDown(int d) { if(speed-d < 0){ this.speed=0; } else { this.speed= speed-d; //将成员变量speed与参数d的差赋值给成员变量speed } } (3)增加一个刹车方法void brake(),Vehicle类的对象调用它能将speed的值变成0。 void brake(){ this.speed = 0; } 调用brake: car1.brake(); System.out.println("car1目前的速度:"+car1.getSpeed()); 结果如下: ———————————————— 版权声明:本文为CSDN博主「刘涧茗」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/sziit1609030127/article/details/129509725
-
近期遇到一个问题,之前发布的APP连接蓝牙都是正常的,现在有人反映连不上了。经过测试发现:android 12 和 harmonyOS 3.0.0 都会有这个问题,而之前的版本就不会有这个。 经过网上一番查找,原来是因为最近Google发布的Android 12,新引入了 BLUETOOTH_SCAN、BLUETOOTH_CONNECT、BLUETOOTH_ADVERTISE 三个权限。、 从Android 12开始,过去的蓝牙权限被拆分成了3个新的权限,并且全都是运行时权限(需要动态申请): BLUETOOTH_SCAN 用于使用蓝牙扫描附件其他的蓝牙设备 BLUETOOTH_ADVERTISE 用于允许当前的设备被其他的蓝牙设备所发现 BLUETOOTH_CONNECT 用于连接之前已经配对过的蓝牙设备 这3个权限都是从Android 12系统才开始有的,所以为了能够兼容过去的老版本,建议在AndroidManifest.xml中这样声明: <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> 新增的3个蓝牙权限都是运行时权限,因此只在AndroidManifest.xml中声明是没有用的,还要在代码中动态申请权限才行。必须先在应用中用户明确批准使用,然后才能查找蓝牙设备、使某个设备可被其他设备检测到,或者与已配对的蓝牙设备通信。 具体的申请方法如下:首先要判断当前的系统版本,只有当Android 12及以上系统时,才应该去请求新增的蓝牙权限。(PS:3个权限都属于同一个权限组,因此理论上只要申请一个权限,另外2个也就自动授权了。) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { String[] permission = checkSelfPermissionArray(this, new String[]{ Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_ADVERTISE, Manifest.permission.BLUETOOTH_CONNECT}); if (permission.length > 0) { ActivityCompat.requestPermissions(this, permission, 102); } } 注意: 之前的Android系统中有一个很奇怪的现象,当我们在应用中使用蓝牙扫描附件设备的时候,需要申请地理位置权限。蓝牙权限并不是运行时权限,但地理位置权限却是。 ———————————————— 版权声明:本文为CSDN博主「老杜_d」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/minusn/article/details/128660803
-
定义能计算圆的面积、周长的类 Circle,半径r为私有数据变量,其值由类circle的构造方法初始化,类circle提供读取半径r的方法getr();t算面积的方法area();计算周长的方法circlelength()。再定义类Circlecomputer,其包含程序运行所需的方法main,请设计程序完成初始化数据变量和计算圆的面积、周长并打印出结果。 以下是Java代码实现: public class Circle { private double r; public Circle(double r) { this.r = r; } public double getr() { return r; } public double area() { return Math.PI * r * r; } public double circlelength() { return 2 * Math.PI * r; } } public class Circlecomputer { public static void main(String[] args) { Circle circle = new Circle(3.0); // 初始化圆的半径为3.0 System.out.println("半径为:" + circle.getr()); System.out.println("面积为:" + circle.area()); System.out.println("周长为:" + circle.circlelength()); } } 在Circle类中,我们定义了私有数据变量r,通过构造方法初始化,并提供了读取半径r的方法getr()、计算面积的方法area()和计算周长的方法circlelength()。 在Circlecomputer类中,我们创建一个Circle对象并将半径初始化为3.0,然后调用Circle对象的方法计算面积和周长,并打印输出结果。 ———————————————— 版权声明:本文为CSDN博主「鱼弦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/feng1790291543/article/details/131311635
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签