Spring高手之路18——从XML配置角度理解Spring AOP

文章目录

  • 1. Spring AOP与动态代理
    • 1.1 Spring AOP和动态代理的关系
    • 1.2 AOP基本术语
  • 2. 通过XML配置实现Spring AOP
    • 2.1 添加Spring依赖
    • 2.2 定义业务接口和实现类
    • 2.3 定义切面类
    • 2.4 配置XML

1. Spring AOP与动态代理

1.1 Spring AOP和动态代理的关系

  Spring AOP使用动态代理作为其主要机制来实现面向切面的编程。这种机制允许Spring在运行时动态地创建代理对象,这些代理对象包装了目标对象(即业务组件),以便在调用目标对象的方法前后插入额外的行为(如安全检查、事务管理、日志记录等)。

  • JDK动态代理:当目标对象实现了一个或多个接口时,Spring AOP默认使用JDK的动态代理。JDK动态代理通过反射机制,为接口创建一个代理对象,这个代理对象会拦截对目标接口方法的所有调用。

  • CGLIB代理:如果目标对象没有实现任何接口,Spring AOP会退回到使用CGLIB库生成目标类的子类。CGLIBCode Generation Library)是一个强大的高性能代码生成库,它在运行时扩展了Java类,并在子类中覆盖了方法来实现方法拦截。

无论使用哪种代理方式,目的都是在不改变原有业务逻辑代码的基础上,通过切面定义的通知在方法执行的不同阶段插入附加行为。

1.2 AOP基本术语

  1. 切面(Aspect):切面是面向切面编程的核心,它是将横跨多个类的关注点(如日志记录、事务管理等)模块化的构造。一个切面可以包含多种类型的通知(Advice)和一个或多个切点(Pointcut),用于定义在何处以及何时执行这些通知。

  2. 连接点(Join Point):连接点代表程序执行过程中的某个特定位置,Spring AOP限定这些位置为方法的调用。简而言之,连接点就是能够插入切面通知的点。

  3. 通知(Advice):通知定义了切面在连接点上要执行的动作。根据通知类型的不同,这些动作可以在方法调用之前、之后、返回结果后或抛出异常时执行。通知类型包括:

  • 前置通知(Before advice):在方法执行之前执行。
  • 后置通知(After advice):在方法执行后执行,无论其结果如何。
  • 返回后通知(After-returning advice):在方法成功执行之后执行。
  • 异常后通知(After-throwing advice):在方法抛出异常后执行。
  • 环绕通知(Around advice):在方法执行之前和之后执行,提供对方法调用的全面控制。
  1. 切点(Pointcut):切点是一个表达式,切点表达式允许通过方法名称、访问修饰符等条件来匹配连接点,决定了通知应该在哪些方法执行时触发。

  2. 目标对象(Target Object):被一个或多个切面所通知的对象。也被称为被代理对象。

  3. AOP代理(AOP Proxy)AOP框架创建的对象,用于实现切面契约(由通知和切点定义)。在Spring AOP中,AOP代理可以是JDK动态代理或CGLIB代理。

  4. 引入(Introduction):引入允许向现有的类添加新的方法或属性。这是通过定义一个或多个附加接口(Introduction interfaces)实现的,AOP框架会为目标对象创建一个代理,该代理实现这些接口。

