当前位置: 首页 > news >正文

Spring AOP 的概念及其作用

一、什么是 Spring AOP

在介绍 Spring AOP 之前,首先要了解一下什么是 AOP
AOP Aspect Oriented Programming ):面向切面编程,它是一种思想, 它是对某一类事情的集中处 。比如用户登录权限的效验,没学 AOP 之前,我们所有需要判断用户登录的页面(中的方法),都要各自实现或调用用户验证的方法,然而有了 AOP 之后,我们只需要在某一处配置一下,所有需要判断用户登录页面(中的方法)就全部可以实现用户登录验证了,不再需要每个方法中都写相同的用户登录验证了。
AOP 是一种思想,而 Spring AOP 是一个框架,提供了一种对 AOP 思想的实现,它们的关系和 IoC与 DI 类似。

二、为什要用 AOP

想象一个场景,我们在做后台系统时,除了登录和注册等几个功能不需要做用户登录验证之外,其他几乎所有页面调用的前端控制器( Controller )都需要先验证用户登录的状态,那这个时候我们要怎么处 理呢?
我们之前的处理方式是每个 Controller 都要写一遍用户登录验证,然而当你的功能越来越多,那么你要写的登录验证也越来越多,而这些方法又是相同的,这么多的方法就会代码修改和维护的成本。那有没有简单的处理方案呢?答案是有的,对于这种功能统一,且使用的地方较多的功能,就可以考虑 AOP 来统一处理了
除了统一的用户登录判断之外, AOP 还可以实现:
  • 统一日志记录
  • 统一方法执行时间统计
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交等
也就是说 使用 AOP 可以扩充多个对象的某个能力 ,所以 AOP 可以说是 OOP Object Oriented
Programming ,面向对象编程)的补充和完善。

三、Spring AOP 应该怎么学习呢?

Spring AOP 学习主要分为以下 3 个部分:
1. 学习 AOP 是如何组成的?也就是学习 AOP 组成的相关概念。
2. 学习 Spring AOP 使用。
3. 学习 Spring AOP 实现原理。
下面我们分别来看。

3.1 AOP 组成

