SpringBoot3核心原理
SpringBoot3核心原理
事件和监听器
生命周期监听
场景:监听应用的生命周期
可以通过下面步骤自定义SpringApplicationRunListener来监听事件。
①、编写SpringApplicationRunListener
实现类
②、在META-INF/spring.factories
中配置org.springframework.boot.SpringApplicationRunListener=自己的Listener
,还可以指定一个有参构造器,接收两个参数SpringApplication application, String[] args
③、springboot在spring-boot.jar
中配置了默认的Listener,如下:
org.springframework.boot.SpringApplicationRunListener=
org.springframework.boot.context.event.EventPublishingRunListener
场景实现
创建监听器
MyApplicationListener
package com.louis.listener;import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;import java.time.Duration;/*** springboot应用生命周期监听* @author XRY* @date 2023年07月14日14:51*/
public class MyApplicationListener implements SpringApplicationRunListener {@Overridepublic void starting(ConfigurableBootstrapContext bootstrapContext) {System.out.println("===========starting==========正在启动=======");}@Overridepublic void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {System.out.println("===========environmentPrepared==========环境准备完成=======");}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {//相当与IOC容器System.out.println("===========contextPrepared==========ioc容器准备完成=======");}@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {System.out.println("===========contextLoaded==========ioc容器加载完成=======");}@Overridepublic void started(ConfigurableApplicationContext context, Duration timeTaken) {System.out.println("===========started==========启动完成=======");}@Overridepublic void ready(ConfigurableApplicationContext context, Duration timeTaken) {System.out.println("===========ready==========准备就绪=======");}@Overridepublic void failed(ConfigurableApplicationContext context, Throwable exception) {System.out.println("===========failed==========应用启动失败=======");}
}
提示:
想要让配置的监听器生效,需要在根目录下创建一个META-INF文件夹并添加文件spring.factories(它是一个key,value写法:key为接口全类名, value为我们创建类的全类名)
org.springframework.boot.SpringApplicationRunListener=com.louis.listener.MyApplicationListener
springboot应用生命周期监听
Listener先要从BootStrapContext引导整个项目启动,主要分为下面的几个步骤:
-
引导:利用BootstrapContext引导整个项目启动
starting:应用开始,调用SpringApplication的run方法,只要有了BootStrapContext就执行 environmentPrepared:环境准备好(把启动参数等绑定到环境变量中),但是ioc容器还没有创建。(调一次)
-
启动:
contextPrepared: ioc容器创建并准备好,但是sources(主配置类)没加载,并关闭上下文,组件还没有创建(调一次)
contextLoaded: ioc容器加载。著配置类加载进去,但是ioc容器还没有刷新。(Bean都没创建)
started: ioc容器刷新了(容器中加入了Bean),但是runner没调用。
ready: ioc容器刷新了(容器中加入了Bean),所有runner调用完。 -
运行
以前的步骤都正确执行,代表容器running
事件触发时机
1、各种回调监听器介绍
监听器 | 监听阶段 | 作用 | 使用场景 |
---|---|---|---|
BootstrapRegistryInitializer | 感知特定阶段 | 感知引导初始化META-INF/spring.factories 创建引导上下文bootstrapContext的时候触发可以在主程序调用:application.add.BootstrapRegistryInitializer() | 进行密钥校对授权 |
ApplicationContextInitializer | 感知特定阶段 | 感知ioc容器初始化META-INF/spring.factories | |
ApplicationListener | 感知全阶段 | 基于事件机制,感知事件。@Bean或EventListener、SpringApplication.addListeners(…)或SpringApplicationBuilder.listeners(…)、META-INF/spring.factories | |
SpringApplicationRunListener | 感知全阶段生命周期+各种阶段 | 自定义操作META-INF/spring.factories | |
ApplicationRunner | 感知特定阶段 | 感知应用就绪Ready的@Bean | |
CommandLineRunner | 感知特定阶段 | 感知应用就绪Ready的@Bean |
总结:
如果项目启动前做事:BootstrapRegistryInitializer和ApplicationContextInitializer
如果想要在项目启动完成后做事:ApplicationRunner和CommandLineRunner
如果想要干涉生命周期:SpringApplicationRunListener
如果想要用事件机制:ApplicationListener
2、事件完整触发流程(9种事件)
- ApplicationStartingEvent:应用启动但未做任何事情,
- ApplicationEnvironmentPreparedEvent:Environment准备好,但context未创建
- ApplicationContextInitializedEvent:ApplicationContext准备好,ApplicationContextInitializers调用,到那时任何bean未加载
- ApplicationPreparedEvent:容器刷新之前,bean定义信息加载
- ApplicationStartedEvent:容器刷新完成,runner未调用
- AvailabilityChangeEvent:LivenessState.CORRECT应用存活,存活探针
- ApplicationReadyEvent:任何runner被调用
- AvailabilityChangeEvent:ReadinessState.ACCEPTING_TRAFFIC应用就绪,可以接收请求,就绪探针
- ApplicationFailedEvent:启动出错
事件发送顺序
**两个探针的作用是感知应用是否存货和就绪。 **
3、SpringBoot事件驱动开发
应用启动过程生命周期事件感知(9大事件)、应用运行中事件感知(无数种)
- 事件发布:ApplicationEventPublisherAware或注入:ApplicationEventMulticaser
- 事件监听:组件 + @EventListener
示例
创建service
AccountService
@Service
public class AccountService {public void addAccountScore(String username){System.out.println(username + "加了1分");}
}
CouponService
@Service
public class CouponService {public void sendCoupon(String username){System.out.println(username + "随机得到了一张优惠券");}
}
SystemService
@Service
public class SystemService {public void recordLog(String username, String password){System.out.println(username + " ,密码为" + password + "登录信息已被记录");}
}
不使用事件
LoginController
@RestController
public class LoginController {@AutowiredAccountService accountService;@AutowiredCouponService couponService;@AutowiredSystemService systemService;@GetMapping("login")public String login(@RequestParam String username,@RequestParam String password){//业务处理登录System.out.println("业务处理登录完成.........");//1、账户服务自动签到加积分accountService.addAccountScore(username);//2、优惠服务随机发放优惠券couponService.sendCoupon(username);//3、系统服务登记用户登录信息systemService.recordLog(username, password);return username + "登录成功";}
}
使用事件机制
创建实体类UserEntity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {private String username;private String password;
}
创建事件LoginSuccessEvent,继承ApplicationEvent
package com.louis.event;import com.louis.entity.UserEntity;
import org.springframework.context.ApplicationEvent;import java.awt.desktop.AppEvent;/*** @author XRY 登录成功事件, 所有事件都推荐继承ApplicationEvent* @date 2023年07月14日19:19*///登录成功事件
public class LoginSuccessEvent extends ApplicationEvent {/*** @param source 代表谁登录成功了*/public LoginSuccessEvent(UserEntity source) {super(source);}
}
创建事件发送类 EventPublisher
package com.louis.event;import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;/*** @author XRY* @date 2023年07月14日19:18*/
@Service
public class EventPublisher implements ApplicationEventPublisherAware {/*** 底层发送事件的组件,SpringBoot会通过ApplicationEventPublisherAware接口自动注入给我们*/ApplicationEventPublisher applicationEventPublisher;/*** 所有事件都可以发* @param event*/public void sendEvent(ApplicationEvent event){//用底层API发送事件applicationEventPublisher.publishEvent(event);}/*** 会被自动调用,把真正发事件的底层组件注入进来* @param applicationEventPublisher*/@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}
}
控制器LoginController
@RestController
public class LoginController {//事件@AutowiredEventPublisher eventPublisher;@GetMapping("login")public String login(@RequestParam String username,@RequestParam String password){//业务处理登录System.out.println("业务处理登录完成.........");//发送事件//1、创建事件信息LoginSuccessEvent event = new LoginSuccessEvent(new UserEntity(username, password));//2、发送事件eventPublisher.sendEvent(event);return username + "登录成功";}
}
自动配置原理
入门理解
应用关注的三大核心:场景、配置、组件
1、 自动配置流程
①、导入starter
②、依赖导入autoconfigure
③、寻找类路径下META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.import文件
④、启动,加载所有自动配置类-xxxAutoConfiguration
i、给容器种配置功能组件
ii、组件参数绑定到属性类中。xxxProperties
iii、属性类和配置文件前缀项绑定
iV、@Conditional派生的条件注解进行判断是否组件生效
⑤、效果:
i、修改配置文件、修改底层参数
ii、所有场景自动配置好直接使用
iii、可以注入SpringBoot配置好的组件随时使用。
2、SPI机制
SPI 全称是 Service Provider Interface,是一种 JDK 内置的动态加载实现扩展点的机制,通过 SPI 技术我们可以动态获取接口的实现类,不用自己来创建。这个不是什么特别的技术,只是 一种设计理念。它实际上是基于接口的编程+策略模式+配置文件组合实现的动态加载机制。
系统设计的各个抽象,往往有很多不同的实现方案,在面向对象的设计里,一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。Java SPI就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。所以SPI的核心思想就是解耦。
3、功能开关
-
自动配置:全部都配置好,什么都不用管,自动批量导入。
项目启动,spi文件中指定的所有都加载
-
@Enablexxx:手动控制哪些功能的开启,手动导入。
开启xxx功能,都是利用@Import把此功能要用的组件导入进去。
进阶理解
@SpringBootApplication是以下三个注解的复合注解:
①、@SpringBootConfiguration:就是@Configuration,容器中的组件,配置类。Spring ioc启动就会加载创建这个类对象。
②、@EnableAutoConfiguration:开启自动配置,由如下两注解复合:
- @AutoConfigurationPackage
扫描主程序包。利用@Import(AutoConfigurationPackages.Registrar.class)加载自己想要给容器中导入的组件。把主程序所在包的所有组件导入进来。即只扫描主程序及主程序所在的包及其子包。
- @Import(AutoConfigurationImportSelector.class)
加载所有自动配置类,加载starter导入组件List configurations = ImportCandidates.load(AutoConfiguration.class,getBeanClassLoader()).getCandidates();
扫描SPI文件:“META-INF/spring/org.springframework.boot.autoconfigure.Autoconfiguration.imports”
③、@ComponentScan
组件扫描,排除一些组件,排除前面已经扫描进来的配置类和自动配置类。
自定义starter
场景:抽取聊天机器人场景,它可以打招呼。
效果:任何项目导入此starter都具有打招呼功能,并且问候语中的人名需要可以在配置文件中修改。
实现步骤
①、创建自定义starter项目,引入spring-boot-starter基础依赖
②、编写模块功能,引入模块所有需要的依赖,编写xxxAutoConfiguration自动配置类
③、编写配置文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports指定启动需要加载的自动配置。
④、其他下项目引入即可使用。
通用业务代码
小技巧:可以导入如下依赖重启项目,再写配置文件会有提示。
<!--导入配置处理器,自定义的properties配置文件会有提示-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>
配置类
@ConfigurationProperties(prefix = "robot")
@Component
@Data
public class RobotProperties {private String name;private String email;private Integer age;
}
配置文件
robot.name=张三
robot.age=23
robot.email=louis@qq.com
通用功能
@Service
public class RobotService {@AutowiredRobotProperties robotProperties;public String sayHello(){return "你好:" + robotProperties.getName() + " ;年龄:" + robotProperties.getAge();}
}
控制器
@RestController
public class RobotController {@AutowiredRobotService robotService;@GetMapping("/robot/hello")public String sayHello(){return robotService.sayHello();}
}
基本抽取(新建模块)
新建模块时不需要选择任何场景。
复制公共功能
根据公共功能,添加场景
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
<!--导入配置处理器,自定义的properties配置文件会有提示-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>
删除主类
在需要引用项目下导入该starter
<!--自定义的starter-->
<dependency><groupId>com.louis</groupId><artifactId>boot3-robot-starter</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>
在starter下编写配置类
原因:SpringBoot项目只能扫描主程序以及主程序所在的子包,当导入自定义的starter时,不属于这一层级。
@Configuration
@Import({RobotController.class, RobotService.class, RobotProperties.class})
public class RobotAutoConfiguration {}
在主程序导入配置类
@SpringBootApplication
@Import(RobotAutoConfiguration.class)
public class Boot307Application {public static void main(String[] args) {SpringApplication.run(Boot307Application.class, args);}}
引入starter不会读取starter本身的配置。
编写application.properties
robot.name=louie
robot.age=23
robot.email=louis@qq.com
测试
总结:
a、创建starter,将公共代码所需的所有依赖导入
b、将公共代码复制到starter
c、自己写一个RobotAutoConfiguration,该容器中导入需要组件(主程序扫描规则)
d、测试功能
使用Enable机制
原因:在导入starter的时候,使用者可能不知道需要导入哪些相关的文件。
在我们的starter编写注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RobotAutoConfiguration.class})
public @interface EnableRobot {
}在主程序中使用@EnableRobot注解
@SpringBootApplication
@EnableRobot
public class Boot307Application {public static void main(String[] args) {SpringApplication.run(Boot307Application.class, args);}}
测试
总结:
别人引入starter需要使用@EnableRobot开启功能
完全自动
依赖SpringBoot的SPI机制"META-INF/spring/org.springframework.boot.autoconfigure.Autoconfiguration.imports"在其中放置RobotAutoConfiguration
配置类的全类名。如:com.louis.starter.robot.config.RobotAutoConfiguration
只需要导入starter,不用加任何注解。
测试
相关文章:

SpringBoot3核心原理
SpringBoot3核心原理 事件和监听器 生命周期监听 场景:监听应用的生命周期 可以通过下面步骤自定义SpringApplicationRunListener来监听事件。 ①、编写SpringApplicationRunListener实现类 ②、在META-INF/spring.factories中配置org.springframework.boot.Sprin…...
JS常用数据类型转换(数字型和字符串型之间转换)
提供了5中基本数据类型:数字 number 字符串 string 布尔 boolean 空值 null 未定义的 undefined 常用的是数字型和字符串型之间的转换,常用的转换方法如下: 1 数字型转换成字符串型 a) 使用String()方法…...