如果还是觉得抽象,我们再举一个电影制作的例子来类比

  • 🎭 切面(Aspect)
      想象一下,有人正在拍摄一部电影,而电影中的特效(比如爆炸和特殊光效)就像是应用程序中需要处理的横切关注点(比如日志记录或事务管理)。这些特效会在电影的许多不同场景中出现,而不仅仅局限于某一个特定场景。在AOP中,这些“特效”就是切面,它们可以被应用到程序的多个部分,而不需要改变实际的场景(或代码)。

  • 📍 连接点(Join Point)
      继续使用电影的比喻,每个场景中的特定时刻,比如一个爆炸发生的瞬间,可以看作是一个连接点。在编程中,这通常对应于方法的调用。

  • 📣 通知(Advice)
      通知就像是导演对特效团队的具体指令,比如“在这个场景开始之前加入一个爆炸效果”或“场景结束后显示烟雾渐散的效果”。这些指令告诉特效团队在电影的哪个具体时刻应该添加特定的效果。在AOP中,这些“指令”就是通知,指定了切面(特效)应该在连接点(特定的代码执行时刻)之前、之后或周围执行。

  • 🎯 切点(Pointcut)
      如果说通知是导演对特效团队的指令,那么切点就是指令中包含的具体条件,比如“所有夜晚的外景戏”。切点定义了哪些连接点(比如哪些具体的方法调用)应该接收通知(特效指令)。

  • 🎬 目标对象(Target Object)
      目标对象就是那些需要添加特效的场景。在我们的编程比喻中,它们是那些被切面逻辑影响的对象(比如需要日志记录的类)。

  • 🕵️‍♂️ AOP代理(AOP Proxy)
      AOP代理就像是特效团队提供的一个虚拟的、可控制特效的场景副本。这个副本在观众看来与原场景无异,但实际上它能在导演需要的时刻自动添加特效。在编程中,代理是一个被AOP框架自动创建的对象,它包装了目标对象,确保了通知(特效指令)在正确的时间被执行。

  • 🎁 引入(Introduction)
      引入就好比是在电影中加入一个全新的角色或者场景,这在原本的脚本中并不存在。在AOP中,引入允许我们向现有的类添加新的方法或属性,这就像是在不改变原始脚本的情况下扩展电影的内容。

2. 通过XML配置实现Spring AOP

  Spring提供了丰富的AOP支持,可以通过XML配置来定义切面、通知(advice)和切点(pointcuts)。这样可以在不修改源代码的情况下增加额外的行为(如日志、事务管理等)

实现步骤:

  1. 添加Spring依赖:在项目的pom.xml中添加Spring框架和AOP相关的依赖。

  2. 定义业务接口和实现类:创建业务逻辑接口及其实现,比如一个简单的服务类。

  3. 定义切面类:创建一个切面类,用于定义前置、后置、环绕等通知。

  4. 配置XML:在applicationContext.xml中配置切面和业务bean,以及AOP相关的标签。

2.1 添加Spring依赖

pom.xml文件中,添加以下依赖

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.10</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency>
</dependencies>

2.2 定义业务接口和实现类

首先,我们定义一个业务逻辑接口MyService和它的实现MyServiceImpl

MyService.java:

package com.example.demo.aop;public interface MyService {String performAction(String input) throws Exception;
}

MyServiceImpl.java:

package com.example.demo.aop;public class MyServiceImpl implements MyService {@Overridepublic String performAction(String action) throws Exception {System.out.println("Performing action in MyService: " + action);if ("throw".equals(action)) {throw new Exception("Exception from MyService");}return "Action performed: " + action;}
}

2.3 定义切面类

接下来,我们定义一个切面类MyAspect,这个类将包含一个前置通知(advice),它在MyServiceperformAction方法执行之前执行。

MyAspect.java:

package com.example.demo.aop;import org.aspectj.lang.ProceedingJoinPoint;public class MyAspect {// 前置通知public void beforeAdvice() {System.out.println("Before advice is running!");}// 后置通知public void afterAdvice() {System.out.println("After advice is running!");}// 返回后通知public void afterReturningAdvice(Object retVal) {System.out.println("After returning advice is running! Return value: " + retVal);}// 异常后通知public void afterThrowingAdvice(Throwable ex) {System.out.println("After throwing advice is running! Exception: " + ex.getMessage());}// 环绕通知public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Around advice: Before method execution");Object result = null;try {result = joinPoint.proceed();} finally {System.out.println("Around advice: After method execution");}return result;}
}

2.4 配置XML

