【Spring】深入学习AOP编程思想的实现原理和优势

【切面编程】深入学习AOP编程思想的实现原理和优势

  • 前言
  • AOP的由来及AOP与代理的关系
  • AOP的实现方式详解
    • 静态代理
    • 动态代理
  • AOP的应用场景
    • 记录日志
    • 权限控制
    • 数据库事务控制
    • 缓存处理
    • 异常处理
    • 监控管理
  • AOP的底层实现全流程解析
    • Spring AOP的简介
    • 动态代理的实现原理
    • Spring AOP的实现原理
    • Spring AOP的切面
    • Spring AOP的执行流程
  • 总结

前言

在后端开发多年,深知Spring 中 AOP(Aspect Oriented Programming)是一种很重要的编程思想。它可以将程序中通用的功能抽象出来,通过切面和切点的方式实现对具体方法的增强。结合自己多年的开发经验,利用业余时间,做一个有关AOP的知识原理分析。本文将详细介绍AOP的由来和与代理模式的关系,以及AOP的实现方式、应用场景和底层实现全流程解析。

首先,我们将讨论AOP的由来和与代理模式的关系,以及AOP的概念和目标。接着,我们将介绍AOP的两种实现方式:静态代理和动态代理。然后,我们将探讨AOP的应用场景,包括记录日志、权限控制、数据库事务控制和缓存处理等。最后,我们将详细介绍Spring AOP的底层实现流程,包括定义切点和切面、生成代理对象、执行增强逻辑和执行目标方法等步骤。本文旨在帮助读者深入理解AOP的原理和应用,从而提高软件开发效率和质量。

AOP的由来及AOP与代理的关系

AOP(Aspect Oriented Programming)是面向切面编程,它弥补了 OOP(Object Oriented Programming)编程中“垂直继承”的不足,可以在程序运行时动态地向类中添加新的方法或者修改已有的方法,是一种能够将程序中通用部分抽象出来的编程思想。AOP最初由Gregor Kiczales等人提出并发表于1997年的一篇论文《Aspect-oriented programming》。

AOP(Aspect Oriented Programming)的概念最早由Gregor Kiczales等人在1997年提出。他们注意到,软件开发中的很多问题都是由于跨越了程序各个部分的横切关注点而引起的,例如日志记录、性能统计、事务管理等。而这些横切关注点往往散布在不同的方法和类中,导致代码的复杂性和维护成本的提高。为了解决这些问题,他们提出了AOP编程思想。

AOP与代理的关系密不可分。在OOP编程中,代理模式可以使对象在不修改原始代码的情况下增加功能,将一些横切关注点从业务逻辑中分离出去,但是代理模式的使用需要手动实现,AOP则可以自动实现代理。
AOP和代理模式都属于面向对象编程中的一种重要编程思想。代理模式是目标对象的包装器,以实现对目标对象的访问控制、增强功能或者隐藏底层实现等目的;AOP则是在不修改源代码的情况下,通过切面和切点的方式实现对目标对象的增强。AOP可以使用代理模式来实现增强的过程,也可以使用其他技术(如字节码操作)来实现。因此,可以说代理模式是AOP的一种实现方式,而AOP更多的是一种编程思想和技术范畴。

AOP的实现方式详解

在这里插入图片描述

静态代理

静态代理是指在编译期确定被代理对象和代理对象,利用继承或者实现相同接口的方式实现代码增强。

例如,在Spring框架中就使用了静态代理的方式实现了JDBC模板的增强,下面是一个简单的示例:

public interface UserDao {
    public void addUser();
    public void deleteUser();
}
public class UserDaoImpl implements UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }
    public void deleteUser() {
        System.out.println("删除用户");
    }
}
public class UserDaoProxy implements UserDao {
    private UserDao userDao;
    public UserDaoProxy(UserDao userDao) {
        this.userDao = userDao;
    }
    public void addUser() {
        System.out.println("记录日志 - 添加用户");
        userDao.addUser();
    }
    public void deleteUser() {
        System.out.println("记录日志 - 删除用户");
        userDao.deleteUser();
    }
}