3.1.1 切面(Aspect

切面( Aspect )由切点( Pointcut )和通知( Advice )组成,它既包含了横切逻辑的定义,也包括了连接点的定义。
切面是包含了:通知、切点和切面的类,相当于 AOP 实现的某个功能的集合。

3.1.2 连接点(Join Point

应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
连接点相当于需要被增强的某个 AOP 功能的所有方法。

3.1.3 切点(Pointcut

Pointcut 是匹配 Join Point 的谓词。
Pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述)来匹配 Join Point,给满足规则的 Join Point 添加 Advice
切点相当于保存了众多连接点的一个集合(如果把切点看成一个表,而连接点就是表中一条一条的
数据)。

3.1.4 通知(Advice

切面也是有目标的 —— 它必须完成的工作。在 AOP 术语中, 切面的工作被称之为通知
通知:定义了切面是什么,何时使用,其描述了切面要完成的工作,还解决何时执行这个工作的问题。
Spring 切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用:
  • 前置通知使用 @Before:通知方法会在目标方法调用之前执行。
  • 后置通知使用 @After:通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知使用 @AfterReturning:通知方法会在目标方法返回后调用。
  • 抛异常后通知使用 @AfterThrowing:通知方法会在目标方法抛出异常后调用。
  • 环绕通知使用 @Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。
切点相当于要增强的方法。
AOP 整个组成部分的概念如下图所示,以多个页面都要访问用户登录权限为例:

3.2 Spring AOP 实现

接下来我们使用 Spring AOP 来实现一下 AOP 的功能,完成的目标是拦截所有 UserController 里面的方法,每次调用 UserController 中任意一个方法时,都执行相应的通知事件。
Spring AOP 的实现步骤如下:
1. 添加 Spring AOP 框架支持。
2. 定义切面和切点。
3. 定义通知。

3.2.1 添加 AOP 框架支持

pom.xml 中添加如下配置:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-bootstarter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

3.2.2 定义切面和切点

切点指的是具体要处理的某一类问题,比如用户登录权限验证就是一个具体的问题,记录所有方法的执行日志就是一个具体的问题,切点定义的是某一类问题。
Spring AOP 切点的定义如下,在切点中我们要定义拦截的规则,具体实现如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect // 表明此类为一个切面
@Component
public class UserAspect {
// 定义切点,这里使用 AspectJ 表达式语法
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut(){ }
}
其中 pointcut 方法为空方法,它不需要有方法体,此方法名就是起到一个 标识 的作用,标识下面的通知方法具体指的是哪个切点(因为切点可能有很多个)。
切点表达式说明
AspectJ 支持三种通配符:
  • * :匹配任意字符,只匹配一个元素(包,类,或方法,方法参数)。
  • * .. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使用。
  • + :表示按照类型匹配指定类的所有类,必须跟在类名后面,如 com.cad.Car+ ,表示继承该类的所有子类包括本身。
切点表达式由切点函数组成,其中 execution() 是最常用的切点函数,用来匹配方法,语法为:
execution(< 修饰符 >< 返回类型 >< . . 方法 ( 参数 )>< 异常 >)
修饰符 异常 可以省略。
表达式示例

 

3.2.3 定义相关通知

通知定义的是被拦截的方法具体要执行的业务,比如用户登录权限验证方法就是具体要执行的业务。
Spring AOP 中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用:
  • 前置通知使用@Before:通知方法会在目标方法调用之前执行。
  • 后置通知使用@After:通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知使用@AfterReturning:通知方法会在目标方法返回后调用。
  • 抛异常后通知使用@AfterThrowing:通知方法会在目标方法抛出异常后调用。
  • 环绕通知使用@Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自
  • 定义的行为。
具体实现如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UserAspect {
// 定义切点方法
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut(){ }
// 前置通知
@Before("pointcut()")
public void doBefore(){
System.out.println("执行 Before 方法");
}
// 后置通知
@After("pointcut()")
public void doAfter(){
System.out.println("执行 After 方法");
}
// return 之前通知
@AfterReturning("pointcut()")
public void doAfterReturning(){
System.out.println("执行 AfterReturning 方法");
}
// 抛出异常之前通知
@AfterThrowing("pointcut()")
public void doAfterThrowing(){
System.out.println("执行 doAfterThrowing 方法");
}
// 添加环绕通知
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint){
Object obj = null;
System.out.println("Around 方法开始执行");
try {
// 执行拦截方法
obj = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("Around 方法结束执行");
return obj;
}
}
经过以上的代码我们就能实现 Spring AOP 了。

3.3 Spring AOP 实现原理

Spring AOP 是构建在 动态代理 基础上,因此 Spring AOP 的支持局限于方法级别的拦截
Spring AOP 支持 JDK Proxy CGLIB 方式实现动态代理。默认情况下,实现了接口的类,使用 AOP 会基于 JDK 生成代理类,没有实现接口的类,会基于 CGLIB 生成代理类。

织入(Weaving):代理的生成时机

织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:
  • 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
  • 类加载器:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader,可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving. LTW)就支持以这种方式织入切面。
  • 运行期:切面在应用运行的某一时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象。SpringAOP就是以这种方式织入切面的。

动态代理

此种实现在设计模式上称为动态代理模式,在实现的技术手段上,都是在 class 代码运行期,动态的织 入字节码。

我们学习 Spring 框架中的AOP,主要基于两种方式:JDK CGLIB 的方式。这两种方式的代理目标都是被代理类中的方法,在运行期,动态的织入字节码生成代理类。

  • CGLIBJava中的动态代理框架,主要作用就是根据目标类和方法,动态生成代理类。
  • Java中的动态代理框架,几乎都是依赖字节码框架(如 ASMJavassist 等)实现的。
  • 字节码框架是直接操作 class 字节码的框架。可以加载已有的class字节码文件信息,修改部分信息,或动态生成一个 class

JDK 动态代理实现

JDK 实现时,先通过实现 InvocationHandler 接口创建方法调用处理器,再通过 Proxy 来创建代理类。
以下为代码实现:
import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理:使用JDK提供的api(InvocationHandler、Proxy实现),此种方式实现,要求被代理类必
须实现接口
public class PayServiceJDKInvocationHandler implements InvocationHandler {
//目标对象即就是被代理对象
private Object target;
public PayServiceJDKInvocationHandler( Object target) {
this.target = target;
}
//proxy代理对象
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
//1.安全检查
System.out.println("安全检查");
//2.记录日志
System.out.println("记录日志");
//3.时间统计开始
System.out.println("记录开始时间");
//通过反射调用被代理类的方法
Object retVal = method.invoke(target, args);
//4.时间统计结束
System.out.println("记录结束时间");
return retVal;
}
public static void main(String[] args) {
PayService target= new AliPayService();
//方法调用处理器
InvocationHandler handler =
new PayServiceJDKInvocationHandler(target);
//创建一个代理类:通过被代理类、被代理实现的接口、方法调用处理器来创建
PayService proxy = (PayService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class[]{PayService.class},
handler
);
proxy.pay();
}
}

CGLIB 动态代理实现

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;
import java.lang.reflect.Method;
public class PayServiceCGLIBInterceptor implements MethodInterceptor {
//被代理对象
private Object target;
public PayServiceCGLIBInterceptor(Object target){
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy
methodProxy) throws Throwable {
//1.安全检查
System.out.println("安全检查");
//2.记录日志
System.out.println("记录日志");
//3.时间统计开始
System.out.println("记录开始时间");
//通过cglib的代理方法调用
Object retVal = methodProxy.invoke(target, args);
//4.时间统计结束
System.out.println("记录结束时间");
return retVal;
}
public static void main(String[] args) {
PayService target= new AliPayService();
PayService proxy= (PayService) Enhancer.create(target.getClass(),new
PayServiceCGLIBInterceptor(target));
proxy.pay();
}
}

JDK CGLIB 的区别

1. JDK 实现,要求被代理类必须实现接口,之后是通过 InvocationHandler Proxy ,在运行时动态的在内存中生成了代理类对象,该代理对象是通过实现同样的接口实现(类似静态代理接口实现的方式),只是该代理类是在运行期时,动态的织入统一的业务逻辑字节码来完成。
2. CGLIB 实现,被代理类可以不实现接口,是通过继承被代理类,在运行时动态的生成代理类对象。

总结

AOP 是对某方面能力的统一实现,它是一种实现思想, Spring AOP 是对 AOP 的具体实现, Spring AOP 可通过 AspectJ (注解)的方式来实现 AOP 的功能, Spring AOP 的实现步骤是:
1. 添加 AOP 框架支持。
2. 定义切面和切点。
3. 定义通知。
Spring AOP 是通过动态代理的方式,在运行期将 AOP 代码织入到程序中的,它的实现方式有两种: JDK Proxy 和 CGLIB

 

相关文章:

Spring AOP 的概念及其作用

一、什么是 Spring AOP&#xff1f; 在介绍 Spring AOP 之前&#xff0c;首先要了解一下什么是 AOP &#xff1f; AOP &#xff08; Aspect Oriented Programming &#xff09;&#xff1a;面向切面编程&#xff0c;它是一种思想&#xff0c; 它是对某一类事情的集中处 理 。…...

python基础1——环境安装

文章目录 一、Windows安装二、Linux安装三、pycharm安装3.1 软件安装3.2 个性化设置3.3 基本使用3.3.1 定义变量3.3.2 查看数据类型3.3.3 运算符3.3.4 操作符3.3.5 转义符 一、Windows安装 1、下载软件安装包&#xff0c;官网 2、开始安装。 2.查看是否安装成功。 3.安装…...

uniapp 中 的progress加载进度条 的使用,在 页面显示数据加载的进度条,使用户的使用体验效果更好

学习目标&#xff1a; 学习目标如下&#xff1a; 例如&#xff1a; uniapp 中 的progress加载进度条 的使用&#xff0c;在 页面显示数据加载的进度条&#xff0c;使用户的使用体验效果更好 学习内容&#xff1a; 学习内容如下所示&#xff1a; 相关属性的说明 进度条的显…...

【尚硅谷】第01章:随堂复习与企业真题(Java语言概述)

来源&#xff1a;尚硅谷Java零基础全套视频教程(宋红康2023版&#xff0c;java入门自学必备) 基本都是宋老师发的资料里面的内容&#xff0c;只不过补充几个资料里没直接给出答案的问题的答案。 不想安装markdown笔记的app所以干脆在这里发一遍。 第01章&#xff1a;随堂复习…...

MyBatis的SqlSession理解

SqlSession是Mybatis最重要的构建之一&#xff0c;可以认为Mybatis一系列的配置目的是生成类似JDBC生成的Connection对象的statement对象&#xff0c;这样才能与数据库开启“沟通”&#xff0c;通过SqlSession可以实现增删改查&#xff08;当然现在更加推荐是使用Mapper接口形式…...

axios 某个接口使用自己独有的完整地址

可以在axios请求中使用完整的URL&#xff0c;而不使用baseURL&#xff0c; 只需将url字段设置为完整的URL即可 import axios from axios;export function getInfo() {return axios({url: http://192.168.3.15:8086/test/messages,method: post}); }直接在url字段中提供了完整的…...

WEB:Web_python_template_injection

背景知识 python模板注入 ssit 题目 打开题目&#xff0c;发现页面提示&#xff0c;翻译为python模板注入 先测试是否存在注入 可以发现被执行了 先查看所有的子类 payload {{[].__class__.__base__.__subclasses__()}} 利用site.Printer的os模块执行命令 payload {{.__…...

【Android安全】Embedded Trace Microcell模块

ETM: Embedded Trace Macrocell, hardware unit responsible to generate hardware instruction trace. ETM模块用于在硬件层面实现instruction trace&#xff0c;可用于辅助逆向分析。 使用教程&#xff1a; https://mcuoneclipse.com/2016/11/05/tutorial-getting-etm-inst…...

修改内核驱动之后-如何给内核打补丁

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言思路步骤1.进入下面路径2.修改文件calibrate.c3.使用git工具生产补丁文件4.移动补丁文件到自己的Linux的recipem目录下总结前言 本文来学习如何使用YOCTO修改Linux内核驱动之后,如何通过打补…...

【javaSE】 类和对象详解

目录 面向对象的初步认知 什么是面向对象 面向对象与面向过程 类定义和使用 简单认识类 类的定义格式 注意事项 练习定义类 定义一个狗类 定义一个学生类 注意事项 类的实例化 什么是实例化 注意事项 类和对象的说明 this引用 为什么要有this引用 什么是this引…...

大数据课程D5——hadoop的Sink

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 掌握Sink的HDFS Sink&#xff1b; ⚪ 掌握Sink的Logger Sink&#xff1b; ⚪ 掌握Sink的File Roll Sink&#xff1b; ⚪ 掌握Sink的Null Sink&#xff1b; ⚪ 掌握Si…...

【数据结构】27.移除元素

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

机器学习分布式框架ray运行xgboost实例

Ray是一个开源的分布式计算框架&#xff0c;专门用于构建高性能的机器学习和深度学习应用程序。它的目标是简化分布式计算的复杂性&#xff0c;使得用户能够轻松地将任务并行化并在多台机器上运行&#xff0c;以加速训练和推理的速度。Ray的主要特点包括支持分布式任务执行、Ac…...

C++设计模式笔记

设计模式 如何解决复杂性&#xff1f; 分解 核心思想&#xff1a;分而治之&#xff0c;将大问题分解为多个小问题&#xff0c;将复杂问题分解为多个简单的问题。 抽象 核心思想&#xff1a;从高层次角度讲&#xff0c;人们处理复杂性有一个通用的技术&#xff0c;及抽象。…...

简单聊聊创新与创造力

文章目录 前言一、大脑运行的两种方式1、聚焦模式2、发散模式3、影响想法的因素a、背景知识b、兴趣c、天赋 4、思维固化 二、想法的不可靠1、对想法进行验证2、颠覆性创新&#xff0c;挤牙膏式创新3、为什么模仿这么多 三、更多更多的idea1、个人的方面a、积累不同的背景知识b、…...

使用TensorFlow训练深度学习模型实战(上)

大家好&#xff0c;尽管大多数关于神经网络的文章都强调数学&#xff0c;而TensorFlow文档则强调使用现成数据集进行快速实现&#xff0c;但将这些资源应用于真实世界数据集是很有挑战性的&#xff0c;很难将数学概念和现成数据集与我的具体用例联系起来。本文旨在提供一个实用…...

【Spring】什么是Bean的生命周期及作用域,什么是Spring的执行流程?

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE进阶 在前面的播客中讲解了如何从Spring中存取Bean对象&#xff0c;那么本篇我们来讲解Bean对象的生命周期是什么&#xff0c;Bean对象的6种作用域分别是什么&#xff0c;都有哪些区别&#xff…...

立创EDA学习

学习树莓派3B的板子发现有个扩展板比较好&#xff0c;自己最好画一个&#xff0c;反正免费。 学习视频&#xff1a;立创EDA&#xff08;专业版&#xff09;电路设计与制作快速入门。 下载专业版&#xff0c;并激活。【分专业版和标准版&#xff0c;专业版也是免费的】 手机…...

清风学习笔记—层次分析法—matlab对判断矩阵的一致性检验

在判断矩阵是否为正互反矩阵这块&#xff0c;我写了两种代码&#xff0c;改进前很麻烦且有错误&#xff0c;改进后简洁多了&#xff0c;改进前的代码还有错误&#xff0c;忽略了对角线的值必须都是1&#xff0c;只考虑了除开对角线的元素相乘为1。 %% 改进前代码 A[3 2 4;1/2 …...

大众安徽内推

大众汽车&#xff08;安徽&#xff09;有限公司是大众汽车集团在中国第一家专注于新能源汽车的合资企业&#xff0c;是集团在中国首家拥有全面运营管理权的合资企业&#xff0c;担负着产品研发及数字化研发的重任&#xff0c;将成为集团全球电动出行中心之一。 VW Anhui Offic…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...