学会Spring Batch 批处理框架,效率翻倍,上班轻松又快乐

news2024/11/18 1:44:30

一、SpringBatch 介绍

Spring Batch 是一个轻量级、全面的批处理框架,旨在支持开发对企业系统的日常操作至关重要的健壮的批处理应用程序。Spring Batch 建立在人们期望的 Spring Framework 特性(生产力、基于 POJO 的开发方法和一般易用性)的基础上,同时使开发人员可以在必要时轻松访问和使用更高级的企业服务。

Spring Batch 不是一个调度框架。在商业和开源领域都有许多优秀的企业调度程序(例如 Quartz、Tivoli、Control-M 等)。Spring Batch 旨在与调度程序结合使用,而不是替代调度程序。

二、业务场景

我们在业务开发中经常遇到这种情况:

img

Spring Batch 支持以下业务场景:

  • 定期提交批处理。

  • 并发批处理:并行处理作业。

  • 分阶段的企业消息驱动处理。

  • 大规模并行批处理。

  • 失败后手动或计划重启。

  • 相关步骤的顺序处理(扩展到工作流驱动的批次)。

  • 部分处理:跳过记录(例如,在回滚时)。

  • 整批交易,适用于批量较小或已有存储过程或脚本的情况。

三、基础知识

3.1、整体架构

官方文档:https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html#domainLanguageOfBatch

名称作用
JobRepository为所有的原型(Job、JobInstance、Step)提供持久化的机制
JobLauncherJobLauncher表示一个简单的接口,用于启动一个Job给定的集合 JobParameters
JobJob是封装了整个批处理过程的实体
StepStep是一个域对象,它封装了批处理作业的一个独立的顺序阶段

3.2、核心接口

  • ItemReader: is an abstraction that represents the output of a Step, one batch or chunk of items at a time

  • ItemProcessor:an abstraction that represents the business processing of an item.

  • ItemWriter: is an abstraction that represents the output of a Step, one batch or chunk of items at a time.

大体即为 输入数据加工输出 ,一个Job定义多个Step及处理流程,一个Step通常涵盖ItemReaderItemProcessorItemWriter

四、基础实操

4.0、引入 SpringBatch

🔖 pom 文件引入 springboot

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.2.5.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

🔖 pom 文件引入 spring-batch 及相关依赖

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-batch</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
  </dependencies>

🔖 mysql 创建依赖的库表

sql 脚本的 jar 包路径:.....\maven\repository\org\springframework\batch\spring-batch-core\4.2.1.RELEASE\spring-batch-core-4.2.1.RELEASE.jar!\org\springframework\batch\core\schema-mysql.sql

🔖 启动类标志@EnableBatchProcessing

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

🔖FirstJobDemo

@Component
public class FirstJobDemo {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job firstJob() {
        return jobBuilderFactory.get("firstJob")
                .start(step())
                .build();
    }

    private Step step() {
        return stepBuilderFactory.get("step")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("执行步骤....");
                    return RepeatStatus.FINISHED;
                }).build();
    }
}

4.1、流程控制

A、多步骤任务

@Bean
public Job multiStepJob() {
    return jobBuilderFactory.get("multiStepJob2")
            .start(step1())
            .on(ExitStatus.COMPLETED.getExitCode()).to(step2())
            .from(step2())
            .on(ExitStatus.COMPLETED.getExitCode()).to(step3())
            .from(step3()).end()
            .build();
}


private Step step1() {
    return stepBuilderFactory.get("step1")
            .tasklet((stepContribution, chunkContext) -> {
                System.out.println("执行步骤一操作。。。");
                return RepeatStatus.FINISHED;
            }).build();
}

private Step step2() {
    return stepBuilderFactory.get("step2")
            .tasklet((stepContribution, chunkContext) -> {
                System.out.println("执行步骤二操作。。。");
                return RepeatStatus.FINISHED;
            }).build();
}

private Step step3() {
    return stepBuilderFactory.get("step3")
            .tasklet((stepContribution, chunkContext) -> {
                System.out.println("执行步骤三操作。。。");
                return RepeatStatus.FINISHED;
            }).build();
}

B、并行执行

创建了两个 Flow:flow1(包含 step1 和 step2)和 flow2(包含 step3)。然后通过JobBuilderFactorysplit方法,指定一个异步执行器,将 flow1 和 flow2 异步执行(也就是并行)

@Component
public class SplitJobDemo {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job splitJob() {
        return jobBuilderFactory.get("splitJob")
                .start(flow1())
                .split(new SimpleAsyncTaskExecutor()).add(flow2())
                .end()
                .build();

    }