算法通关村第一关—青铜挑战—用Java基本实现各种链表操作
文章目录 第一关—链表【青铜挑战】1.1 单链表的概念1.2 链表的相关概念1.3 创建链表 - Java实现1.4 链表的增删改查1.4.1 遍历单链表 - 求单链表长度1.4.2 链表插入 - 三种位置插入(1)在链表的表头插入(2)在链表的中间插入&#…...

SparkRDD及算子-python版
RDD相关知识 RDD介绍 RDD 是Spark的核心抽象,即 弹性分布式数据集(residenta distributed dataset)。代表一个不可变,可分区,里面元素可并行计算的集合。其具有数据流模型的特点:自动容错,位置…...

嵌入式设备与PC上位机通信协议设计的几点原则
嵌入式设备在运行中需要设置参数,这个工作经常由PC机来实现,需要为双方通信设计协议,有代表性协议是如下三种: 从上表可以看到,一般嵌入式设备内存和运算性能都有限,因此固定二进制是首选通信协议。 一&am…...

Go 内置运算符
一、算数运算符 1、算数运算符使用 package mainimport ("fmt" )func main(){fmt.PrintIn("103",103) //10313fmt.PrintIn("10-3",10-3) //10-37fmt.PrintIn("10*3",10*3) //10*330//除法注意:如果运算的数都是…...

Table和HashBasedTable的使用案例
------------------- 1.普通使用 package org.example.testhashbasedtable;import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table;import java.util.Map;public class TestHashBasedTable {public static void main(String[] args) {Ta…...

【执行批处理后 executeBatch() 没反应,一个参数相信就能搞定】
一、场景是在使用EasyExcel读取全表时,每次手动提交事务6w多条,总计190w数据量的情况下发生的。 博主比较fw,卡住了两天😶 此问题还有一个比较bug的地方,就是当你在 executeBatch() 上下打断点时还能够执行出来&…...

【LeetCode】每日一题 2023_11_25 二叉树中的伪回文路径(dfs,数组/位运算)
文章目录 刷题前唠嗑题目:二叉树中的伪回文路径题目描述代码与解题思路偷看大佬题解 结语 刷题前唠嗑 LeetCode?启动!!! 这个月第一次周末早起~ 题目:二叉树中的伪回文路径 题目链接:1457. 二…...

什么是海外私人IP代理?是纯净独享的代理吗?
相信许多互联网工作者都遇到过IP禁令,比如网络抓取项目,使用共享代理服务器向网站发出第一个请求,但却您收到了禁令,这大部分是由于你的共享IP经过多人使用被禁用所致。 那么到底什么是私人代理呢?它们是否适合您的情…...
Vue组件库推荐:Element UI深度解析
在Vue开发中,使用组件库可以极大地提高开发效率,减少重复工作量。Element UI作为一款优秀的Vue组件库,被广泛应用于各类项目中。本文将对Element UI进行深度解析,为开发者提供详细的使用说明和具体的代码示例。 1,Ele…...

Mysql 8.0主从复制模式安装(兼容Mysql 5.7)
Mysql V8.0.35安装 官网地址:MySQL :: Download MySQL Community Server 下载【Mysql 8.0.35】压缩包 解压压缩包,仅保留6个安装文件即可 mysql-community-client-8.0.31-1.el7.x86_64.rpm mysql-community-client-plugins-8.0.31-1.el7.x86_64.rpm my…...

基于Django+Tensorflow卷积神经网络鸟类识别系统
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介系统概述系统功能核心技术系统架构系统优势 二、功能三、系统四. 总结 总结 一项目简介 介绍一个基于DjangoTensorflow卷积神经网络鸟类识别系统是一个非…...

史上最全前端知识点+高频面试题合集,十二大专题,命中率高达95%
前言: 下面分享一些关于阿里,美团,深信服等公司的面经,供大家参考一下。大家也可以去收集一些其他的面试题,可以通过面试题来看看自己有哪里不足。也可以了解自己想去的公司会问什么问题,进行有针对的复习。…...

我叫:基数排序【JAVA】
1.自我介绍 基数排序(radix sort)属于“分配式排序” (distribution sort),又称“桶子法” (bucket sort)或bin sort,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,是‘桶排序’的扩展 2.基本思想 将所有待比较数值统一为同样的数位长度,数位较短的数…...

ArkUI开发进阶—@Builder函数@BuilderParam装饰器的妙用与场景应用【鸿蒙专栏-05】
ArkUI开发进阶—@Builder函数@BuilderParam装饰器的妙用与场景应用 HarmonyOS,作为一款全场景分布式操作系统,为了推动更广泛的应用开发,采用了一种先进而灵活的编程语言——ArkTS。ArkTS是在TypeScript(TS)的基础上发展而来,为HarmonyOS提供了丰富的应用开发工具,使开…...

智慧城市内涝积水监测仪功能,提升城市预防功能
内涝积水监测仪不仅改变了人们应对城市内涝的老办法,还让智慧城市往前迈了一大步。这个监测仪是怎么做到的呢?就是靠它精准的数据监测和预警,让城市管理有了更科学高效的解决妙招。它就像有了个聪明又负责任的助手,让城市管理更加…...

ISCTF2023 部分wp
学一年了还在入门( web where_is_the_flag ISCTF{41631519-1c64-40f6-8dbb-27877a184e74} 圣杯战争 <?php // highlight_file(__FILE__); // error_reporting(0);class artifact{public $excalibuer;public $arrow;public function __toString(){echo "为Saber选择…...
springboot(ssm毕业生学历证明系统Java(codeLW)
springboot(ssm毕业生学历证明系统Java(code&LW) 开发语言:Java 框架:ssm/springboot vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7(或8.0) 数据…...

分布式锁3: zk实现分布式锁
一 zk 实现分布式锁 1.1 zk分布式操作命令 1.指令: ls / get /zookeeper create /aa "test" delete /aa set /aa "test1" 分布式锁实现原理与最佳实践 2..znode节点类型: 永…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...