十八、Stream 流

news2024/11/29 12:39:31

目录

1、为什么要引入SpringCloud Stream

2、SpringCloud Stream简介

2.1、标准MQ架构图

2.2、SpringCloud Stream架构图

2.3、SpringCloud Stream处理流程

3、如何使用SpringCloud Stream

3.1、创建springcloud-stream-sender项目(消息生产者)

3.1.1、在pom文件中引入依赖

3.1.2、添加application.yml并配置

3.1.3、创建启动类

3.1.4、创建Service服务,发送消息到MQ

3.1.5、创建Controller对外提供接口服务

 3.2、创建springcloud-stream-consumer项目(消息消费者)

3.2.1、在pom文件中引入依赖

3.2.2、添加application.yml并配置

3.2.3、创建启动类

3.2.4、编写消息接收类,监听消费消息

3.3、启动RabbitMQ服务器,访问管理页面http://localhost:15672/

3.4、启动springcloud-stream-sender消息生产者和springcloud-stream-consumer消息消费者服务

3.5、使用IDEAJ自带的http client发送一个post请求到消息生产者

4、SpringCloud Stream集群消费

5、切换消息中间件(RabbitMQ--->Kafka)

5.1、修改springcloud-stream-sender项目

5.2、修改springcloud-stream-consumer项目

5.3、启动Zookeeper、Kafka(服务器)、send(消息生产者)、consumer(消息消费者)

6、自定义通道名称

6.1、自定义输出通道(发布消息)

6.1.1、创建接口MyOutput

6.1.2、修改消息发送服务注解@EnableBinding

6.1.3、修改配置application.yml文件

6.2、自定义输入通道(接收消息)

6.2.1、创建接口

6.2.2、修改消息接收监听服务注解@EnableBinding

6.2.3、修改配置application.yml文件


1、为什么要引入SpringCloud Stream

在实际的企业开发中,消息中间件是至关重要的组件之一。主要解决服务解耦、异步消费、流量削峰等问题。实现高性能、高可用、高扩展和最终一致性架构。不同消息中间件的实现方式和内部结构不一致,如常见的RabbitMQ和Kafka,由于这两个消息中间件的架构不同,像RabbitMQ有exchange,Kafka有topic和partition分区,这些中间件的差异给我们项目开发造成了一定的困扰,如果选择了其中一种消息中间件,由于中间件的差异性,一旦业务需要迁移部分消息队列到其他的消息中间件,这将是一件灾难性的工作,很多工作需要推到重新做,因为消息中间件和项目耦合了,这时候SpringCloud Stream给我们带来了福音,它给我们提供了一种解耦方式,我们不需要关注具体使用的是什么MQ,它会自动的给我们在各种MQ内切换。

引入SpringCloud Stream的目的:屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型(解耦)

2、SpringCloud Stream简介

   SpringCloud Stream是一个用来为微服务应用构建消息驱动能力的框架,它可以基于SpringBoot来创建独立的、可用于生产的Spring应用程序。同时为一些供应商的消息中间件产品提供了个性化的自动化配置实现,并引入了发布-订阅、消费组、分区这三个核心概念。

通过使用 SpringCloud Stream可以有效简化开发人员对消息中间件的使用复杂度,让系统开发人员可以有更多的精力关注于核心业务的逻辑实现。但是目前SpringCloud Stream只支持RabbitMQ和Kafka的自动化配置。

SpringCloud Stream是一个构建消息驱动微服务的框架。应用程序通过inputs或者outputs来与SpringCloud Stream中的binder对象交互。

2.1、标准MQ架构图

 

·  生产者/消费者之间靠消息媒介Message传递信息内容

·  消息必须走特定的消息通道MessageChannel

·  消息通道里的消息,消费和收发都是靠消息通道的子接口SubscribableChannel,由MessageHandler消息处理器所订阅

2.2、SpringCloud Stream架构图

 

Middleware中间件,目前只支持RabbitMQ和Kafka