    private Step step1() {
        return stepBuilderFactory.get("step1")
                .tasklet((stepContribution, chunkContext) -> {
                    System.out.println("执行步骤一操作。。。");
                    return RepeatStatus.FINISHED;
                }).build();
    }

    private Step step2() {
        return stepBuilderFactory.get("step2")
                .tasklet((stepContribution, chunkContext) -> {
                    System.out.println("执行步骤二操作。。。");
                    return RepeatStatus.FINISHED;
                }).build();
    }

    private Step step3() {
        return stepBuilderFactory.get("step3")
                .tasklet((stepContribution, chunkContext) -> {
                    System.out.println("执行步骤三操作。。。");
                    return RepeatStatus.FINISHED;
                }).build();
    }

    private Flow flow1() {
        return new FlowBuilder<Flow>("flow1")
                .start(step1())
                .next(step2())
                .build();
    }

    private Flow flow2() {
        return new FlowBuilder<Flow>("flow2")
                .start(step3())
                .build();
    }
}

C、任务决策

决策器的作用就是可以指定程序在不同的情况下运行不同的任务流程,比如今天是周末,则让任务执行 step1 和 step2,如果是工作日,则之心 step1 和 step3。

@Component
public class MyDecider implements JobExecutionDecider {
    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        LocalDate now = LocalDate.now();
        DayOfWeek dayOfWeek = now.getDayOfWeek();

        if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) {
            return new FlowExecutionStatus("weekend");
        } else {
            return new FlowExecutionStatus("workingDay");
        }
    }
}
@Bean
public Job deciderJob() {
 return jobBuilderFactory.get("deciderJob")
   .start(step1())
   .next(myDecider)
   .from(myDecider).on("weekend").to(step2())
   .from(myDecider).on("workingDay").to(step3())
   .from(step3()).on("*").to(step4())
   .end()
   .build();
}
private Step step1() {
 return stepBuilderFactory.get("step1")
   .tasklet((stepContribution, chunkContext) -> {
    System.out.println("执行步骤一操作。。。");
    return RepeatStatus.FINISHED;
   }).build();
}

private Step step2() {
 return stepBuilderFactory.get("step2")
   .tasklet((stepContribution, chunkContext) -> {
    System.out.println("执行步骤二操作。。。");
    return RepeatStatus.FINISHED;
   }).build();
}

private Step step3() {
 return stepBuilderFactory.get("step3")
   .tasklet((stepContribution, chunkContext) -> {
    System.out.println("执行步骤三操作。。。");
    return RepeatStatus.FINISHED;
   }).build();
}


private Step step4() {
 return stepBuilderFactory.get("step4")
   .tasklet((stepContribution, chunkContext) -> {
    System.out.println("执行步骤四操作。。。");
    return RepeatStatus.FINISHED;
   }).build();
}

D、任务嵌套

任务 Job 除了可以由 Step 或者 Flow 构成外,我们还可以将多个任务 Job 转换为特殊的 Step,然后再赋给另一个任务 Job,这就是任务的嵌套。

@Component
public class NestedJobDemo {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    private JobLauncher jobLauncher;
    @Autowired
    private JobRepository jobRepository;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    // 父任务
    @Bean
    public Job parentJob() {
        return jobBuilderFactory.get("parentJob")
                .start(childJobOneStep())
                .next(childJobTwoStep())
                .build();
    }


    // 将任务转换为特殊的步骤
    private Step childJobOneStep() {
        return new JobStepBuilder(new StepBuilder("childJobOneStep"))
                .job(childJobOne())
                .launcher(jobLauncher)
                .repository(jobRepository)
                .transactionManager(platformTransactionManager)
                .build();
    }

    // 将任务转换为特殊的步骤
    private Step childJobTwoStep() {
        return new JobStepBuilder(new StepBuilder("childJobTwoStep"))
                .job(childJobTwo())
                .launcher(jobLauncher)
                .repository(jobRepository)
                .transactionManager(platformTransactionManager)
                .build();
    }

    // 子任务一
    private Job childJobOne() {
        return jobBuilderFactory.get("childJobOne")
                .start(
                    stepBuilderFactory.get("childJobOneStep")
                            .tasklet((stepContribution, chunkContext) -> {
                                System.out.println("子任务一执行步骤。。。");
                                return RepeatStatus.FINISHED;
                            }).build()
                ).build();
    }