最后,我们需要在Spring的配置文件applicationContext.xml中配置上述bean以及AOP的相关内容。

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 
上面这是XML文件的头部声明,它定义了文件的版本和编码类型,同时引入了Spring beans 和 AOP 的命名空间。
通过这些命名空间,我们可以在XML中使用<bean>和<aop:*>标签。 
--><!-- Bean definitions --><bean id="myService" class="com.example.demo.aop.MyServiceImpl"/><bean id="myAspect" class="com.example.demo.aop.MyAspect"/><!-- AOP配置 --><aop:config><!-- 定义切面及其通知 --><aop:aspect id="myAspectRef" ref="myAspect"><!-- 定义切点,指定通知应该在哪些方法执行时触发 --><aop:pointcut id="serviceOperation" expression="execution(* com.example.demo.aop.MyService.performAction(..))"/><!-- 应用前置通知,指定方法执行前的操作 --><aop:before method="beforeAdvice" pointcut-ref="serviceOperation"/><!-- 应用后置通知,指定方法执行后的操作,不论方法执行成功还是抛出异常 --><aop:after method="afterAdvice" pointcut-ref="serviceOperation"/><!-- 应用返回后通知,指定方法成功执行并返回后的操作 --><aop:after-returning method="afterReturningAdvice" pointcut-ref="serviceOperation" returning="retVal"/><!-- 应用异常后通知,指定方法抛出异常后的操作 --><aop:after-throwing method="afterThrowingAdvice" pointcut-ref="serviceOperation" throwing="ex"/><!-- 应用环绕通知,提供方法执行前后的完全控制 --><aop:around method="aroundAdvice" pointcut-ref="serviceOperation"/></aop:aspect></aop:config>
</beans>
  • myService:这是业务逻辑的bean,指向MyServiceImpl类的实例。

  • myAspect:这是切面的bean,指向MyAspect类的实例。

  • <aop:config>:这是AOP配置的根元素,所有的AOP配置,包括切面定义、切点和通知方法等,都需要在此元素内部定义。

  • 切面(Aspect):通过<aop:aspect>元素定义,它包含了一系列通知(advice)和一个或多个切点(pointcut)。这个元素将切面类(包含通知逻辑的类)与具体的操作(如何、何时对目标对象进行增强)关联起来。

  • 切点(Pointcut):通过<aop:pointcut>元素定义,切点通过表达式来指定,当需要精确控制哪些方法执行时会触发通知时,就需要定义切点。切点表达式可以非常精确地指定方法,例如通过方法名称、参数类型、注解等。expression定义了切点的表达式,指明了切点的匹配规则。这里的表达式execution(* com.example.demo.aop.MyService.performAction(..))意味着切点匹配MyService接口中performAction方法的执行,切点用于指定在哪些连接点(Join Point,例如方法调用)上应用通知。

关于解析表达式execution(* com.example.demo.aop.MyService.performAction(..))

  1. execution:是最常用的切点函数,用于匹配方法执行的连接点。

  2. *:表示方法的返回类型是任意的。

  3. com.example.demo.aop.MyService.performAction:指定了全路径的接口名和方法名。

  4. (…):表示方法参数是任意的,无论方法有多少个参数都匹配。

  • 连接点(Join Point)连接点是指在程序执行过程中的某一点,比如方法的调用。 连接点是通过切点(Pointcut)的表达式来识别和匹配的,execution(* com.example.demo.aop.MyService.performAction(..))表达式定义了一个切点,它指定了一个明确的连接点集合——即MyService接口的performAction方法的所有调用。这个例子中,MyService接口的performAction方法的调用就是潜在的连接点。每次performAction方法被调用时,就达到了一个连接点。这个连接点就是这里通知应用的时机。

  • 通知(Advice):这是AOP通过在特定时机执行的操作来增强方法的执行。method属性指明当切点匹配时应该执行的切面的方法名,pointcut-ref引用了上面定义的切点。比如这里的beforeAdvice是在目标方法performAction执行之前被调用的方法。这意味着每当MyService.performAction(..)方法被调用时,beforeAdvice方法将首先被执行。

  总结为一句话:Spring AOP通过在切面中定义规则(切点)来指定何时(连接点)以及如何(通知)增强特定方法,实现代码的模块化和关注点分离,无需修改原有业务逻辑。

  通过这种方式,Spring AOP 允许定义在特定方法执行前、执行后、环绕执行等时机插入自定义逻辑,而无需修改原有业务逻辑代码。这是实现关注点分离的一种强大机制,特别是对于跨越应用程序多个部分的横切关注点(如日志、事务管理等)。