Binder是应用与消息中间件之间的封装,完美地实现了应用程序与消息中间件细节之间的隔离,目前实现了Kafka和RabbitMQ的Binder,通过Binder可以很方便的连接中间件,可以动态的改变消息类型(对应于Kafka的topic,RabbitMQ的exchange),这些都可以通过配置文件来实现

@Input注解标识输入通道,通过该输入通道接收的消息进入应用程序

@Output注解标识输出通道,发布的消息将通过该通道离开应用程序

@StreamListener监听队列,用于消费者的队列的消息接收

@EnableBinding指信道channel和exchange绑定在一起

2.3、SpringCloud Stream处理流程

 

Binder:很方便的连接中间件,屏蔽差异
Channel:通道,是队列Queue的一种抽象,在消息通讯系统中就是实现存储和转发的媒介,通过Channel对队列进行配置。
Source和Sink:简单的可理解为参照对象是SpringCloud Stream自身,从Stream发布消息就是输出,接受消息就是输入。

Source:org.springframework.cloud.stream.messaging.Source

Sink:org.springframework.cloud.stream.messaging.Sink

3、如何使用SpringCloud Stream

3.1、创建springcloud-stream-sender项目(消息生产者)

3.1.1、在pom文件中引入依赖

<!--引入web模块-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入SpringCloud Stream依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

3.1.2、添加application.yml并配置

server:
  port: 9061
spring:
  application:
    name: stream-sender
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings: #服务的整合处理
        output: #通道名称,根据@EnableBinding配置的类里的属性OUTPUT的值来配
          destination: TestExchange #Exchange名称,消息目的地
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型

3.1.3、创建启动类

@SpringBootApplication
public class SenderApp {
    public static void main( String[] args ) {
        SpringApplication.run(SenderApp.class,args);
    }
}

3.1.4、创建Service服务,发送消息到MQ

注意包不要引入错了

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;

//属性为org.springframework.cloud.stream.messaging下的Source类
@EnableBinding(Source.class)
public class SendService {

    @Resource
    MessageChannel output;

    @PostMapping("/send")
    public Boolean sendMsg(String msg){
        //MessageBuilder是org.springframework.messaging.support下,注意不要引错包
        boolean result = this.output.send(MessageBuilder.withPayload(msg).build());
        return result;
    }
}

@EnableBinding(Source.class)

 3.1.5、创建Controller对外提供接口服务

@RestController
public class SendController {

    @Resource
    private SendService sendService;

    @PostMapping("/send")
    public String send(){
        String msg="测试信息";
        Boolean result = this.sendService.sendMsg(msg);
        System.out.println("send msg status:  "+result);
        return "发送成功";
    }
}

 3.2、创建springcloud-stream-consumer项目(消息消费者)

3.2.1、在pom文件中引入依赖

<!--引入web模块-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入SpringCloud Stream依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

3.2.2、添加application.yml并配置

server:
  port: 9062
spring:
  application:
    name: stream-consumer
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings: #服务的整合处理
        input: #通道名称
          destination: TestExchange #Exchange名称
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型

Springcloud stream配置基本和生产者sender端一样,只是把bindings下的output改成input

3.2.3、创建启动类

@SpringBootApplication
public class ConsumerApp {
    public static void main( String[] args ) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

3.2.4、编写消息接收类,监听消费消息

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;

@EnableBinding(Sink.class)
public class MsgListener {

    @Value("${server.port}")
    private String port;

    @StreamListener(Sink.INPUT)
    public void listener(Message<String> msg){
        System.out.println("消费端接受的消息是:  "+msg+"------port: "+port);
    }
}

3.3、启动RabbitMQ服务器,访问管理页面http://localhost:15672/

管理页面默认端口号为15672

3.4、 启动springcloud-stream-sender消息生产者和springcloud-stream-consumer消息消费者服务

springcloud-stream-sender:http://localhost:9061

springcloud-stream-consumer:http://localhost:9062

重新访问RabbitMQ的管理界面,可以看到多了一个Exchange,就是我们在配置文件里配置的Exchange名称

3.5、使用IDEAJ自带的http client发送一个post请求到消息生产者

http://localhost:9061/send