    // 子任务二
    private Job childJobTwo() {
        return jobBuilderFactory.get("childJobTwo")
                .start(
                    stepBuilderFactory.get("childJobTwoStep")
                            .tasklet((stepContribution, chunkContext) -> {
                                System.out.println("子任务二执行步骤。。。");
                                return RepeatStatus.FINISHED;
                            }).build()
                ).build();
    }
}

4.2、读取数据

定义 Model TestData,下面同一

@Data
public class TestData {
    private int id;
    private String field1;
    private String field2;
    private String field3;
}

读取数据包含:文本数据读取、数据库数据读取、XML 数据读取、JSON 数据读取等,具体自己查资料。

文本数据读取 Demo

@Component
public class FileItemReaderDemo {

    // 任务创建工厂
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    // 步骤创建工厂
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job fileItemReaderJob() {
        return jobBuilderFactory.get("fileItemReaderJob2")
                .start(step())
                .build();
    }

    private Step step() {
        return stepBuilderFactory.get("step")
                .<TestData, TestData>chunk(2)
                .reader(fileItemReader())
                .writer(list -> list.forEach(System.out::println))
                .build();
    }

    private ItemReader<TestData> fileItemReader() {
        FlatFileItemReader<TestData> reader = new FlatFileItemReader<>();
        reader.setResource(new ClassPathResource("reader/file")); // 设置文件资源地址
        reader.setLinesToSkip(1); // 忽略第一行

        // AbstractLineTokenizer的三个实现类之一,以固定分隔符处理行数据读取,
        // 使用默认构造器的时候,使用逗号作为分隔符,也可以通过有参构造器来指定分隔符
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();

        // 设置属性名,类似于表头
        tokenizer.setNames("id", "field1", "field2", "field3");

        // 将每行数据转换为TestData对象
        DefaultLineMapper<TestData> mapper = new DefaultLineMapper<>();
        // 设置LineTokenizer
        mapper.setLineTokenizer(tokenizer);

        // 设置映射方式,即读取到的文本怎么转换为对应的POJO
        mapper.setFieldSetMapper(fieldSet -> {
            TestData data = new TestData();
            data.setId(fieldSet.readInt("id"));
            data.setField1(fieldSet.readString("field1"));
            data.setField2(fieldSet.readString("field2"));
            data.setField3(fieldSet.readString("field3"));
            return data;
        });
        reader.setLineMapper(mapper);
        return reader;
    }

}

4.3、输出数据

输出数据也包含:文本数据读取、数据库数据读取、XML 数据读取、JSON 数据读取等

Component
public class FileItemWriterDemo {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Resource(name = "writerSimpleReader")
    private ListItemReader<TestData> writerSimpleReader;

    @Bean
    public Job fileItemWriterJob() throws Exception {
        return jobBuilderFactory.get("fileItemWriterJob")
                .start(step())
                .build();
    }

    private Step step() throws Exception {
        return stepBuilderFactory.get("step")
                .<TestData, TestData>chunk(2)
                .reader(writerSimpleReader)
                .writer(fileItemWriter())
                .build();
    }

    private FlatFileItemWriter<TestData> fileItemWriter() throws Exception {
        FlatFileItemWriter<TestData> writer = new FlatFileItemWriter<>();

        FileSystemResource file = new FileSystemResource("D:/code/spring-batch-demo/src/main/resources/writer/writer-file");
        Path path = Paths.get(file.getPath());
        if (!Files.exists(path)) {
            Files.createFile(path);
        }
        // 设置输出文件路径
        writer.setResource(file);

        // 把读到的每个TestData对象转换为JSON字符串
        LineAggregator<TestData> aggregator = item -> {
            try {
                ObjectMapper mapper = new ObjectMapper();
                return mapper.writeValueAsString(item);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return "";
        };

        writer.setLineAggregator(aggregator);
        writer.afterPropertiesSet();
        return writer;
    }

}

4.5、处理数据

@Component
public class ValidatingItemProcessorDemo {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Resource(name = "processorSimpleReader")
    private ListItemReader<TestData> processorSimpleReader;

    @Bean
    public Job validatingItemProcessorJob() throws Exception {
        return jobBuilderFactory.get("validatingItemProcessorJob3")
                .start(step())
                .build();
    }