注意,如果<aop:config>设置为

<aop:config proxy-target-class="true"><!-- 其他配置不变 -->
</aop:config>

设置proxy-target-class="true"会使Spring AOP优先使用CGLIB代理,即使目标对象实现了接口。默认情况下,不需要设置proxy-target-class属性,或者将其设置为false,则是使用JDK动态代理。

主程序:

DemoApplication.java:

package com.example.demo;import com.example.demo.aop.MyService;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class DemoApplication {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");MyService myService = (MyService) context.getBean("myService");try {System.out.println(myService.performAction("normal"));} catch (Exception e) {e.printStackTrace();}System.out.println("=======================");try {System.out.println(myService.performAction("throw"));} catch (Exception e) {System.out.println("Exception caught in main: " + e.getMessage());}context.close();}
}

运行结果:

在这里插入图片描述

  通过结合动态代理技术和这些AOP概念,Spring AOP能够以非侵入式的方式为应用程序提供横切关注点的支持,这样开发者就可以将这些关注点模块化,并保持业务逻辑组件的聚焦和简洁。

  如果对动态代理感兴趣可以再调试看看,这里是JDK动态代理是因为public class MyServiceImpl implements MyService 实现了接口,调试如下:

在这里插入图片描述

简单说一下这里能看到的关键类和接口

  • ProxyFactory: 这是Spring AOP用来创建代理对象的工厂类。它可以根据目标对象是否实现接口来决定使用JDK动态代理还是CGLIB代理。

  • AopProxy: 这个接口定义了获取代理对象的方法。它有两个主要实现:JdkDynamicAopProxy(用于JDK动态代理)和CglibAopProxy(用于CGLIB代理)。

  • JdkDynamicAopProxy: 实现了AopProxy接口,使用JDK动态代理技术创建代理。它实现了InvocationHandler接口,拦截对代理对象的所有方法调用。

  • CglibAopProxy: 同样实现了AopProxy接口,但使用CGLIB库来创建代理对象。对于没有实现接口的类,Spring会选择这种方式来创建代理。

如果大家想深入了解Spring AOP的源码,可以直接查看JdkDynamicAopProxyCglibAopProxy这两个类的实现。这里不是本篇重点,简单提一下:

比如在JdkDynamicAopProxy中看到动态代理的实现:

  1. JdkDynamicAopProxy类实现了InvocationHandler接口,这是JDK动态代理的核心。在其invoke方法中,会有逻辑判断是否需要对调用进行拦截,并在调用前后应用相应的通知。

  2. 创建代理的过程主要是在ProxyFactory通过调用createAopProxy()方法时完成的,这个方法会根据配置返回JdkDynamicAopProxyCglibAopProxy的实例。

  3. 代理的使用:客户端代码通过ProxyFactory获取代理对象,并通过这个代理对象调用目标方法。代理对象在内部使用JdkDynamicAopProxyCglibAopProxy来拦截这些调用,并根据AOP配置执行通知。通过ProxyFactory获取代理对象的过程,通常在Spring的配置和使用中是隐式完成的,特别是在使用Spring容器管理AOP时。这一过程不需要开发者直接调用ProxyFactory类。当Spring配置中定义了一个bean,并对其应用了切面,Spring容器会自动处理代理的创建和应用通知的过程。这是通过Spring的后处理器和AOP命名空间的支持实现的,开发者通常只需声明式地配置切面和通知即可。

