Spring源码_05_IOC容器启动细节
前面几章,大致讲了Spring
的IOC
容器的大致过程和原理,以及重要的容器和beanFactory
的继承关系,为后续这些细节挖掘提供一点理解基础。掌握总体脉络是必要的,接下来的每一章都是从总体脉络中,
去研究之前没看的一些重要细节。
本章就是主要从Spring
容器的启动开始,查看一下Spring
容器是怎么启动的,调用了父类的构造方法有没有干了什么。😄
直接从创建容器为切入点进去:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean(User.class);
进去之后会调用到这个方法:
可以看到这里是分了三步:
1、调用父类构造方法
2、设置配置文件地址
3、刷新容器
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {//调用父类构造方法,其实没做啥,就是如果有父容器(默认啥空),设置父容器和合并父容器的environment到当前容器super(parent);//设置配置文件地址:如果有用了$、#{}表达式,会解析到这些占位符,拿environment里面到属性去替换返回setConfigLocations(configLocations);if (refresh) {//刷新容器,是Spring解析配置,加载Bean的入口。// 用了模板方法设计模型:规定了容器中的一系列步骤refresh();}
}
1. super(parent)-调用父类构造方法
其实这个方法点进去,会调用到一系列父类的super方法,但是最终只是调用到了 AbstractApplicationContext
的构造方法(其实每个父类里面对应的属性都可以看一看,有些都是直接初始化默认的)
/*** Create a new AbstractApplicationContext with the given parent context.* @param parent the parent context*/
public AbstractApplicationContext(@Nullable ApplicationContext parent) {//会初始化resourcePatternResolver属性为PathMatchingResourcePatternResolver//就是路径资源解析器,比如写的"classpath:*",会默认去加载classpath下的资源this();//设置父容器。并会copy父容器的environment属性合并到当前容器中setParent(parent);
}
1.1 this()
接下来调用自己的this方法
public AbstractApplicationContext() {//设置资源解析器this.resourcePatternResolver = getResourcePatternResolver();
}
就是设置了自己的resourcePatternResolver
资源解析器
1.1.1 getResourcePatternResolver()
这个代码没啥,就是创建了一个默认的资源解析处理器 PathMatchingResourcePatternResolver
protected ResourcePatternResolver getResourcePatternResolver() {return new PathMatchingResourcePatternResolver(this);
}
其实这个对象的功能就是把你传进来的字符串的路径,解析加载到具体的文件,返回Spring
能识别的Resource
对象
ok,this
方法走完了应该就继续走之前的setParent(parent)
方法
1.2 setParent(parent)
其实这里目前就是走不进去的,默认的parent父容器我们这里没使用,所以是空的,并不会走if
的逻辑
但是代码也挺简单,其实就是设置了parent属性,合并父容器的Environment
到当前容器的Environment
中
public void setParent(@Nullable ApplicationContext parent) {this.parent = parent;//如歌有父容器,则合并父容器的Environment的元素到当前容器中//合并PropertySource(也就是key和value)//合并激活activeProfiles文件列表//合并默认文件列表defaultProfilesif (parent != null) {Environment parentEnvironment = parent.getEnvironment();if (parentEnvironment instanceof ConfigurableEnvironment) {getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);}}
}
当然,可以假设我们设置了parent
属性。
会先调用到getEnvironment
方法,获取环境对象,如果没有的话,会创建一个默认的
1.2.1 getEnvironment
@Override
public ConfigurableEnvironment getEnvironment() {if (this.environment == null) {this.environment = createEnvironment();}return this.environment;
}
默认是空的,会跑到createEnvironment
方法
1.2.1.1 createEnvironment()
protected ConfigurableEnvironment createEnvironment() {return new StandardEnvironment();
}
会初始化一个StandardEnvironment
类型的对象,我们可以关注他的构造方法,其实并没有内容,但是会默认调用他的父类AbstractEnvironment
构造器的方法
public AbstractEnvironment() {//这里会默认加载属性属性变量和环境信息this(new MutablePropertySources());
}
1.2.1.1.1 new MutablePropertySources()
其实这个对象就是使用了迭代器的设计模式,里面用 propertySourceList
数组存储不同类型的PropertySource
那么PropertySource
是干嘛的呢??
//存放Environment对象里的每个属性,一个PropertySource对象里面存有不同的Properties对象
//Properties对象就是有key和value的键值对象
//比如name=systemProperties -> 系统属性Properties对象
//比如name=systemEnv -> 系统环境变量Properties对象
public abstract class PropertySource<T> {protected final Log logger = LogFactory.getLog(getClass());protected final String name;protected final T source;
}
这里摘取了他的属性。
其实name
只是一个类型而已,比如Environment
包括了systemProperties
(系统属性)和systemEnv
(系统环境变量)两种。对应就是不同的name
的属性存储器
source
属性一般都是Java中的Properties
对象,这个对象大家应该都熟悉吧(就跟map
差不多,有key
和value
,一般用于读取properties
文件使用)
看一下下面的图就知道了,Environment
在Spring中算是非常重要的对象了,所以必须了解
好了,知道了创建了这个默认的对象即可。
接下来就是调用AbstractEnvironment
的this
方法进去了。
AbstractEnvironment(MutablePropertySources)
protected AbstractEnvironment(MutablePropertySources propertySources) {this.propertySources = propertySources;//创建属性解析器PropertySourcesPropertyResolverthis.propertyResolver = createPropertyResolver(propertySources);//调用子类的方法,加载系统的环境变量和系统属性到environment中customizePropertySources(propertySources);
}
可以看到这里就是设置了Environment内部的propertySources
对象(存储属性的容器),
设置了propertyResolver
属性解析器,类型为PropertySourcesPropertyResolver
还把刚刚那个propertySources
设置进去了,这个解析器在后面会用到(在设置配置文件路径时会解析,后面会聊到!)
接下来非常重要的方法就是customizePropertySources
方法了,其实在当前类AbstractEnvironment
中是空方法,是子类 StandardEnvironment
实现的。(这里是不是很熟悉的味道,又是模版方法设计模式,AbstractEnvironment
规定了步骤,调用了当前类的空方法,子类会去覆盖这个空方法)😄
ok,我们进来了子类StandardEnvironment
的customizePropertySources
方法
其实可以看到这里就是写了两句代码,分别就是去读取系统属性和系统环境变量的值,加载到Environment
中
public class StandardEnvironment extends AbstractEnvironment {/** System environment property source name: {@value}. */public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";/** JVM system properties property source name: {@value}. */public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {//添加系统属性和系统环境变量,封装了一个个propertySource对象,添加到Environment的propertySources属性列表中propertySources.addLast(//系统属性new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));propertySources.addLast(//系统环境变量new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));}}
我们可以看其中一个方法getSystemEnvironment
,就是调用了jdk的System.getenv()
方法,去获取到你本机的系统环境变量的值,然后最后设置到propertySources
-> Environment
中
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Map<String, Object> getSystemEnvironment() {if (suppressGetenvAccess()) {return Collections.emptyMap();}try {//jdk提供的方法,获取系统的环境变量return (Map) System.getenv();}catch (AccessControlException ex) {return (Map) new ReadOnlySystemAttributesMap() {@Override@Nullableprotected String getSystemAttribute(String attributeName) {try {return System.getenv(attributeName);}catch (AccessControlException ex) {if (logger.isInfoEnabled()) {logger.info("Caught AccessControlException when accessing system environment variable '" +attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());}return null;}}};}
}
解析完的Environment的里面的值大概是这样:
到这里,应该是理解Environment对象了吧。😄
okk,✋🏻回到之前的调用getEnvironment
的地方,咱们已经看完这个方法啦!也就是标题1.2处
接下里有了Environment
对象,就会进行父子容器的Environment
的合并啦!
1.2.2 Environment.merge()-父子容器的Environment合并
这里的代码就非常简单了,主要就是合并父容器的Environment
的属性到当前子容器中
public void merge(ConfigurableEnvironment parent) {
//合并PropertySource,也就是具体存在的属性键值对
for (PropertySource<?> ps : parent.getPropertySources()) {if (!this.propertySources.contains(ps.getName())) {this.propertySources.addLast(ps);}
}
//合并活跃的profile - 一般SpringBoot中多开发环境都会设置profile
String[] parentActiveProfiles = parent.getActiveProfiles();
if (!ObjectUtils.isEmpty(parentActiveProfiles)) {synchronized (this.activeProfiles) {Collections.addAll(this.activeProfiles, parentActiveProfiles);}
}
//合并默认的profile
String[] parentDefaultProfiles = parent.getDefaultProfiles();
if (!ObjectUtils.isEmpty(parentDefaultProfiles)) {synchronized (this.defaultProfiles) {this.defaultProfiles.remove(RESERVED_DEFAULT_PROFILE_NAME);Collections.addAll(this.defaultProfiles, parentDefaultProfiles);}
}
}
ok,到这里标题1,调用父类构造的方法到这里就结束了,接下来继续探索setConfigLocations
干了什么。
2. setConfigLocations-设置配置文件路径
/*** 设置配置文件地址,并且会将文件路径格式化成标准格式* 比如applicationContext-${profile}.xml, profile存在在Environment。* 假设我的Environment中有 profile = "dev",* 那么applicationContext-${profile}.xml会被替换成 applicationContext-dev.xml* Set the config locations for this application context.* <p>If not set, the implementation may use a default as appropriate.*/
public void setConfigLocations(@Nullable String... locations) {if (locations != null) {//断言,判读当前配置文件地址是空就跑出异常Assert.noNullElements(locations, "Config locations must not be null");this.configLocations = new String[locations.length];for (int i = 0; i < locations.length; i++) {//解析当前配置文件的地址,并且将地址格式化成标准格式this.configLocations[i] = resolvePath(locations[i]).trim();}}else {this.configLocations = null;}
}
这里关键的方法是会调用到resolvePath
方法并返回这些字符串路径
点进去,有没有感觉到很惊喜,为什么用了getEnvironment
去调用的呢?
其实之前的getEnvironment
并没有执行到,因为我们没有设置父类parent,到这里才是第一次初始化这个Environment
对象然后调用它的resolveRequiredPlaceholders
方法去解析路径
(这里关Environment
什么事呢?其实我们可以动态地写我们的配置文件,配置文件会去读取占位符,判断在Environment
是否存在这些属性,并完成替换)
protected String resolvePath(String path) {//这里的获取getEnvironment,会默认创建StandardEnvironment对象。//并用这个Environment对象解析路径return getEnvironment().resolveRequiredPlaceholders(path);
}
写个示例就清楚咯!
2.1. 示例
我的电脑中存在HOME这个环境变量
接下来修改我的配置文件名称:
修改完之后发现,配置文件路径确定给解析到了。
了解这个功能即可。平时很少这么使用
ok,解析完配置,接下来就是最核心的方法了,调用refresh
容器刷新方法
3. refresh-容器刷新方法
这个方法是IOC的核心方法,只要掌握这个方法中的每一个方法,其实就基本掌握了Spring的IOC的整个流程。
后面将会分为很多章节去解释每个方法。
/*** 容器刷新方法,是Spring最核心到方法。* 规定了容器刷新到流程:比如prepareRefresh 前置刷新准备、* obtainFreshBeanFactory 创建beanfactory去解析配置文、加载beandefinition、* prepareBeanFactory 预设置beanfactory、* invokeBeanFactoryPostProcessors 执行beanfactoryPostProcessor* registerBeanPostProcessors 注册各种beanPostProcesser后置处理器* initMessageSource 国际化调用* initApplicationEventMulticaster 初始化事件多播器* onRefresh 刷新方法,给其他子容器调用,目前这个容器没干啥* registerListeners 注册时间监听器* finishBeanFactoryInitialization 初始化所有非懒加载的bean对象到容器中* finishRefresh 容器完成刷新: 主要会发布一些事件** @throws BeansException* @throws IllegalStateException*/
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.//容器刷新的前置准备//设置启动时间,激活状态为true,关闭状态false//初始化environment//初始化监听器列表prepareRefresh();// Tell the subclass to refresh the internal bean factory.//创建beanFactory对象,并且扫描配置文件,加载beanDeifination,注册到容器中ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.//BeanFactory的预准备处理,设置beanFactory的属性,比如添加各种beanPostProcessor//设置environment为bean对象并添加到容器中,后面可以直接@autowrie注入这些对象prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.//子类去实现的回调方法,当前容器没做什么工作,是个空方法postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.//加载并处理beanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.//注册BeanPostProcessor对象到容器中registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.//初始化消息源,国际化使用initMessageSource();// Initialize event multicaster for this context.//初始化事件多播器对象,并注册到容器中initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.//刷新,又是spring为了扩展,做的一个空实现,让子类可以覆盖这个方法做增强功能onRefresh();// Check for listener beans and register them.//注册监听器到容器中,如果容器中的earlyApplicationEvents列表中有事件列表//就会先发送这些事件。比如可以在前面的onRefresh方法中设置registerListeners();// Instantiate all remaining (non-lazy-init) singletons.//最最重要的方法,根据之前加载好的beandefinition,实例化bean到容器中,//涉及到三级缓存、bean的生命周期、属性赋值等等finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.//完成刷新,会发送事件。//检查earlyApplicationEvents事件列表中有没有新增的未发送的事件,有就发送// 在执行applicationEventMulticaster事件列表中的所有事件finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}
}
相关文章:
Spring源码_05_IOC容器启动细节
前面几章,大致讲了Spring的IOC容器的大致过程和原理,以及重要的容器和beanFactory的继承关系,为后续这些细节挖掘提供一点理解基础。掌握总体脉络是必要的,接下来的每一章都是从总体脉络中, 去研究之前没看的一些重要…...
【c语言】简单的c程序设计
内存 1byte8bit 1KB1024byte 1MB1024byte 1G1024MB 1T1024G 变量 变量可以由数字、字母和下划线组成且不能以数字开头任何不满足条件的变量都是非法变量,如含有特殊字符的变量等变量不能含有空白字符,如空格、换行符等变量区分大小写变量不能是c语言…...
k8s dashboard可视化操作界面的安装
一、官方安装方法 根据官网的安装配置可以选择如下安装: kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml 二、添加阿里云加速进行安装 #修改recommended.yaml拉取镜像的链接 vim recommended.yam…...
鸿蒙项目云捐助第三十一讲云捐助项目云前台显示商品列表
鸿蒙项目云捐助第三十一讲云捐助项目云前台显示商品列表 前面完成了云数据库后台的商品批量添加,这里需要把数据放在分类导航页面中显示。 一、云前台显示商品列表 这里需要把商品列表显示在MyNavSliderBar的组件中,MyNavSliderBar组件是通过首页路由实现的,在项…...
【rustdesk】客户端和服务端的安装和部署(自建服务器,docker,远程控制开源软件rustdesk)
【rustdesk】客户端和服务端的安装和部署(自建服务器,docker) 一、官方部署教程 https://rustdesk.com/docs/zh-cn/client/mac/ 官方服务端下载地址 https://github.com/rustdesk/rustdesk-server/releases 我用的docker感觉非常方便&am…...
Flink源码解析之:如何根据算法生成StreamGraph过程
Flink源码解析之:如何根据算法生成StreamGraph过程 在我们日常编写Flink应用的时候,会首先创建一个StreamExecutionEnvironment.getExecutionEnvironment()对象,在添加一些自定义处理算子后,会调用env.execute来执行定义好的Flin…...
【Spring MVC 核心机制】核心组件和工作流程解析
在 Web 应用开发中,处理用户请求的逻辑常常会涉及到路径匹配、请求分发、视图渲染等多个环节。Spring MVC 作为一款强大的 Web 框架,将这些复杂的操作高度抽象化,通过组件协作简化了开发者的工作。 无论是处理表单请求、生成动态页面&#x…...
2、Bert论文笔记
Bert论文 1、解决的问题2、预训练微调2.1预训练微调概念2.2深度双向2.3基于特征和微调(预训练下游策略) 3、模型架构4、输入/输出1.输入:2.输出:3.Learned Embeddings(学习嵌入)1. **Token Embedding**2. **Position Embedding**3…...
hadoop搭建
前言 一般企业中不会使用master slave01 slave02来命名 vmware创建虚拟机 打开vmware软件,新建虚拟机 典型 稍后安装系统 选择centos7 虚拟机名称和安放位置自行选择(最小化安装消耗空间较少) 默认磁盘大小即可 自定义硬件 选择centos7的i…...
19_HTML5 Web Workers --[HTML5 API 学习之旅]
HTML5 Web Workers 是一种允许 JavaScript 在后台线程中运行的技术,从而不会阻塞用户界面或其他脚本的执行。通过使用 Web Workers,你可以执行复杂的计算任务而不影响页面的响应速度,提升用户体验。 Web Workers 的特点 Web Workers 是 HTM…...
【PCIe 总线及设备入门学习专栏 5.1 -- PCIe 引脚 PRSNT 与热插拔】
文章目录 OverviewPRSNT 与热插拔PRSNT 硬件设计 Overview Spec 定义的热插拔是把一个PCIe卡(设备)从一个正在运行的背板或者系统中插入/或者移除。这个过程需要不影响系统的其他功能。插入的新的设备可以正确工作。 显然,这里面需要考虑的问…...
使用docker compose安装gitlab
使用docker compose安装gitlab GitLab简介设置GITLAB_HOME路径创建docker挂载目录获取可用的GitLab版本编写docker-compose.yml文件启动docker基础配置 GITLAB_OMNIBUS_CONFIG修改配置 中文设置数据库配置系统邮箱配置 GitLab简介 GitLab是一个基于Git的开源项目,…...
性能中 UV、PV 和并发量的关系
在性能测试中,UV(独立访客数)、PV(页面浏览量)和并发量是重要的指标,用于评估系统的负载能力。它们之间关系紧密,需要通过合理的计算和示例进行说明。 1. 概念解析 UV(Unique Visito…...
Go语言zero项目服务恢复与迁移文档
## 一. 服务器环境配置 在迁移和配置 项目时,首先需要确保服务器环境正确配置。以下是配置步骤: ### 1. 安装 Go 语言环境 首先,确保 Go 语言环境已经安装,并且配置正确。执行以下步骤: # 下载 Go 语言安装包 wge…...
Redis - Token JWT 概念解析及双token实现分布式session存储实战
Token 定义:令牌,访问资源接口(API)时所需要的资源凭证 一、Access Token 定义:访问资源接口(API)时所需要的资源凭证,存储在客户端 组成 组成部分说明uid用户唯一的身份标识time…...
QT中使用OpenGL function
1.前言 QT做界面编程很方便,QTOpenGL的使用也很方便,因为QT对原生的OpenGL API进行了面向对象化的封装。 如: 函数:initializeOpenGLFunctions()...... 类:QOpenGLVertexArrayObject、QOpenGLBuffer、QOpenGLShader…...
STM32-笔记18-呼吸灯
1、实验目的 使用定时器 4 通道 3 生成 PWM 波控制 LED1 ,实现呼吸灯效果。 频率:2kHz,PSC71,ARR499 利用定时器溢出公式 周期等于频率的倒数。故Tout 1/2KHZ;Ft 72MHZ PSC71(喜欢设置成Ft的倍数&…...
MAC M4安装QT使用国内镜像源在线安装
MAC M4安装QT使用国内镜像源在线安装 一、下载安装包1. 访问[https://www.qt.io/](https://www.qt.io/)下载在线安装包2. 下载结果 二、创建QT账户,安装的时候需要三、安装1. 终端打开安装包2. 指定安装源3. 运行安装完的QT 一、下载安装包 1. 访问https://www.qt.…...
go语言中zero框架项目日志收集与配置
在 GoZero 项目中,日志收集和配置是非常重要的,尤其是在分布式系统中,日志可以帮助开发人员追踪和排查问题。GoZero 提供了灵活的日志系统,能够方便地进行日志的配置和管理。 以下是如何在 GoZero 项目中进行日志收集与配置的基本…...
springboot496基于java手机销售网站设计和实现(论文+源码)_kaic
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本手机销售网站就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…...
iClient3D for Cesium在Vue中快速实现场景卷帘
作者:gaogy 1、背景 iClient3D for Cesium是由SuperMap提供的一个前端3D地图客户端,提供了丰富的功能与接口,使得开发者能够在Web应用中快速集成并展现3D地理信息。而在Vue框架中集成iClient3D,不仅可以利用Vue的响应式特性提高开…...
Elasticsearch-索引的批量操作
索引的批量操作 批量查询和批量增删改 批量查询 #批量查询 GET product/_search GET /_mget {"docs": [{"_index": "product","_id": 2},{"_index": "product","_id": 3}] }GET product/_mget {"…...
TVS二极管选型【EMC】
TVS器件并联在电路中,当电路正常工作时,他处于截止状态(高阻态),不影响线路正常工作,当线路处于异常过压并达到其击穿电压时,他迅速由高阻态变为低阻态,给瞬间电流提供一个低阻抗导通…...
反编译APK获取xml资源
第一步去官网下载 jar 包 最新的即可 apktool官网下载地址 下载好重命名一下 改成 apktool.jar 第二步将你的 apk 和 jar 包放在同一个文件夹下面 第三步在该文件夹下打开 命令行 并输入 java -jar apktool.jar d 测试.apk回车后会正在解析 解析完成后,文件夹下…...
C++ 设计模式:装饰模式(Decorator Pattern)
链接:C 设计模式 链接:C 设计模式 - 桥接模式 装饰模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。装饰模式通过创建一个装饰类来包装原始类&…...
排序算法之快速排序、归并排序
目录 快速排序归并排序的意义 快速排序 思维步骤 具体思想 测试样例解释 代码实现 归并排序 思维步骤 具体思想 测试样例解释 代码实现 快速排序归并排序的意义 快速排序和归并排序不仅仅是一种方法,更重要的是其作为一种算法而节省时间,在…...
一文读懂变分自编码(VAE)
一文读懂变分自编码(VAE) 概述 变分自编码器(Variational Autoencoder, VAE)是一种生成模型,用于学习数据的潜在表示并生成与原始数据分布相似的新数据。它是一种概率模型,通过结合深度学习和变分推断的思想,解决了传…...
【每日学点鸿蒙知识】webview性能优化、taskpool、热更新、Navigation问题、调试时每次都卸载重装问题
1、HarmonyOS webview页面第二次,第三次打开感觉和第一次打开速度差不多,有优化吗,或者有没有webview秒开方案之类的? 目前没有webview秒开的方案,针对web场景的优化参考一下文档:https://developer.huawe…...
周记-唐纳德的《计算机程序设计艺术》
用代码生成代码 开发一个协议,字段有些多,每个字段是QT的属性,需要写Q_PROPERTY,一个一个编辑的话比较繁琐,耗费时间。后来就用代码生成了头文件和源文件,get和set还有signal函数,内容基本都是…...
AR 模型的功率谱
功率谱密度(Power Spectral Density, PSD)的表达式是从信号的自相关函数和系统的频率响应推导出来的,特别是对于 AR(Auto-Regressive,自回归)模型。以下是推导的过程: 1. AR 模型的定义…...
抖音小程序登录(前端通过tt.login获取code换取openId)
抖音小程序登录 抖音开放平台小程序登录: https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/tutorial/basic-ability/microapp-login 前端(通过tt.login获取code) 流程 静默登录依赖小程序 API tt.login,把tt.loginsuccess 回调…...
Linux 更改Jenkins使用其他账户启动
Linux 更改Jenkins使用其他账户启动 步骤一:修改 Jenkins 配置文件1. 编辑 Jenkins 的 systemd 服务文件:2. 在编辑器中添加以下内容:3. 保存并退出编辑器 步骤二:更改 Jenkins 目录的权限步骤三:重新加载 systemd 配置…...
117.【C语言】数据结构之排序(选择排序)
目录 1.知识回顾 2.分析 设想的思路 代码 执行结果 编辑 错误排查和修复 详细分析出错点 执行结果 3.正确的思路 4.其他问题 1.知识回顾 参见42.5【C语言】选择排序代码 点我跳转 2.分析 知识回顾里所提到的文章的选择排序一次循环只比一个数字,和本文接下来要…...
读书系列2024
认知类 1、《人生没有太晚的开始》: 作者摩西奶奶。 书中经典语录:“与其着急忙慌地不知从何开始,不如一切都慢慢来,开始并坚持了,总会有结果的那一天。喜欢一件事,你就慢慢去做吧。” 2、《忏悔录》托尔…...
如何快速又安全的实现端口转发【Windows MAC linux通用】
背景 有很多程序是在虚拟机上运行的,返回的url 又是127.0.0.1。在个人电脑上调试需要解决这个问题。端口转发是一个不错的方法 可能的解决办法: 1.修改程序,返回虚拟机的ip (要改代码,换虚拟机还要再改代码…...
OpenGL变换矩阵和输入控制
在前面的文章当中我们已经成功播放了动画,让我们的角色动了起来,这一切变得比较有意思了起来。不过我们发现,角色虽然说是动了起来,不过只是在不停地原地踏步而已,而且我们也没有办法通过键盘来控制这个角色来进行移动…...
51单片机学习笔记——找不到REG52.H头文件,点亮一个LED
创建工程 将STC型号导入keil并使用 STC可以从官网下载,也可我这的网盘: 链接:https://pan.baidu.com/s/1bO85DPN3IFaXGhiKSwyOrA?pwd7f4h 提取码:7f4h 打开STC,选择“keil仿真设置”,选择“添加型号和头…...
07 基于OpenAMP的核间通信方案
引言 ZYNQ7020有两个CPU核心,这两个核心可以采用SMP或AMP方式进行调度,当采用AMP方式进行调度时核0和核1可以运行不同的操作系统,如核0运行Linux系统,提供有些复杂的用户交互工作,核1运行实时操作系统,对设…...
Ubuntu升级ssh版本到9.8
方案一:实测只有8.9有漏洞不推荐 1、更新软件包列表 sudo apt update 2、查找可用版本 apt-cache policy openssh-server 3、 选择版本 sudo apt install openssh-server1:9.8p1-<具体版本号> 4、 重启 sudo systemctl restart ssh 5、验证版本 /usr/sbin/ss…...
git设置项目远程仓库指向github的一个仓库
要将你的Git项目设置为指向GitHub上的远程仓库,你需要执行以下步骤: 创建GitHub仓库: 登录到你的GitHub账户。点击右上角的 “” 号,选择 “New repository” 创建一个新的仓库。填写仓库的名称,可以添加描述ÿ…...
【实战示例】面向对象的需求建模
前言 博主准备写一个以面向对象为核心思想的软件需求建模、领域建模的系列,总结一整套可落地的DDD的打法,前面几篇文章论述了如何进行面向对象的需求建模,本文将以一个简单的购物商城的需求来演示如何进行面向对象的需求建模。 面向对象的需…...
平方数的判断不用sqrt()函数
//判断一个数是不是平方数,13…(2*m-1)m*mn #include<stdio.h> int main(){ int n; scanf("%d",&n); int i; for(i1;n>0;i2){ nn-1; } if(n0){ printf("YES!\n"); …...
node.js之---回调函数
什么是回调函数? 为什么会有回调函数? 回调函数的特性 回调函数的应用场景 怎么解决回调地狱 什么是回调函数? 回调函数是一个函数,他作为参数传递给另外一个函数,并且会在另外一个函数执行完毕之后被调用&#…...
浏览器http缓存问题
一、什么是浏览器缓存 浏览器将请求过的资源(html、js、css、img)等,根据缓存机制,拷贝一份副本存储在浏览器的内存或者磁盘上。如果下一次请求的url相同时则根据缓存机制决定是读取内存或者磁盘上的数据还是去服务器请求资源文件…...
编写一个简单的引导加载程序(bootloader)
编写一个简单的引导加载程序(bootloader)通常用于嵌入式系统或自定义操作系统。这里,我将为你提供一个基于x86架构的简单汇编语言 bootloader 示例。这个 bootloader 将会在启动时打印一条消息到屏幕上。 使用 NASM 汇编器来编写这个 bootlo…...
Three.js 字体
在 Three.js 中,我们可以通过 FontLoader 加载字体,并结合 TextGeometry 创建 3D 文本。加载字体是因为字体文件包含了字体的几何信息,例如字体的形状、大小、粗细等,而 TextGeometry 则是根据字体信息生成 3D 文本的几何体。 在…...
Jenkins 构建流水线
在 Linux 系统上安装 Jenkins 服务,以及配置自动化构建项目 前置准备环境:docker、docker-compose、jdk、maven 一、环境搭建 1. Jenkins 安装 (1)拉取镜像 # 安装镜像包,默认安装最新版本 docker pull jenkins/jen…...
ES 磁盘使用率检查及处理方法
文章目录 1. 检查原因2. 检查方法3. 处理方法3.1 清理数据3.2 再次检查磁盘使用率 1. 检查原因 磁盘使用率在 85%以下,ES 可正常运行,达到 85%及以上会影响 PEIM 数据存储。 在 ES 磁盘分配分片控制策略中,为了保护数据节点的安全࿰…...
【回溯】LeetCode经典题目总结:组合、排列、子集、分割、N皇后、单词搜索
回溯 组合问题组合总和全排列子集分割回文串N皇后电话号码的字母组合单词搜索括号生成 组合问题 给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 树形结构࿱…...
uniapp开发小程序内嵌h5页面,video视频两边有细小黑色边框
1.问题如图 2.原因分析 是否为设置上述属性呢? 设置了,但是仍然有黑边。经过选中页面元素分析后,判断video元素本身就有这种特点,就是视频资源无法完全铺满元素容器。 3.解决方案...