    private Step step() throws Exception {
        return stepBuilderFactory.get("step")
                .<TestData, TestData>chunk(2)
                .reader(processorSimpleReader)
                .processor(beanValidatingItemProcessor())
                .writer(list -> list.forEach(System.out::println))
                .build();
    }

//    private ValidatingItemProcessor<TestData> validatingItemProcessor() {
//        ValidatingItemProcessor<TestData> processor = new ValidatingItemProcessor<>();
//        processor.setValidator(value -> {
//            // 对每一条数据进行校验
//            if ("".equals(value.getField3())) {
//                // 如果field3的值为空串,则抛异常
//                throw new ValidationException("field3的值不合法");
//            }
//        });
//        return processor;
//    }

    private BeanValidatingItemProcessor<TestData> beanValidatingItemProcessor() throws Exception {
        BeanValidatingItemProcessor<TestData> beanValidatingItemProcessor = new BeanValidatingItemProcessor<>();
        // 开启过滤,不符合规则的数据被过滤掉;
//        beanValidatingItemProcessor.setFilter(true);
        beanValidatingItemProcessor.afterPropertiesSet();
        return beanValidatingItemProcessor;
    }

}

4.6、任务调度

可以配合 quartz 或者 xxljob 实现定时任务执行

@RestController
@RequestMapping("job")
public class JobController {

    @Autowired
    private Job job;
    @Autowired
    private JobLauncher jobLauncher;