如果想看到CGLIB代理,这里有2种方法

1种方法是去掉MyServiceImpl实现的MyService接口,然后把主程序和expression表达式对应的地方改成MyServiceImpl
2种方法就是Spring配置文件中显式设置<aop:config>标签的proxy-target-class="true"属性来实现这一点。如下:

<aop:config proxy-target-class="true"><!-- 其他配置保持不变 -->
</aop:config>

调试如下:
在这里插入图片描述


欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------

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

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

相关文章

Python从0到POC编写--基础

什么是EXP、POC、CVE&#xff1a; 在某个漏洞出现的时候&#xff0c;会经常看到 exp啊&#xff0c;poc啊什么鬼的&#xff0c; 那么这些究竟是什么东西&#xff1f;&#xff1f; 余弦大大说&#xff1a; POC 即 Proof Of Concept&#xff0c;观点验证程序。 运行这个程序就…

【Linux系统编程】第十七弹---进程理解

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、进程的基本概念 2、描述进程-PCB 2.1、什么是PCB 2.2、为什么要有PCB 3、task_ struct 3.1、启动进程 3.2、创建进程…

基于微信小程序的预约挂号系统(源码)

博主介绍&#xff1a;✌程序员徐师兄、10年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447…

Ubuntu20.04右键打不开终端

今天用virtualbox安装了ubuntu20.04 问题&#xff1a;右键打开终端&#xff0c;怎么也打开不了&#xff01; 点了也没反应&#xff0c;或者鼠标转小圈圈&#xff0c;然后也没有反应… 解决方法&#xff1a; 1、Ctrl Alt F6 先切换到终端访问界面 mac电脑 Ctrl Alt F6 …

vuerouter声明式导航

声明式导航-跳转传参数 1.查询参数传参 语法&#xff1a;to /path?参数名值 2.对应页面组件接受传来的值 $router.query.参数名 2.动态路由传参 1.配置动态路由 2.配置导航连接 to/path/参数值 3.对应页面组件接收传递过来的值 #route.params.参数名 多个参数传递&…

情感感知OCR:整合深度学习技术提升文字识别系统的情感理解能力

摘要&#xff1a;随着深度学习技术的发展&#xff0c;文字识别&#xff08;OCR&#xff09;系统在识别准确率和速度上取得了长足的进步。然而&#xff0c;在处理文本时&#xff0c;仅仅依靠字符和词语的识别并不足以满足用户对信息的全面理解需求。本文提出了一种新颖的方法&am…

Redis五大基本数据类型介绍及其使用场景

文章目录 1 String&#xff08;字符串&#xff09;应用场景 2 List&#xff08;列表&#xff09;应用场景 3 Set&#xff08;集合&#xff09;4 sorted set&#xff08;有序集合&#xff09;应用场景 5 hash&#xff08;哈希&#xff09;应用场景 Redis 是一个开源&#xff0c;…

彩信群发推广:四大革新优势,引领营销新时代!

在数字化营销日益盛行的今天&#xff0c;短信群发已成为我们生活中不可或缺的一部分。然而&#xff0c;您是否想过&#xff0c;除了传统的文本短信&#xff0c;还有一种更为丰富、更具吸引力的推广方式——彩信群发推广&#xff1f;彩信不仅融合了图片、文字、音频、动画和视频…

【漏洞复现】泛微OA E-Cology ln.FileDownload文件读取漏洞

漏洞描述&#xff1a; 泛微OA E-Cology是一款面向中大型组织的数字化办公产品&#xff0c;它基于全新的设计理念和管理思想&#xff0c;旨在为中大型组织创建一个全新的高效协同办公环境。泛微OA E-Cology ln.FileDownload存在任意文件读取漏洞&#xff0c;允许未经授权的用户…