public class Test {
    public static void main(String[] args) {
        UserDao userDao = new UserDaoImpl();
        UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
        userDaoProxy.addUser();
        userDaoProxy.deleteUser();
    }
}

动态代理

动态代理是指在运行期根据被代理对象生成相应的代理对象,动态代理可以通过反射机制来实现,Java中的Proxy类和InvocationHandler接口可以用来实现动态代理。

例如,在Spring框架中就使用了动态代理的方式实现AOP,下面是一个简单的示例:

public interface UserDao {
    public void addUser();
    public void deleteUser();
}
public class UserDaoImpl implements UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }
    public void deleteUser() {
        System.out.println("删除用户");
    }
}
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志 - " + method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
}
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志 - " + method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
}

AOP的应用场景

记录日志

在程序运行中记录方法调用次数和执行时间等信息,方便管理员对系统进行监控和优化。

权限控制

通过AOP可以实现对用户权限的控制,例如在访问某个功能时需要进行身份验证或者权限验证。

数据库事务控制

在进行数据库操作时,如果出现异常需要回滚事务,可以通过AOP来实现事务的管理和控制。

缓存处理

在查询数据时,如果经常查询到相同的数据,可以将数据缓存在内存中以提高程序执行效率,通过AOP可以实现缓存的管理和控制。

异常处理

在程序中添加异常处理横切关注点,通过AOP技术,可以实现对业务逻辑中抛出的异常进行捕获和统一处理。

监控管理

在程序中添加监控管理横切关注点,通过AOP技术,可以实现对程序运行状态和调用情况的监控和管理。

目前常用的AOP框架包括:

  • Spring AOP:Spring框架的核心模块之一,提供基于代理的AOP实现方式。
  • AspectJ:一个独立的AOP框架,提供比Spring AOP更为强大的AOP功能,支持多种AOP实现方式。
  • JBoss AOP:一个专门为J2EE应用开发的AOP框架,提供对EJB组件进行AOP增强的功能。
  • Guice AOP:Google开发的AOP框架,与Google Guice依赖注入框架配合使用,使得AOP和IoC容器能够无缝衔接。
  • Castle Windsor:.NET平台下的AOP框架,提供基于代理和字节码注入两种AOP实现方式。

AOP的底层实现全流程解析

Spring AOP的简介

Spring AOP是Spring框架中的一个重要组件,它能够在不修改原始代码的情况下增加新的功能,如记录日志、性能监控和事务管理等。Spring AOP是基于动态代理实现的,要想理解Spring AOP的底层实现原理,需要对Java中的动态代理有所了解。

动态代理的实现原理

Java中的动态代理是基于Java反射机制实现的,通过Proxy类和InvocationHandler接口来生成代理对象和拦截方法调用。在动态代理中,将要被代理的对象委托给InvocationHandler接口的实现类来处理,实现类中的invoke()方法负责拦截被代理对象的方法调用,并在调用前后进行逻辑处理。

动态代理是一种常用的代理模式,它可以在程序运行时动态生成代理类实例。在Java中,动态代理通常有两种实现方式:基于接口的动态代理和基于类的动态代理。下面分别介绍这两种实现方式的原理和代码示例。

(1) 基于接口的动态代理
在基于接口的动态代理中,代理类实现了目标接口,并重写了其中的方法。然后,在程序运行时,使用Java反射机制动态生成代理类实例,并将目标对象实例和代理对象实例传递给调用方。

public interface UserService {
    void addUser(User user);
}
public class UserServiceImpl implements UserService {
    public void addUser(User user) {
        System.out.println("新增用户:" + user.getName());
    }
}
public class LogHandler implements InvocationHandler {
    private Object target;
 
    public LogHandler(Object target) {
        this.target = target;
    }
 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志-前置通知");
        Object result = method.invoke(target, args);
        System.out.println("记录日志-后置通知");
        return result;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        LogHandler logHandler = new LogHandler(userService);
        UserService proxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[] { UserService.class },
            logHandler);
        proxy.addUser(new User("Tom"));
    }
}