    @GetMapping("launcher/{message}")
    public String launcher(@PathVariable String message) throws Exception {
        JobParameters parameters = new JobParametersBuilder()
                .addString("message", message)
                .toJobParameters();
        // 将参数传递给任务
        jobLauncher.run(job, parameters);
        return "success";
    }
}

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

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

相关文章

uniapp-TypeError: Cannot convert undefined or null to object

问题详情 INFO Starting development server...ERROR TypeError: Cannot convert undefined or null to object TypeError: Cannot convert undefined or null to objectat Function.assign (<anonymous>)at uniapp-cli\node_modules\dcloudio\vue-cli-plugin-uni\lib…

Java EE企业级应用开发(SSM)第7章

第7章Spring MVC拦截器 一.预习笔记 1.拦截器是一个运行在服务器端的程序&#xff0c;主要用于拦截用户的请求并进行相应的处理&#xff0c;即实现对控制器请求的预处理或后处理 2.拦截器的实现 2-1&#xff1a;实现Spring的HandlerInterceptor接口 2-2&#xff1a;实现Spri…

基于html+css的图片展示17

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

Activiti的基本使用

目录 1、Activiti使用 1.1、数据库支持 1.2、Activiti环境 1.2.1、引入依赖 1.2.2、添加配置 1.2.3、启动项目 1.2.4、数据库表介绍 1.3、Activiti常用Service服务接口 1.4、流程设计工具 1.4.1、下载activiti-explorer 1.4.2、解压获取部署包 1.4.3、部署activiti…

mysql的启动关闭原理和实战,及常见的错误排查

前言 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDBMS (Relational Database Management System&#xff0c;关系…

【数据结构】顺序表和链表(上)(附leetcode练习题)

☃️个人主页&#xff1a;fighting小泽 &#x1f338;作者简介&#xff1a;目前正在学习C语言和数据结构 &#x1f33c;博客专栏&#xff1a;数据结构 &#x1f3f5;️欢迎关注&#xff1a;评论&#x1f44a;&#x1f3fb;点赞&#x1f44d;&#x1f3fb;留言&#x1f4aa;&…

春秋云境:CVE-2022-30887(文件上传漏洞)

目录 一.题目 二.蚁剑方式 三.POC方式 一.题目 该CMS中php_action/editProductImage.php存在任意文件上传漏洞&#xff0c;进而导致任意代码执行。 进入页面&#xff1a;登录页面 随意输入用户名和密码&#xff1a;admingmail.com admin 用于burp抓包&#xff1a; burp抓包…

基于PCL抓取Velodyne激光雷达数据包可视化

Velodyne 高清激光雷达 (HDL) 采集器 Velodyne HDL 是一种基于网络的 3D LiDAR 系统&#xff0c;每秒生成包含超过 700,000 个点的 360 度点云。 PCL 中提供的 HDL Grabber 模仿其他 Grabbers&#xff0c;使其几乎可以即插即用。 然而&#xff0c;由于 HDL 设备是基于网络的&…

线性表总结

线性表 目录&#xff1a; 文章目录 线性表概念一、线性表的定义二、线性表的基本操作三、线性表的实现方式四、线性表的应用总结 概念 线性表是一种基本的数据结构&#xff0c;由一系列具有相同类型的数据元素构成&#xff0c;这些元素之间具有线性的顺序关系&#xff0c;每个…

python+vue+django旅游景点酒店线路套餐管理系统

1.查询旅游信息:主要查询景点和酒店的信息&#xff0c;可以进行分类查询也可以用关键在字来查询用户需要的信息。 2.留言功能:用户可以查看别人以前的留言&#xff0c;也可以发表新的留言。. 3.酒店预定:当用户查询到相关酒店&#xff0c;并且可以能够申请相关酒店预定。 4.信息…

【人工智能】— 一阶逻辑、量词的推理规则、一般化分离规则、合一、前向/反向链接算法、归结算法

这里写自定义目录标题 量词的推理规则全称量词实例化存在量词实例化 简化到命题逻辑推理Generalized Modus Ponens&#xff08;一般化分离规则&#xff09;举例 合一Forward chaining 前向链接算法示例 Backward chaining algorithm 反向链接算法一般FOL的FC/BC的完整性 归结算…

系统分析师选择题笔记

目录 1、知识产权与标准化 1.1 保护范围与对象(★★★★) 1.2 保护期限(★) 1.3 知识产权人确定(★★★) 1.4 侵权判断(★★★) 1.5 标准的分类(★) 1.6 标准代号的识别(★) 2、系统配置与性能评价 2.1 系统性能概述 2.2 系统性能&#xff08;性能指标&#xff09;(★…

8款数据迁移工具选型,主流且实用

前言&#xff1a;ETL(是Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程)&#xff0c;对于企业应用来说&#xff0c;我们经常会遇到各种数据的处理、转换、迁移的场景。今天特地给大家汇总了一些目前市面上比较常用的ETL数据迁移工具&#xff0c;希望对…

什么是B/S架构?

目录 一.什么是B/S架构&#xff1f; 二.B/S架构与C/S架构有什么区别&#xff1f; 三.B/S架构的优缺点 四.B/S架构的几种形式 1&#xff1a;客户端-服务器-数据库 2&#xff1a;客户端&#xff0d;web服务器&#xff0d;应用服务器&#xff0d;数据库 3&#xff1a;客户端…

4个方法助你从戴尔笔记本电脑D盘中恢复丢失的文件

用户案例&#xff1a; 案例1&#xff1a;我有一台戴尔笔记本电脑&#xff0c;D盘上存储了很多个人照片和视频&#xff0c;但最近不知道什么原因&#xff0c;这些数据突然全部消失了。因为这些数据是我珍贵的回忆。所以想问问大家戴尔电脑丢失d盘文件怎么恢复&#xff1f; 案例2…

网络中的网关和物联网的网关区别 局域网 路由器 交换机 服务器

网关&#xff1a;是个概念。连接两种不同的网络。例如局域网要与外部通信&#xff0c;需要经过网关。 设备和设备之间的通信&#xff0c;转换协议需要网关 路由器里有功能是对网关这个概念的实现。 所以网关它可以是路由器&#xff0c;交换机或者是PC。 路由器有网关功能&a…

Flink-Scala版学习——转换算子

目录 一、基本转换算子 1.map 2.filter 3.flatMap 3.聚合算子Aggregation (1)keyBy (2)简单聚合&#xff1a;sum、min、minBy、max、maxBy (3)归约聚合&#xff1a;reduce 二、UDF 三、富函数类 四、物理分区 1.随机分区(shuffle) 2. 轮询分区&#xff08;Round-R…

4月20日第壹简报,星期四,农历三月初一,谷雨

4月20日第壹简报&#xff0c;星期四&#xff0c;农历三月初一&#xff0c;谷雨坚持阅读&#xff0c;静待花开1. 已致29人死亡&#xff0c;26人为患者&#xff01;北京长峰医院火灾事故因院内施工作业火花引发&#xff0c;院长王某玲等12人被刑拘。2. 海南发布旅游产品参考价格&…

第二十三章 案例TodoList之数据更新

本小节&#xff0c;我们要实现点击复选框&#xff0c;修改任务项的实时状态&#xff0c;但是Item组件和App组件是祖孙关系&#xff0c;不是父子关系&#xff0c;我们还能使用props进行通信吗&#xff1f;答案是可以的。 在App组件定义一个更新的函数并传递给Item组件 1、定义…

车载网络 - Autosar网络管理 - 网络管理报文

三、网络管理报文 NM报文的ID一般定义为&#xff1a;基础ID源地址&#xff0c;每个节点应分配一个唯一的标识符&#xff08;ECU地址&#xff09;Node_ID&#xff0c;网络管理报文一般会统一一个基地址&#xff0c;这个是根据主机厂不同而不同&#xff0c;有些是用0x400 - 0x4FF…