 可以看到返回发送成功的提示

查看消息生产者的后台日志

 查看消息消费者的后台日志

 可以看到消息的内容是GenericMessage

消费端接受的消息是:

 GenericMessage[
payload=测试信息, 
headers={
amqp_receivedDeliveryMode=PERSISTENT, amqp_receivedExchange=TestExchange, 
amqp_deliveryTag=1,
 deliveryAttempt=1, amqp_consumerQueue=TestExchange.anonymous.gXVX6rHVSQWlXf7SasUwvQ, amqp_redelivered=false, 
amqp_receivedRoutingKey=TestExchange, 
amqp_timestamp=Fri Apr 28 12:36:31 CST 2023, amqp_messageId=fadf505d-92e9-e54c-c86b-62d577e4706b, id=fe3521c0-eeb7-c85b-c6be-43ce6c23bd92, amqp_consumerTag=amq.ctag-R7q-QWuU7PNqfmYOU5y9oQ, 
sourceData=(Body:'测试信息' MessageProperties [headers={}, timestamp=Fri Apr 28 12:36:31 CST 2023, messageId=fadf505d-92e9-e54c-c86b-62d577e4706b, contentType=application/json, 
contentLength=0, 
receivedDeliveryMode=PERSISTENT, 
priority=0, 
redelivered=false, 
receivedExchange=TestExchange, 
receivedRoutingKey=TestExchange,
deliveryTag=1, 
consumerTag=amq.ctag-R7q-QWuU7PNqfmYOU5y9oQ, consumerQueue=TestExchange.anonymous.gXVX6rHVSQWlXf7SasUwvQ]), contentType=application/json,
timestamp=1682656592010}]------port: 9062

4、SpringCloud Stream集群消费

4.1、修改springcloud-stream-consumer的配置文件,将端口号改为9063,运行springcloud-stream-consumer的启动类启动服务

4.2、这样就形成了一个集群

4.3、 再次请求http://localhost:9061/send发送消息

4.4、查看消费者端的控制台打印信息

 可以看到消费者A、消费者B都打印了消息,即造成了消息重复消费的问题

4.5、如果消息生产者发送消息过程中,生产者发送消息成功,但是消费者A、消费者B在消息发送过程中由于某些原因宕机了,但是重启后没有消费消息,这导致了消息丢失。

4.6、解决消息重复消费和消息丢失的问题,只要在消息消费端配置消费者组就可以解决这个问题

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings: #服务的整合处理
        input: #通道名称
          destination: TestExchange #Exchange名称
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型
          group: cousumer_group #配置消费者组解决消息重复消费和丢失问题

4.7、使用http://localhost:9061/send发送6条消息

4.8、 查看消费者A、消费者B的控制台

 

 可以看到消费者A、消费者B各消费了3条消息,解决了重复消费

4.9、关掉消费者A、消费者B服务器后,使用http://localhost:9061/send发送3条消息,重新启动消费者A、消费者B服务器,查看消费者A、消费者B的控制台

 

 

消费者A消费了三条消息

消费者B没有消费消息

这样就解决了消息丢失、消息重复消费的问题

关掉消费者A、消费者B服务器后,使用http://localhost:9061/send发送3条消息后查看RabbitMQ的管理页面,可以看到有3条消息待消费

 重启重新启动消费者A、消费者B服务器后刷新界面,消息被消费者消费了