在上述代码中,LogHandler实现了InvocationHandler接口,并重写了其中的invoke方法。在invoke方法中,先执行与目标方法相关联的前置通知逻辑;然后,使用Java反射机制调用目标对象实例的方法;最后,在方法执行后执行与目标方法相关联的后置通知逻辑。Proxy.newProxyInstance方法用于创建代理对象实例,并将目标对象实例和代理对象实例关联起来。

(2) 基于类的动态代理

在基于类的动态代理中,代理类继承了目标类,并重写了其中的方法。然后,在程序运行时,动态生成代理类实例,并将目标对象实例传递给代理对象实例。

public class UserService {
    public void addUser(User user) {
        System.out.println("新增用户:" + user.getName());
    }
}
public class UserServiceProxy extends UserService {
    private UserService target;
 
    public UserServiceProxy(UserService target) {
        this.target = target;
    }
 
    public void addUser(User user) {
        System.out.println("记录日志-前置通知");
        target.addUser(user);
        System.out.println("记录日志-后置通知");
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        UserService userService = new UserService();
        UserService proxy = new UserServiceProxy(userService);
        proxy.addUser(new User("Tom"));
    }
}

在上述代码中,UserServiceProxy继承了UserService类,并重写了其中的addUser方法。在重写的addUser方法中,先执行与目标方法相关联的前置通知逻辑;然后,调用目标对象实例的方法;最后,在方法执行后执行与目标方法相关联的后置通知逻辑。在程序运行时,使用代理对象实例来调用方法,就可以完成动态代理的过程。

以上就是基于接口和基于类的动态代理的实现原理和代码示例。需要注意的是,在使用动态代理时,需要按照目标对象实现的接口或继承的父类定义代理类,这样才能保证代理类的方法参数和返回值类型与目标对象一致。

Spring AOP的实现原理

Spring AOP是基于动态代理实现的,Spring框架中提供了两种动态代理:JDK动态代理和CGLIB动态代理。

JDK动态代理是基于Java反射机制实现的,要求被代理的对象必须实现一个接口,代理对象和目标对象实现相同的接口,并且由InvocationHandler实现类来处理代理对象的方法调用。

CGLIB动态代理是基于ASM字节码生成库实现的,可以对任意一个类或者接口产生代理对象。CGLIB动态代理直接对类进行操作,比JDK动态代理效率更高,但是生成代理对象的速度比较慢。

在这里插入图片描述

Spring AOP的切面

在Spring AOP中,通常将要被增强的方法称为切点(Pointcut),将要增加的功能称为切面(Aspect)。切面是由切点和增强逻辑组成的,它用于描述目标类中哪些方法会被代理,并且在方法执行前、执行后或抛出异常时执行增强逻辑。

在这里插入图片描述

Aspect 切面是 Java 领域中的一个重要概念,它是面向切面编程(AOP)的核心。AOP 是一种编程思想,可以在程序运行时动态地将代码注入到目标方法中。Aspect 切面就是这些注入的代码,用于实现横切关注点的功能。
Aspect 切面可以通过以下三个元素来定义:

  • Pointcut(切入点):表示需要被织入增强逻辑的方法或者类。AOP 框架通过 Pointcut 来确定增强哪些方法。
  • Advice(增强逻辑):表示需要织入到目标方法执行前、后、异常抛出或者返回结果时的逻辑。Advice 分为以下几种类型:前置通知(Before)、后置通知(After)、异常通知(AfterThrowing)、返回通知(AfterReturning)和环绕通知(Around)。
  • Weaving(织入逻辑):表示将 Aspect 切面中的增强逻辑织入到目标方法中的过程。AOP 框架通过 Weaving 来完成切面的织入。

下面以 Spring AOP 为例进一步解析 Aspect 切面的实现原理。

(1)定义切面

@Aspect
@Component
public class LogAspect {
 