轨迹规划 | 图解纯追踪算法Pure Pursuit(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 纯追踪算法原理推导2 自适应纯追踪算法(APP)3 规范化纯追踪算法(RPP)4 仿真实现4.1 ROS C仿真4.2 Python仿真4.3 Matlab仿真 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细介绍全局规划…

快速配置 Nginx 来实现 GPT 流式传输

目录 1. Nginx 参考配置2. Nginx 核心参数3. 其他参数 场景&#xff1a;代理 ChatGPT、代理各种 GPT 工具套壳等。 1. Nginx 参考配置 支持 GPT 流式访问的配置如下&#xff0c;请根据实际需求适当取舍即可&#xff1a; server {listen 80;server_name chat.test.com; # 绑…

如何推动物联网的未来?——青创智通

工业物联网解决方案-工业IOT-青创智通 物联网作为连接物理世界和数字世界的桥梁&#xff0c;正逐渐改变着我们的生活和工作方式。在工业领域&#xff0c;物联网技术的应用不仅提高了生产效率&#xff0c;还实现了对设备的智能化管理和维护。而工业网关作为物联网的重要组成部分…

java数据保留几位小数的问题

String.format()&#xff1a; 这个方法在格式化输出时非常常用&#xff0c;可以方便地控制小数位数&#xff0c;并且语法简洁易懂。它不仅可以用于格式化浮点数和双精度数&#xff0c;还可以用于格式化其他数据类型&#xff0c;如整数、字符串等。 示例代码&#xff1a; BigD…

仪器校准中,CNAS对报告的认可评审要求有哪些?

CNAS扩项时&#xff0c;常常会有关于对报告认可的相关要求&#xff0c;而这些要求往往有明确规范&#xff0c;那么在仪器校准中&#xff0c;CNAS对报告的认可评审要求有哪些&#xff1f; 现场评审时&#xff0c;评审组应关注抽查报告&#xff0c;评审组将现场随机抽取报告&…

酷开科技让你能够放心地把遥控器交给孩子

我国电视从诞生至今已有65个年头&#xff0c;从黑白到彩色&#xff0c;从背投到液晶&#xff0c;电视的外观随着时代技术的发展而不断变化&#xff0c;直到现在随着技术的不断迭代&#xff0c;电视的功能越来越丰富&#xff0c;电视在客厅中的地位也越来越凸显。作为家庭娱乐的…

【Linux基础】Vim保姆级一键配置教程(手把手教你把Vim打造成高效率C++开发环境)

目录 一、前言 二、安装Vim 三、原始Vim编译器的缺陷分析 四、Vim配置 &#x1f95d;预备知识----.vimrc 隐藏文件 &#x1f34b;手动配置 Vim --- &#xff08;不推荐&#xff09; &#x1f347;自动化一键配置 Vim --- (强烈推荐) ✨功能演示 五、共勉 一、前言 Vim作为…

实现字符串比较函数(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i, result;char s1[100], s2[100];//填充数组&#xff1b;printf("请输入数组s1的…

2.分布式-算法

目录 一、限流算法有哪些&#xff1f; 1.计数器算法&#xff08;Counter-Based Algorithm&#xff09; 2.固定窗口算法&#xff08;Fixed Window&#xff09; 3.滑动窗口算法&#xff08;Sliding Window&#xff09; 4.令牌桶算法&#xff08;Token Bucket&#xff09; 5.…

生产设备数据管控要怎么做 可以实现精益生产和智能制造?

生产设备在制造过程中会产生多种类型的数据&#xff0c;这些数据对于优化生产流程、提高效率、降低成本和预防性维护等方面至关重要。需要对这些数据进行有效的采集和管理&#xff0c;以实现对生产设备数据管控。 一、生产设备数据类型包括&#xff1a; 设备运行状态数据&…

C++八股(面试题、手撕题)自用版

目录 面试题&#xff1a; 1. define inline 在编译的哪个阶段 2. const static 3. 子函数返回结构体有什么问题&#xff0c;返回对象调用了哪些函数 4. volatile关键字 5. 编译器基本原理 6. 预处理、编译、汇编、链接以及他们在操作系统上如何运作的 7. 数组和指针&a…