 5、切换消息中间件(RabbitMQ--->Kafka)

5.1、修改springcloud-stream-sender项目

5.1.1、在pom文件中引入Kafka依赖

<!--引入kafka依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

5.1.2、改造springcloud-stream-sender项目配置文件结构

主配置文件application.yml配置如下

server:
  port: 9061
spring:
  application:
    name: stream-sender
  profiles:
    active: kafka   #激活kafka配置文件
#    active: rabbit

application-rabbit.yml配置如下

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings: #服务的整合处理
        output: #通道名称,根据@EnableBinding配置的类里的属性OUTPUT的值来配
          destination: TestExchange #Exchange名称,消息目的地
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型

application-kafka.yml配置如下

spring:
  cloud:
    stream:
      kafka:  #kafka的连接地址
        binder:
          brokers: localhost:9092
      bindings: #服务的整合处理
        output:
          destination: TestTopic #Exchange名称
          context-type: application/json #设置消息的类型
          binder: kafka #设置要绑定的消息服务类型

5.2、修改springcloud-stream-consumer项目

5.2.1、在pom文件中引入Kafka依赖

<!--引入kafka依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

5.2.2、改造springcloud-stream-consumer项目配置文件结构

主配置文件application.yml配置如下

server:
  port: 9062
spring:
  application:
    name: stream-consumer
  profiles:
    active: kafka  #激活kafka配置文件
#    active: rabbit

application-rabbit.yml配置如下

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings: #服务的整合处理
        input: #通道名称
          destination: TestExchange #Exchange名称
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型
          group: cousumer_group #配置消费者组解决消息重复消费和丢失问题

application-kafka.yml配置如下

spring:
  cloud:
    stream:
      kafka:  #kafka的连接地址
        binder:
          brokers: localhost:9092
      bindings: #服务的整合处理
        input:
          destination: TestTopic #Exchange名称
          context-type: application/json #设置消息的类型
          binder: kafka #设置要绑定的消息服务类型
          group: consumer_group #配置消费者组解决消息重复消费和丢失问题

5.3、启动Zookeeper、Kafka(服务器)、send(消息生产者)、consumer(消息消费者)

本地启动Zookeeper、Kafka时需要修改的配置文件可百度查询

6、自定义通道名称

参照Source与Sink的格式自定义输入输出通道名称

Source:org.springframework.cloud.stream.messaging.Source

Sink:org.springframework.cloud.stream.messaging.Sink

6.1、自定义输出通道(发布消息)

6.1.1、创建接口MyOutput

public interface MyOutput {
    String OUTPUT = "MyOutput";

    @Output("MyOutput")
    MessageChannel output();
}

6.1.2、修改消息发送服务注解@EnableBinding

//属性为org.springframework.cloud.stream.messaging下的Source类
//@EnableBinding(Source.class)
@EnableBinding(MyOutput.class)
public class SendService {

    @Resource
    MessageChannel MyOutput;

    @PostMapping("/send")
    public Boolean sendMsg(String msg){
        //MessageBuilder是org.springframework.messaging.support下,注意不要引错包
        boolean result = this.MyOutput
.send(MessageBuilder.withPayload(msg).build());
        return result;
    }
}

6.1.3、修改配置application.yml文件

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings: #服务的整合处理
        output: #通道名称,根据@EnableBinding配置的类里的属性OUTPUT的值来配
          destination: TestExchange #Exchange名称,消息目的地
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型
        MyOutput: #通道名称,根据@EnableBinding配置的类里的属性OUTPUT的值来配
          destination: MyOutputExchange #Exchange名称,消息目的地
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型

 可以定义多个通道,每个通道可以配置自己独立的消息中间件(可以rabbit,也可以kafka)

6.2、自定义输入通道(接收消息)

6.2.1、创建接口

public interface MyInput {
    String INPUT = "MyInput";

    @Input("MyInput")
    SubscribableChannel input();
}

 6.2.2、修改消息接收监听服务注解@EnableBinding

//@EnableBinding(Sink.class)
@EnableBinding(MyInput.class)
public class MsgListener {

    @Value("${server.port}")
    private String port;