    @Pointcut("execution(public * com.example.service.*.*(..))")
    public void servicePointcut() {}
 
    @Before("servicePointcut()")
    public void before(JoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[" + className + "." + methodName + "] 方法开始执行");
    }
 
    @AfterReturning(value = "servicePointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[" + className + "." + methodName + "] 方法执行完毕,返回值:" + result);
    }
 
    @AfterThrowing(value = "servicePointcut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[" + className + "." + methodName + "] 方法抛出异常:" + e.getMessage());
    }
}

上述代码中定义了一个名为 LogAspect 的切面类,用于在 com.example.service 包下的所有方法中记录方法的执行状态。

(2)定义目标类

@Service
public class UserServiceImpl implements UserService {
    public void addUser(User user) {
        System.out.println("新增用户:" + user.getName());
    }
}

上述代码中定义了一个名为 UserServiceImpl 的目标类,用于执行业务逻辑。

(3)使用 AOP 织入

在 Spring AOP 中,有两种方式将切面织入到目标方法中:基于代理的 AOP 和基于字节码生成技术的 AOP。这里以基于代理的 AOP 为例进行说明。

public class ProxyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = context.getBean(UserService.class);
        userService.addUser(new User("Tom"));
    }
}

上述代码中定义了一个名为 ProxyTest 的主类,用于初始化 ApplicationContext 并获取 UserService 实例。在上述代码执行时,Spring AOP 会根据 LogAspect 中定义的 Pointcut 和 Advice,将增强逻辑织入到 UserServiceImpl 的 addUser 方法中。

Spring AOP的执行流程

Spring AOP的执行流程包括以下几个步骤:

  1. 定义切点:在XML配置文件中定义切点,用于描述目标类中哪些方法会被代理。
  2. 定义切面:在XML配置文件中定义切面,用于描述增强逻辑。
  3. 生成代理对象:通过动态代理生成代理对象,可以使用JDK动态代理或者CGLIB动态代理。
  4. 执行增强逻辑:在代理对象上调用方法时,会首先进入到切面中,切面会根据切点匹配目标方法并执行相应的增强逻辑。
  5. 执行目标方法:增强逻辑执行完成后,再执行目标方法的逻辑。

Spring AOP的执行流程和普通Java程序的执行流程类似,只不过在方法执行前后增加了Aspect切面的逻辑。

下面是Spring AOP的执行流程示例:

(1) 创建Spring容器,并加载Bean配置文件。

ApplicationContext context = 
    new ClassPathXmlApplicationContext("applicationContext.xml");

(2) 从Spring容器中获取目标对象实例,并调用目标方法。

UserService userService = (UserService) context.getBean("userService");
userService.addUser(user);

(3) Spring AOP拦截目标方法的执行,并执行与该方法相关联的Aspect切面逻辑。

public class LogAspect {
 
    public void before() {
        System.out.println("记录日志-前置通知");
    }
 
    public void after() {
        System.out.println("记录日志-后置通知");
    }
}

public class UserServiceProxy implements UserService {
 
    private UserService target;
    private LogAspect logAspect;
 
    public UserServiceProxy(UserService target, LogAspect logAspect) {
        this.target = target;
        this.logAspect = logAspect;
    }
 
    public void addUser(User user) {
        logAspect.before();
        target.addUser(user);
        logAspect.after();
    }
}

上述代码中,LogAspect代表了一个切面,在其中实现了目标方法前后的日志记录功能。UserServiceProxy是一个代理类,用来拦截目标方法的执行,并执行与该方法相关联的切面逻辑。其中,代理类需要注入目标对象实例和相关联的切面实例。

由于Spring AOP是基于代理的AOP实现方式,因此在执行过程中会创建一个代理对象,并将目标对象实例和切面逻辑注入代理对象中。然后,在调用代理对象的方法时,代理类会先执行与该方法相关联的切面逻辑,再转发给目标对象实例执行实际的业务逻辑。在方法执行完成之后,代理类又会执行与该方法相关联的切面逻辑。这样,就实现了目标方法前后增加切面逻辑的效果。

