Sping源码(七)— 后置处理器
简单回顾一下上一篇文章,是在BeanFacroty创建完之后,可以通过Editor和EditorRegistrar实现对类属性的自定义扩展,以及忽略要自动装配的Aware接口。
本篇帖子会顺着refresh()主流程方法接着向下执行。在讲invokeBeanFactoryPostProcessors方法的具体逻辑之前,先简单介绍BeanFactoryPostProcessor接口和整个invokeBeanFactoryPostProcessors方法的执行流程。
refresh
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing./*** 前戏,做容器刷新前的准备工作* 1、设置容器的启动时间* 2、设置活跃状态为true* 3、设置关闭状态为false* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中* 5、准备监听器和事件的集合对象,默认为空的集合*/prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 创建容器对象:DefaultListableBeanFactory// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// beanFactory的准备工作,对各种属性进行填充prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 调用各种beanFactory处理器invokeBeanFactoryPostProcessors(beanFactory);} }}

@FunctionalInterface
public interface BeanFactoryPostProcessor {/*** Modify the application context's internal bean factory after its standard* initialization. All bean definitions will have been loaded, but no beans* will have been instantiated yet. This allows for overriding or adding* properties even to eager-initializing beans.* @param beanFactory the bean factory used by the application context* @throws org.springframework.beans.BeansException in case of errors*/void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {/*** Modify the application context's internal bean definition registry after its* standard initialization. All regular bean definitions will have been loaded,* but no beans will have been instantiated yet. This allows for adding further* bean definitions before the next post-processing phase kicks in.* @param registry the bean definition registry used by the application context* @throws org.springframework.beans.BeansException in case of errors*/void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
BFPP和BDRPP
根据上面的流程图以及代码块可以看出BFPP和BDRPP的关系,其中BFPP类中只有一个postProcessBeanFactory()方法,而BDRPP中只有postProcessBeanDefinitionRegistry()方法,因为是继承的关系,所以所有实现BDRPP接口的类,也会有postProcessBeanFactory()方法。
而BFPP和BDRPP其中有一个很重要的区别就在于,它们两个方法接收的参数不同,其中BFPP接收BeanFactory参数,针对整个BeanFactory做操作,而BDRPP接收的参数是BeanDefinitionRegistry(可以理解是对Definition做一些正删改查的操作)。
BeanDefinitionRegistry
public interface BeanDefinitionRegistry extends AliasRegistry {/*** 注册BeanDefinition到注册表** Register a new bean definition with this registry.* Must support RootBeanDefinition and ChildBeanDefinition.* @param beanName the name of the bean instance to register* @param beanDefinition definition of the bean instance to register* @throws BeanDefinitionStoreException if the BeanDefinition is invalid* @throws BeanDefinitionOverrideException if there is already a BeanDefinition* for the specified bean name and we are not allowed to override it* @see GenericBeanDefinition* @see RootBeanDefinition* @see ChildBeanDefinition*/void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;/*** 移除注册表中beanName的BeanDefinition** Remove the BeanDefinition for the given name.* @param beanName the name of the bean instance to register* @throws NoSuchBeanDefinitionException if there is no such bean definition*/void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;/*** 获取注册表中beanName的BeanDefinition** Return the BeanDefinition for the given bean name.* @param beanName name of the bean to find a definition for* @return the BeanDefinition for the given name (never {@code null})* @throws NoSuchBeanDefinitionException if there is no such bean definition*/BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;/*** 检查此注册表是否包含具有给定名称的BeanDefinition** Check if this registry contains a bean definition with the given name.* @param beanName the name of the bean to look for* @return if this registry contains a bean definition with the given name*/boolean containsBeanDefinition(String beanName);/*** 返回此注册表中定义的所有bean的名称** Return the names of all beans defined in this registry.* @return the names of all beans defined in this registry,* or an empty array if none defined*/String[] getBeanDefinitionNames();/*** 返回注册表中定义的bean的数目** Return the number of beans defined in the registry.* @return the number of beans defined in the registry*/int getBeanDefinitionCount();/*** 确定给定bean名称是否已在该注册表中使用** Determine whether the given bean name is already in use within this registry,* i.e. whether there is a local bean or alias registered under this name.* @param beanName the name to check* @return whether the given bean name is already in use*/boolean isBeanNameInUse(String beanName);}
接口的作用和整体的执行流程已经介绍完成,下面看看invokeBeanFactoryPostProcessors方法的具体执行逻辑。
invokeBeanFactoryPostProcessors
主要是调用delegate中的同名invokeBeanFactoryPostProcessors方法,对BaenFactory中和自定义注册进来的BFPP的实现类进行处理。
其中getBeanFactoryPostProcessors()是如果类继承了AbstractApplicationContext后,可以有add方法自行注册BeanFactoryPostProcessor。处理时也会先处理这部分的BFPP。
invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {// 获取到当前应用程序上下文的beanFactoryPostProcessors变量的值,并且实例化调用执行所有已经注册的beanFactoryPostProcessor// 默认情况下,通过getBeanFactoryPostProcessors()来获取已经注册的BFPP,但是默认是空的PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantimeif (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}
AbstractApplicationContext
如果想要自己注册进来,要实现AbstractApplicationContext并调用addBeanFactoryPostProcessor方法将自定义BFPP实现类加进来,就可以get到。
public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {@Overridepublic void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {this.beanFactoryPostProcessors.add(postProcessor);}/*** Return the list of BeanFactoryPostProcessors that will get applied* to the internal BeanFactory.*/public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {return this.beanFactoryPostProcessors;}//删除其他代码
}
具体处理逻辑
如最开始图片中标注的处理流程一样,
- 处理过的BFPP都放入processedBeans集合,避免后续重复执行。
- 先遍历beanFactoryPostProcessors中BDRPP类型的,并直接调用postProcessBeanDefinitionRegistry进行逻辑处理。非BDRPP类型放入regularPostProcessors集合,后续统一处理。
- 找到BeanFactory中BDRPP类型,并根据PriorityOrdered,Order进行优先级排序,最后再执行没有优先级的。
- 因为继承了BDRPP的肯定也会有BFPP中的方法,所以还会统一处理执行BDRPP中的postProcessBeanFactory方法。
- 执行完BeanFactory中的BDRPP类型后,再查找BeanFactory中BFPP类型,同样按照PriorityOrdered,Order进行优先级排序。并执行postProcessBeanFactory方法。
class PostProcessorRegistrationDelegate {public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.//所有已经执行过BFPP的存储在processedBeans,防止重复执行Set<String> processedBeans = new HashSet<String>();//判断beanFactory是否属于BeanDefinitionRegistry类型,默认的beanFactory是DefaultListableBeanFactory,//实现了BeanDefinitionRegistry 所以为trueif (beanFactory instanceof BeanDefinitionRegistry) {//强制类型转换BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;//存放BFPP类型的集合List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();//存放BDRPP类型的集合List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =new LinkedList<BeanDefinitionRegistryPostProcessor>();//优先处理入参中的beanFactoryPostProcessors,遍历所有beanFactoryPostProcessors,//并将参数中的BFPP和BDRPP区分开for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {//如果是BDRPP类型if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryPostProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;//直接调用BDRPP中的postProcessBeanDefinitionRegistry具体方法进行处理registryPostProcessor.postProcessBeanDefinitionRegistry(registry);//放入registryPostProcessors集合中registryPostProcessors.add(registryPostProcessor);}else {//否则,只是普通的BeanFactoryPostProcessor,则放入regularPostProcessors集合regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.//根据type获取BeanFactory中所有类型为BDRPP的postProcessorNamesString[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.//将实现了BDRPP和priorityOrder接口的类放入该集合List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {//如果是PriorityOrdered类型的if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//放入priorityOrderedPostProcessors集合priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));//放入processedBeans集合,避免重复执行processedBeans.add(ppName);}}//按照优先级进行排序OrderComparator.sort(priorityOrderedPostProcessors);//添加到registryPostProcessors中registryPostProcessors.addAll(priorityOrderedPostProcessors);//遍历priorityOrderedPostProcessors集合,执行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.//再次获取BDRPP类型的所有postProcessorNamespostProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);//实现了Order接口的BeanDefinitionRegistryPostProcessor放入该集合List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {//如果是没执行过,并且实现了Order接口的if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {//放到Order集合中orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));//放入processedBeans集合,避免重复执行processedBeans.add(ppName);}}//按照优先级排序OrderComparator.sort(orderedPostProcessors);//放入registryPostProcessors集合registryPostProcessors.addAll(orderedPostProcessors);//遍历orderedPostProcessors集合,执行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;//找出所有实现了BDRPP接口的类postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {//跳过执行过BDRPP的类if (!processedBeans.contains(ppName)) {//根据name获取实例BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);//添加到registryPostProcessors集合中registryPostProcessors.add(pp);//添加到processedBeans集合中processedBeans.add(ppName);//直接执行BDRPPpp.postProcessBeanDefinitionRegistry(registry);reiterate = true;}}} // Now, invoke the postProcessBeanFactory callback of all processors handled so far.//遍历registryPostProcessors和regularPostProcessors中有所的bean,//执行BFPP接口postProcessBeanFactory方法invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}//如果beanFactory不属于BeanDefinitionRegistry,直接执行具体方法else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}//到这为止,入参的beanFactoryPostProcessors和BeanFactory中BDRPP类型的方法已经全部处理完成//后面开始都是操作BFPP类型//到这位置// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!//找到所有实现BeanFactoryPostProcessor的类String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.//依次声明priorityOrderedPostProcessors、orderedPostProcessorNames和nonOrderedPostProcessorNames分别用来存放对应//实现了priorityOrdered、ordered和没实现排序接口的类List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();List<String> orderedPostProcessorNames = new ArrayList<String>();List<String> nonOrderedPostProcessorNames = new ArrayList<String>();//遍历所有postProcessorNames,将没执行过的BFPP方法的类放入对应集合中。for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.//按照优先级进行排序,并执行具体的BFPP方法OrderComparator.sort(priorityOrderedPostProcessors);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}OrderComparator.sort(orderedPostProcessors);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);}
看完上面这段源码之后,不知道大家有没有这样的一个疑问,为什么重复代码较多?每次都要根据类型重新获取String[] postProcessorNames,第一次获取后,根据postProcessorNames按照PriorityOrdered和Order进行优先级排序、分组执行不行么?
是因为在执行BDRPP的方法postProcessBeanDefinitionRegistry时,有可能会有新增的额外的BDRPP的类,每次都重新获取,能避免BDRPP类执行的不完全。
相关文章:
Sping源码(七)— 后置处理器
简单回顾一下上一篇文章,是在BeanFacroty创建完之后,可以通过Editor和EditorRegistrar实现对类属性的自定义扩展,以及忽略要自动装配的Aware接口。 本篇帖子会顺着refresh()主流程方法接着向下执行。在讲invokeBeanFactoryPostProcessors方法…...
docker导出、导入镜像、提交
导出镜像到本地,然后可以通过压缩包的方式传输。 导出:docker image save 镜像名:版本号 > /home/quxiao/javatest.tgz 导入:docker image load -i /home/quxiao/javatest.tgz 删除镜像就得先删除容器,当你每运行一次镜像&…...
shell的变量
一、什么是变量 二、变量的命名 三、查看变量的值 env显示全局变量,刚刚定义的root_mess是局部变量 四、变量的定义 旧版本(7、8四个文件都加载)和新版本(9只加载两个etc)不一样,所以su - 现在要永久生效在…...
CentOS系统环境搭建(十三)——CentOS7安装nvm
centos系统环境搭建专栏🔗点击跳转 CentOS7.9安装nvm 文章目录 CentOS7.9安装nvm1.安装2.刷新系统环境3.查看所有node4.安装Node.js版本5.查看已安装版本号6.使用指定版本7.设置默认版本8.验证 在我们的日常开发中经常会遇到这种情况:手上有好几个项目&…...
uniapp评论列表插件获取
从评论列表,回复,点赞,删除,留言板 - DCloud 插件市场里导入,并使用。 代码样式优化及接入如下: <template><view class"hb-comment"><!-- 阅读数-start --><view v-if&q…...
3.redis数据结构之List
List-列表类型:L&R 列表类型:有序、可重复 Arraylist和linkedlist的区别 Arraylist是使用数组来存储数据,特点:查询快、增删慢 Linkedlist是使用双向链表存储数据,特点:增删快、查询慢,但是查询链表两端…...
安装使用MySQL8遇到的问题记录
1、root密码 启动运行后 /var/log/mysqld.log 存在默认密码 2023-08-21T15:58:17.469516Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.34) initializing of server in progress as process 61233 2023-08-21T15:58:17.478009Z 1 [System] [MY-013576] [I…...
Mysql、Oracle 中锁表问题解决办法
MySQL中锁表问题的解决方法: 1. 确定锁定表的原因: 首先,需要确定是什么原因导致了表的锁定。可能的原因包括长时间的事务、大量的并发查询、表维护操作等。 2. 查看锁定信息: 使用以下命令可以查看当前MySQL数据库中的锁定信…...
AUTOSAR规范与ECU软件开发(实践篇)5.1 ETAS ISOLAR-A工具简介
前言 如前所述, 开发者可以先在系统级设计工具ISOLAR-A中设计软件组件框架, 包括端口接口、 端口等, 即创建各软件组件arxml描述性文件; 再将这些软件组件描述性文件导入到行为建模工具, 如Matlab/Simulink中完成内部行为建模。 亦可以先在行为建模工具中完成逻辑建模, 再…...
shell脚本——expect脚本免交互
目录 一.Here Document 1.1.定义 1.2.多行重定向 二.expect实现免交互 2.1.基础免交互改密码 2.2.expect定义 2.3.expect基本命令 2.4.expect实现免交互ssh主机 一.Here Document 1.1.定义 使用I/O重定向的方式将命令列表提供给交互式程序,是标准输 入的一…...
ubuntu18.04安装远程控制软件ToDest方法,针对官网指令报错情况
有时我们在家办公,需要控制实验室的笔记本,因此好用的远程控制软件会让我们的工作事半功倍! 常用的远程控制软件有ToDesk,向日葵,以及TeamViewer,但是为感觉ToDesk更流畅一些,所以这里介绍一下…...
系统架构设计师之缓存技术:Redis持久化的两种方式-RDB和AOF
系统架构设计师之缓存技术:Redis持久化的两种方式-RDB和AOF...
以创新点亮前路,戴尔科技开辟数实融合新格局
编辑:阿冒 设计:沐由 2023年,对于戴尔科技而言是特殊的一年,这是戴尔科技进入中国市场第25个年头——“巧合”的是,这25年也是中国产业经济发展最快,人们工作与生活发生变化最大的四分之一个世纪。 2023年&…...
使用Pandas处理Excel文件
Excel工作表是非常本能和用户友好的,这使得它们非常适合操作大型数据集,即使是技术人员也不例外。如果您正在寻找学习使用Python在Excel文件中操作和自动化内容的地方,请不要再找了。你来对地方了。 在本文中,您将学习如何使用Pan…...
设计模式——接口隔离原则
文章目录 基本介绍应用实例应传统方法的问题和使用接口隔离原则改进 基本介绍 客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上先看一张图: 类 A 通过接口 Interface1 依赖类 B,类 C 通过接口 Interface1 依赖类 D&…...
黑客(网络安全)自学
想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客! 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全…...
《Go 语言第一课》课程学习笔记(三)
构建模式:Go 是怎么解决包依赖管理问题的? Go 项目的布局标准是什么? 首先,对于以生产可执行程序为目的的 Go 项目,它的典型项目结构分为五部分: 放在项目顶层的 Go Module 相关文件,包括 go.…...
PSP - 基于开源框架 OpenFold Multimer 蛋白质复合物的结构预测与BugFix
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132410296 AlphaFold2-Multimer 是一个基于 AlphaFold2 的神经网络模型,可以预测多链蛋白复合物的结构。该模型在训练和推理时都可以处…...
Java课题笔记~ MyBatis分页查询插件
1.添加依赖 <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version> </de…...
(嵌入式c语言)类型修饰符
类型修饰符 对内存资源存储位置的限定 auto 默认的类型修饰符 修饰的变量可读可写 register 因为你内部寄存器比较少,使用此类型修饰符,会告诉编译器尽量把此数据放到寄存器。 CPU内部寄存器是编号来定义,无地址编号,所以r…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
计算机系统结构复习-名词解释2
1.定向:在某条指令产生计算结果之前,其他指令并不真正立即需要该计算结果,如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方,那么就可以避免停顿。 2.多级存储层次:由若干个采用不同实现技术的存储…...
AWSLambda之设置时区
目标 希望Lambda运行的时区是东八区。 解决 只需要设置lambda的环境变量TZ为东八区时区即可,即Asia/Shanghai。 参考 使用 Lambda 环境变量...
python打卡day47
昨天代码中注意力热图的部分顺移至今天 知识点回顾: 热力图 作业:对比不同卷积层热图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import D…...