    @StreamListener(MyInput.INPUT)
    public void listener(Message<String> msg){
        System.out.println("消费端接受的消息是:  "+msg+"------port: "+port);
    }
}

 

6.2.3、修改配置application.yml文件

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings: #服务的整合处理
        input: #通道名称
          destination: TestExchange #Exchange名称
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型
          group: cousumer_group #配置消费者组解决消息重复消费和丢失问题
        MyInput: #通道名称
          destination: MyOutputExchange #Exchange名称,与对应的输出绑定同一个Exchange
          context-type: application/json #设置消息的类型
          binder: rabbit #设置要绑定的消息服务类型
          group: myoutput_group #配置消费者组解决消息重复消费和丢失问题

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud_服务调用_Ribbon负载算法简介与如何替换(二)

SpringCloud_服务调用_Ribbon负载算法简介与如何替换(二) Ribbon核心组件IRule IRule:根据特定算法中从服务列表中选取一个要访问的服务 IRule接口有多种实现&#xff1a; Ribbon自带的7种负载规则 com.netflix.loadbalancer.RoundRobinRule 轮询 com.netflix.loadbalancer.Ra…

8年测试老鸟总结,软件测试工程师关键成长晋升要素,这些不能不知道...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、技术-依然是最…

MySQL深入浅出:自增长序列(@i:=@i+1)的用处及用法

目录 1&#xff1a;问题分析 2&#xff1a;模拟自增长序列 2.1 单表查询 2.2 多表关联查询 3&#xff1a;结束语 社区 1&#xff1a;问题分析 Oracle中的伪列 ROWNUM 是一组递增的序列&#xff0c;在查询数据时生成&#xff0c;为结果集中每一行标识一个行号, 每条记录…

医院运维场景下的风险感知

随着医疗信息化建设发展&#xff0c;医院的系统、设备不断叠加&#xff0c;在提升用户体验&#xff0c;享受高效医疗服务的同时&#xff0c;也为支撑系统稳定运行的信息部门带来巨大挑战。诸如科室复杂、应用场景多、终端运维工作量大、软件系统兼容需求强等痛点&#xff0c;并…

WPF MaterialDesign 初学项目实战(0):github 项目Demo运行

前言&#xff1a; 最近在学B站的WPF项目实战合集(2022终结版)&#xff0c;但是到22P时候发现UI框架 MaterialDesignThemes的Github上面的程序没办法正常运行&#xff0c;最后折腾了好久终于解决。 github地址 gitcode镜像地址 下载成功后 下载成功后是如下效果 打开这个文…

259元,诺基亚返祖式新机玩了把大的

智能手机经过这么多年发展&#xff0c;市场逐渐趋向成熟。 在这个过程中&#xff0c;优胜劣汰这一自然法则同样适用&#xff0c;无数没能经受住市场考验的企业也只能含泪离场。 其中最典型的例子还得是曾经手机中的王者诺基亚了。 当初在 Symbian&#xff08;塞班系统&#x…

php event原理以及对象与属性赋值

1、定义时间原理 2、定义对象与对象与属性赋值 ps:赋值过程其实会通过魔术方法_get调动本类的set方法 来源B站大佬视频 4.Yii2.0 Advanced Object与Property的关系_哔哩哔哩_bilibili

刚入职,就想跑路了...

刚入职一家公司&#xff0c;想离职又怕找不到新工作。 说实话&#xff0c;这个问题还是蛮常见的&#xff0c;很多时候&#xff0c;入职的公司并不是自己最满意的&#xff0c;即使是最满意的&#xff0c;入职后总会遇到各种各样的不顺心&#xff0c;公司制度不规范啊&#xff0…

C++ 图进阶系列之剖析二分图的染色算法和匈牙利算法

1. 前言 二分图又称作二部图或称为偶图&#xff0c;是图论中的一种特殊类型&#xff0c;有广泛的应用场景。 什么是二分图&#xff1f; 二分图一般指无向图。看待问题要有哲学思想&#xff0c;有二分图也可以是有向图。 如果图中所有顶点集合能分成两个独立的子集&#xff0…

常用好用的远程连接工具分享

1、RayLink 介绍&#xff1a; RayLink它是一款功能强大的远程控制软件&#xff0c;支持Windows、macOS、IOS以及Android等多种操作系统。同时&#xff0c;它还提供了手机端和桌面端两种不同的应用程序&#xff0c;可以通过手机控制电脑&#xff0c;也可以通过电脑控制手机。这…

C语言编程软件

C语言是一门历史很长的编程语言&#xff0c;其编译器和开发工具也多种多样&#xff0c;其开发工具包括编译器&#xff0c;现举几个开发工具供大家选择&#xff0c;当然也要根据自己的操作系统来选择适合自己的开发工具。 好多刚开始接触c语言的朋友都想知道用上面软件开发c语言…

【JavaScript数据结构与算法】字符串类(计算二进制子串)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端&#xff08;Node.js&#xff09; &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;…

Grafana之Graph Panel使用(05)

Graph是Grafana的原生插件。使用Graph Panel,可以将数据展示成折线、条状、点状等风格。Graph是Grafana展示数据的缺省图形面板,它提供了一组非常丰富的绘图选项。 ① Panel options(面板选项)主要包括:Title(标题);Description(描述) ②Tooltip(鼠标经过图例展示数据效果)…

数字产品在教育行业的应用:关键特点和必备功能概览

数字化转型的浪潮已经席卷了各行各业&#xff0c;不仅出现在互联网、电商、建筑等行业&#xff0c;还应用在了教育行业。数字化的教育ERP软件能够在满足学校需求的基础上&#xff0c;帮助学校完善各类工作流程&#xff0c;提高工作效率。 对于一个拥有多个校区&#xff0c;上万…

LAY-EXCEL实现导入和导出excel功能

lay-excel 是一款开源的、基于 Google Sheets 的免费的在线数据表格库。它使用了 Google Sheets 的开源代码&#xff0c;并进行了本地化处理&#xff0c;以适应中国用户的使用习惯。 lay-excel 提供了丰富的数据表格类型&#xff0c;包括常见的表格、表格拆分、表格计算、图表等…

JAVA并发专题(1)之操作系统底层工作的整体认识

一、分诺依曼计算机模型 现代计算机模型是基于-冯诺依曼计算机模型&#xff0c;计算机在运行时&#xff0c;先从内存中取出第一条指令&#xff0c;通过控制器的译码&#xff0c;按指令的要求&#xff0c;从存储器中取出数据进行指定的运算和逻辑操作等加工&#xff0c;然后再按…

irq_domain 负责的事情以及小组成员分担的任务

文章目录 简介irq_domain 要做哪些事irq_desc 结构图irq_domain 小组的重要成员有哪些irq_domain 小组的重要成员解析irq_domain 的左膀右臂 irq_chip & irq_domain_opsirq_chip 分担了哪些工作irq_domain_ops 分担了哪些工作 其他成员分担了哪些工作 irq_desc 怎么与 irq …

小程序技术助力智慧家居生态互联

随着科技的不断发展&#xff0c;智能终端设备已经成为人们生活中不可或缺的一部分。不仅可以通过智能手机、平板电脑等设备方便地获取信息和进行沟通&#xff0c;现在还可以通过智能电视、智能冰箱等终端设备运行小程序&#xff0c;为人们提供更加便捷的生活体验。 智能终端设…

C1 计算机系统概论

目录 计算机系统简介 计算机的基本组成 计算机硬件的主要技术指标 计算机系统简介 计算机的基本组成 运算器控制器->中央处理器CPU 输入设备输出设备->I/O设备 运算器&#xff1a;ALU 三个寄存器ACC、X、MQ控制器&#xff1a;CU 两个寄存器IR、PC主存储器&#x…

解决css背景图覆盖文字

项目需求&#xff1a;这是个导航栏&#xff08;下面是uveiw的tabs标签&#xff09;&#xff0c;然后高亮的时候会有一个背景图&#xff0c;因为title不固定字数&#xff0c;所以宽度不能写死。 想要的效果 做出来的效果 自己写了个样式&#xff0c;用scroll-view&#xff0…