通过上述示例,我们可以看到,Spring AOP执行流程相对于普通Java程序执行流程而言多了一步“拦截目标方法的执行,并执行与该方法相关联的Aspect切面逻辑”的过程。这也是AOP编程思想的核心所在。

总结

本篇文章详细介绍了Spring AOP的原理分析和应用场景,以及AOP的底层实现全流程解析。AOP是一种能够将程序中通用部分抽象出来的编程思想,可以在程序运行时动态地向类中添加新的方法或者修改已有的方法。Spring AOP是基于动态代理实现的,通常将要被增强的方法称为切点,将要增加的功能称为切面。Spring AOP可以应用于日志记录、权限控制、数据库事务控制和缓存处理等方面,是提高程序效率和可维护性的一种重要工具。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

U-Net网络

U-Net网络 一、基本架构 各个箭头的解释: conv 3 * 3, ReLU:表示通过一个3 * 3的卷积层,并且该层自动附带一个非线性激活层(ReLu)copy and crop:表示进行裁剪然后再进行拼接(在channel的维度上…

仿真51单片机程序(下载安装+Proteus)

我是看的这个大佬的:http://t.csdnimg.cn/Z07SZ 大佬写的很详细了,我就不献丑了. 贴上俩个运行成功的截图,有碰到问题的欢迎交流.

四川景源畅信:新人做抖店的成本很高吗?

随着社交媒体的兴起,抖音成为了一个新兴的电商平台——抖店。不少创业者和商家看中了其庞大的用户基础,想要通过开设抖店来拓展销路。然而,对于刚入行的新手来说,成本问题总是让人犹豫不决。究竟新人做抖店的成本高不高?本文将围…

学习笔记——STM32F103的V3版本——3*3矩阵键盘控制数码管

一.硬件 1.数码管 2.3*3的矩阵键盘(自己做的模块(手残党一枚)) 3.总体连接 二.在Keil5中的部分软代码 test.c中: #include "sys.h" #include "usart.h" #include "delay.h" #include …

【NumPy】全面解析NumPy的bitwise_xor函数:高效按位异或操作指南

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

【实战JVM】-基础篇-04-自动垃圾回收

【实战JVM】-基础篇-04-自动垃圾回收 自动垃圾回收1 多语言内存管理1.1 C/C的内存管理1.2 Java的内存管理1.3 自动与手动对比1.4 应用场景 2 方法区的回收2.1 回收条件 3 堆回收3.1 判断是否被引用3.1.1 引用计数法3.1.2 可达性分析算法3.1.2.1 GC Root3.1.2.2 监视GC Root3.1.…

如何用分立器件设计一个过流保护电路

过流保护电路是指当后级负载电流过大或者发生短路时,自动切断电源与后级负载,从而防止大电流损害电源电路,过流保护又叫OCP。 常见的过流保护电路有保险丝过流保护,集成的过流保护芯片,还有这种分立器件搭建的过流保护…

检索模型预训练方法:RetroMAE

论文title:https://arxiv.org/pdf/2205.12035RetroMAE: Pre-Training Retrieval-oriented Language Models Via Masked Auto-Encoder 论文链接:https://arxiv.org/pdf/2205.12035 摘要 1.一种新的MAE工作流,编码器和解器输入进行了不同的掩…

React@16.x(12)ref 转发-forwardRef

目录 1,介绍2,类组件如何使用4,应用场景-高阶组件HOC 1,介绍 上篇文章中提到,ref 只能对类组件使用,不能对函数组件使用。 而 ref 转发可以对函数组件实现类似的功能。 使用举例: import Re…

SCI一区 | Matlab实现PSO-TCN-LSTM-Attention粒子群算法优化时间卷积长短期记忆神经网络融合注意力机制多变量时间序列预测

SCI一区 | Matlab实现PSO-TCN-LSTM-Attention粒子群算法优化时间卷积长短期记忆神经网络融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现PSO-TCN-LSTM-Attention粒子群算法优化时间卷积长短期记忆神经网络融合注意力机制多变量时间序列预测预测效果基本介绍程序设…

【CCF-CSP】202309-1 202309-2 坐标变换

坐标变换&#xff08;其一&#xff09; 代码&#xff1a; #include <bits/stdc.h> using namespace std; int main(){int n,m,x,y,sumx0,sumy0;cin>>n>>m;for(int i1;i<n;i){cin>>x>>y;sumxx,sumyy;}for(int i1;i<m;i){cin>>x>&…

用天工AI写文章,节约了8个人的成本

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 当下AI工具最大的问题是什么? 是写的文章没有灵魂、没有感情、像机器人! 生成的文章官话连篇&#xff0c;人们一眼就看出是AI写的&#xff0c;这种文章怎么能给客户交差呢?自己这关都过不去&#xff0c;是吧? …

md5强弱碰撞

一&#xff0c;类型。 1.弱比较 php中的""和""在进行比较时&#xff0c;数字和字符串比较或者涉及到数字内容的字符串&#xff0c;则字符串会被转换为数值并且比较按照数值来进行。按照此理&#xff0c;我们可以上传md5编码后是0e的字符串&#xff0c;在…

四川汇聚荣聚荣科技有限公司好不好?

在当今科技飞速发展的时代&#xff0c;企业要想在激烈的市场竞争中脱颖而出&#xff0c;必须具备强大的技术实力和良好的市场口碑。那么&#xff0c;作为一家专注于科技创新的公司&#xff0c;四川汇聚荣聚荣科技有限公司究竟如何呢?接下来&#xff0c;我们将从四个方面进行详…

K210 数字识别 教程

一、烧写固件 连接k210开发板&#xff0c;点开烧录固件工具&#xff0c;选中固件&#xff0c;并下载 二、模型训练 网站&#xff1a;MaixHub 1、上传文件 2、开始标记数据 添加9个标签&#xff0c;命名为1~9&#xff0c;按键盘w开始标记&#xff0c;键盘D可以下一张图片&…

YashanDB携手慧点科技完成产品兼容认证 助力国产信创生态建设

近日&#xff0c;深圳计算科学研究院崖山数据库系统YashanDB与慧点科技顺利完成兼容性互认证。经严格测试&#xff0c;双方产品完全兼容&#xff0c;稳定运行&#xff0c;共同支撑政府、企业、金融等办公应用场景下的数字化转型升级&#xff0c;为企业的信息技术应用创新提供坚…

C++容器之位集(std::bitset)

目录 1 概述2 使用实例3 接口使用3.1 constructor3.2 count_and_size3.3 test3.4 any3.5 none3.6 all3.7 set3.8 reset3.9 filp3.10 to_string3.11 to_ulong3.12 to_ullong3.13 operators1 概述 位集存储位(只有两个可能值的元素:0或1,true或false,…)。   该类模拟bool…

【C++】<知识点> 标准模板库STL(下)

文章目录 六、set与multiset 1. 常用成员函数 2. pair模板 3. set 4. multiset 七、map与multimap 1. map 2. multimap 3. 应用实例 八、容器适配器 1. stack 2. queue 3. priority_queue 九、算法 六、set与multiset 1. 常用成员函数 iterator find(const T&am…

Kubernetes和Docker对不同OS和CPU架构的适配关系

Docker Docker官网对操作系统和CPU架构的适配关系图 对于其他发行版本&#xff0c;Docker官方表示没有测试或验证在相应衍生发行版本上的安装&#xff0c;并建议针对例如Debian、Ubuntu等衍生发行版本上使用官方的对应版本。 Kubernetes X86-64 ARM64 Debian系 √ √ Re…

鸿蒙学习第一课--认识目录结构

项目结构介绍 module.json5 src > main > module.json5&#xff1a;Stage模型模块配置文件。主要包含HAP包的配置信息、应用/服务在具体设备上的配置信息以及应用/服务的全局配置信息。具体的配置文件说明&#xff0c;详见module.json5配置文件。 资源分类和访问 关于s…