SpringBoot中的扩展点

ApplicationContextInitializer的initialize方法。

时机 : 所有的配置文件都已经加载,spring容器还没被刷新之前 准备阶段 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); 

它允许开发人员在Spring应用上下文(ApplicationContext)被创建和刷新之前,对上下文进行自定义的初始化设置。通过实现ApplicationContextInitializer接口,您可以执行以下类型的自定义功能:

  1. 定制ApplicationContext配置

    • 添加或修改ApplicationContext的属性。
    • 设置环境变量(Environment)或系统属性。
    • 注册自定义的PropertySources,以便在上下文初始化时注入自定义的属性值。
  2. 注册额外的Bean Definition

    • 在Spring IoC容器初始化之前预先注册自定义的Bean,这样在容器启动时就可用。
    • 注册自定义的BeanPostProcessorAdvisor等,用于增强或修改容器中其他Bean的行为。
  3. 定制资源加载

    修改上下文的资源加载策略,例如添加自定义的ResourceLoader或修改其默认行为。
  4. 初始化第三方库或中间件

    初始化与Spring容器一起使用的第三方库或中间件,例如数据库连接池、缓存服务、消息队列客户端等。
  5. 初始化应用级基础设施

    设置应用启动时所需的基础设施,如初始化日志框架、加密服务、国际化设置等。
  6. 执行特定的初始化逻辑

    执行一次性的初始化动作,比如配置系统层面的设定、读取外部配置文件并注入到环境中等。

示例代码如下:

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.env.ConfigurableEnvironment;public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {// 获取环境对象ConfigurableEnvironment environment = applicationContext.getEnvironment();// 设置或修改环境属性environment.getPropertySources().addFirst(new MyCustomPropertySource());// 注册自定义的BeanapplicationContext.registerBean("customBean", CustomBean.class);// 执行其他初始化逻辑// ...}
}
BeanDefinitionRegistryPostProcessor

refresh()的 this.invokeBeanFactoryPostProcessors(beanFactory);此时此bean的定义信息 都已经加载完毕 但是还没到实例化以及初始化阶段。

主要用于在Spring IoC容器初始化过程中对Bean定义进行进一步的加工或扩展,可以拓展的功能包括但不限于:

  1. 添加自定义Bean定义

    在容器完成所有默认的Bean定义扫描和注册之后,但在任何Bean实例化之前,可以动态地向容器中注册新的Bean定义,这对于实现动态扩展Bean的集合非常有用。
  2. 修改现有的Bean定义

    改变Bean的属性,如修改构造函数参数、修改Bean的scope(作用域)、修改初始化方法或销毁方法等。
  3. 删除不必要的Bean定义

    根据运行时条件或配置,可以选择性地移除已经注册的Bean定义,避免某些Bean实例化和初始化。
  4. 调整Bean之间的依赖关系

    动态地更改Bean之间的依赖关系,例如添加额外的depends-on属性,确保Bean按期望的顺序初始化。
  5. 配置元数据处理

    处理基于注解的Bean定义,例如解析自定义注解并据此更新Bean定义的元数据。
  6. 处理第三方库或遗留系统的Bean定义

    当第三方库没有使用Spring的@Component注解,但又需要纳入Spring容器管理时,可以使用BeanDefinitionRegistryPostProcessor来注册这些类为Spring Bean。
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;@Configuration
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 注册新的Bean定义GenericBeanDefinition customBeanDef = new GenericBeanDefinition();customBeanDef.setBeanClass(CustomBean.class);registry.registerBeanDefinition("customBean", customBeanDef);// 修改已有Bean定义BeanDefinition existingBeanDef = registry.getBeanDefinition("someExistingBean");existingBeanDef.setAttribute("customAttribute", "newValue");// 删除Bean定义if (registry.containsBeanDefinition("toBeDeletedBean")) {registry.removeBeanDefinition("toBeDeletedBean");}}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 此方法也可以进行一些工厂级别的后处理,但主要用于处理BeanFactory而非BeanDefinitionRegistry}
}

我们老是讲BeanDefinition,那么它是啥呢?

BeanDefinition是IoC(Inversion of Control,控制反转)容器的基本组成单元,它描述了Spring容器中Bean的元信息。每个由Spring容器管理的Bean都有一个对应的BeanDefinition对象,它包含了Bean的所有必要配置信息,如:

  1. Bean 类型(Class):定义了Bean的具体实现类。
  2. 作用域(Scope):定义了Bean的生命周期模式,如singleton(单例)或prototype(原型)。
  3. 构造器参数和属性值:Bean依赖的其他Bean,或者是直接的属性值。
  4. 初始化方法和销毁方法:定义了Bean实例化后要调用的初始化方法和容器关闭前要调用的销毁方法。
  5. 是否懒加载:指示Bean是否应在首次请求时才创建实例。
  6. 自定义属性:其他用户自定义的属性信息。

bean是怎么变成beandefinition的呢?Spring容器在启动和初始化过程中,会将各种来源的Bean配置信息转换成BeanDefinition对象,主要包括以下几个步骤:

  1. XML配置文件

    当使用XML配置方式时,Spring容器读取XML配置文件,通过BeanDefinitionParserDelegate等组件解析XML标签,将标签内的配置信息转换成BeanDefinition对象。
  2. 注解驱动配置

    当使用注解如@Component@Service@Repository@Controller等进行配置时,Spring通过组件扫描(@ComponentScan)自动检测到带有这些注解的类,并使用ClassPathBeanDefinitionScanner或其他类似组件将类转换成对应的BeanDefinition
  3. Java配置类

    在Java配置类(如带有@Configuration注解的类)中,通过@Bean注解的方法声明的Bean,Spring会自动处理这些方法并将方法体中的逻辑转换成BeanDefinition。Spring Boot中ConfigurationClassPostProcessor会处理这些Java配置类。
  4. 手动注册

    在代码中手动创建GenericBeanDefinition等BeanDefinition子类实例,填充相关信息后,通过DefaultListableBeanFactory或其他BeanDefinitionRegistry接口的实现注册到Spring容器。
BeanFactoryPostProcessor

允许开发者在Bean实例化之前对Spring IoC容器中的Bean定义进行修改和扩展。通过实现BeanFactoryPostProcessor接口,您可以拓展以下功能:

  1. 修改Bean属性

    动态修改Bean定义中的属性值,例如修改构造器参数值、属性值、初始化方法、销毁方法等。
  2. 自定义Bean作用域

    更改Bean的作用域(Scope),如将Singleton Bean改为Prototype Bean,或者自定义作用域。
  3. 注入额外的依赖

    动态地向Bean定义中注入额外的依赖,而不必在代码中显式声明。
  4. 配置属性替换

    能够根据运行时环境或配置文件动态替换Bean定义中的占位符属性值。
  5. 实现Bean的动态代理

    可以在Bean实例化前为其生成代理类,添加额外的横切逻辑,如AOP(面向切面编程)的增强功能。
  6. 处理遗留系统的Bean定义

    对于一些不遵循Spring规范的遗留系统,可以通过BeanFactoryPostProcessor将遗留系统中的类注册为Spring Bean,并进行必要的配置。
  7. 整合第三方库配置

    在Bean实例化前,整合第三方库的相关配置,将其无缝融入Spring IoC容器的管理。

示例代码:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {BeanDefinition bd = beanFactory.getBeanDefinition(beanName);// 示例:修改某Bean定义的属性值if ("someBean".equals(beanName)) {bd.getPropertyValues().addPropertyValue("propertyName", "newPropertyValue");}}}
}

那么BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor看起来好像是,有啥区别呢?BeanDefinitionRegistryPostProcessor 它继承了 BeanFactoryPostProcessor 接口。

BeanFactoryPostProcessor:

  • 主要功能:允许开发人员在 Spring 容器完成所有标准 Bean 定义的读取之后但在任何 Bean 实例化之前修改这些 Bean 定义。
  • 改动范围:可以修改现有 Bean 定义的各种属性,包括但不限于构造函数参数、属性值、依赖关系等。
  • 应用场景:例如,可以用来替代配置文件中的占位符属性值,或者进行全局性的属性设置。

BeanDefinitionRegistryPostProcessor:

  • 扩展功能:除了具有 BeanFactoryPostProcessor 的能力之外,还能够注册新的 Bean 定义。
  • 特殊权限:它可以直接操作 BeanDefinitionRegistry,这意味着可以在初始化过程的更早阶段添加或删除 Bean 定义。
  • 应用场景:当需要动态添加、移除或修改整个 Bean 定义集合时特别有用,比如在扫描特定包下带有自定义注解的类并将其自动注册为 Spring Bean 的场景。

总结来说,两者的主要区别在于:

  • BeanFactoryPostProcessor 更专注于修改已有的 Bean 定义属性。
  • BeanDefinitionRegistryPostProcessor 不仅能修改,还能在 Spring 容器构建过程中增加新的 Bean 定义,提供了更高的定制化程度。

执行顺序方面,BeanDefinitionRegistryPostProcessor 先于 BeanFactoryPostProcessor 执行。这样设计的原因在于,确保在 Bean 定义的最终集合形成后,再给所有 Bean 定义提供一个统一修改的机会。最后,所有经过这些后置处理器处理过的 Bean 定义才会被用来创建实际的 Bean 实例。

BeanPostProcessor

它允许开发者在 Spring 容器创建 Bean 实例后,但在 Bean 初始化前后对其进行自定义处理。通过实现 BeanPostProcessor 接口,可以拓展以下功能:

  1. 字段注入或方法调用

    在 Bean 初始化之前或之后添加额外的属性注入,或者调用自定义方法。
  2. AOP 切面增强

    实现面向切面编程(AOP),在 Bean 创建后,对其进行代理,添加横切关注点,如事务管理、日志记录、权限控制等。
  3. 对象包装

    将 Bean 包装成代理对象,以实现在调用 Bean 方法时附加额外的逻辑。
  4. 懒加载优化

    实现自定义的懒加载策略,延迟某些 Bean 的初始化时间点。
  5. 属性修改

    在 Bean 初始化前后,修改 Bean 实例的属性值。
  6. 初始化前后自定义逻辑

    在 Bean 初始化前后执行自定义的初始化或清理逻辑。
  7. 自定义依赖注入

    根据自定义逻辑动态注入 Bean 的依赖,而非仅依赖于 Spring 的默认注入机制。

具体实现这两个方法:

  • Object postProcessBeforeInitialization(Object bean, String beanName): 在 Bean 初始化(调用 InitializingBean 接口的 afterPropertiesSet() 方法或 @PostConstruct 注解的方法)之前调用。

  • Object postProcessAfterInitialization(Object bean, String beanName): 在 Bean 初始化之后调用,但在 Bean 准备好被应用上下文使用之前调用。

如下例子将展示如何在 Spring 容器中创建 Bean 实例之后对其内容进行自定义操作。这里我们将创建一个简单的后处理器,它会打印 Bean 的名称和类名,并对具有特定注解的 Bean 进行额外处理。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.stream.Collectors;@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean '" + beanName + "' is being created. Bean class: " + bean.getClass().getName());// 检查Bean是否带有特定注解,如果有,则进行特殊处理if (bean.getClass().isAnnotationPresent(MySpecialAnnotation.class)) {// 假设MySpecialAnnotation注解存在并有一些自定义逻辑processSpecialBean(bean);}return bean; // 返回未经修改的原始Bean对象,也可以返回一个包装过的Bean}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean '" + beanName + "' has been initialized.");return bean; // 返回未经修改的原始Bean对象,同样可以返回一个包装过的Bean}private void processSpecialBean(Object bean) {// 假设这里的逻辑是对标注了MySpecialAnnotation的Bean的字段进行赋值或其它操作Class<?> clazz = bean.getClass();Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(MySpecialAnnotation.class)).forEach(field -> {try {field.setAccessible(true);// 这里进行自定义的字段赋值或其他操作// ...} catch (IllegalAccessException e) {throw new RuntimeException("Error processing annotated field in bean", e);}});}// 假设的自定义注解@interface MySpecialAnnotation {// 注解的属性...}
}
InitializingBean

允许我们在 Bean 实例化后和依赖注入完成后,被其他bean依赖或者执行前执行一些自定义的初始化逻辑。通过实现 InitializingBean 接口,可以拓展以下功能:

  1. 自定义初始化操作

    执行额外的数据校验、初始化状态设置、与其他Bean交互或建立内部依赖关系等操作。
  2. 执行一次性初始化任务

    在Bean准备就绪投入服务之前,执行必需的一次性初始化任务,如打开数据库连接、初始化缓存、设置定时任务等。
  3. 注入后处理

    当依赖注入完成后,可以基于注入的属性执行一些初始化逻辑。

具体执行顺序如下:

  1. Spring 容器创建 Bean 实例。
  2. 容器对 Bean 进行依赖注入(DI),也就是填充所有通过 Setter 方法、构造函数或其他注解标记的属性。
  3. 如果 Bean 实现了 InitializingBean 接口,Spring 容器接下来会调用 afterPropertiesSet() 方法。
  4. 如果 Bean 上使用了 @PostConstruct 注解的方法,这些方法将在 InitializingBean.afterPropertiesSet() 之后执行。
  5. 如果 Bean 在 XML 配置中或通过 @Configuration 类定义了一个 init-method,那么这个 init-method 方法也会在这之后执行。

下面是一个简单的 InitializingBean 接口实现的例子:

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;@Component
public class MyComponent implements InitializingBean {private String property1;private int property2;// 通过@Autowired注解或者其他方式注入属性public void setProperty1(String property1) {this.property1 = property1;}public void setProperty2(int property2) {this.property2 = property2;}@Overridepublic void afterPropertiesSet() throws Exception {// 在所有属性注入完成后,执行自定义的初始化逻辑System.out.println("MyComponent has been instantiated with property1=" + property1 + " and property2=" + property2);// 模拟一个初始化操作,比如初始化数据库连接// ...// 或者进行数据验证if (property1 == null || property1.isEmpty()) {throw new IllegalArgumentException("Property1 must not be empty!");}}
}
@PostConstruct , @PreDestroy

@PostConstruct

  • 该注解用于标记在一个无参的实例方法上,表示在依赖注入完成后,但在 Bean 正式投入使用(即任何业务方法被调用前)时执行的方法。
  • 这个注解的方法通常用于初始化 Bean 的内部状态,如数据库连接、初始化缓存、加载配置等。
  • 示例:
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;@Component
public class MyComponent {@PostConstructpublic void init() {System.out.println("Bean is being initialized...");// 执行初始化逻辑}// ...其他方法
}

@PreDestroy

  • 该注解用于标记在一个无参的实例方法上,表示在 Bean 生命周期结束时,即将从 Spring 容器中移除之前执行的方法。
  • 这个注解的方法通常用于资源清理,如关闭数据库连接、清除缓存、保存状态、发送关闭通知等。
  • 示例:
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;@Component
public class MyComponent {// ...其他方法@PreDestroypublic void cleanup() {System.out.println("Bean is about to be destroyed...");// 执行资源清理逻辑}
}

注意:在 Spring 中,@PostConstruct 和 @PreDestroy 注解的方法的执行顺序优先级高于 InitializingBean 和 DisposableBean 接口中的 afterPropertiesSet() 和 destroy() 方法,以及在 XML 配置中定义的 init-method 和 destroy-method。

BeanNameAware

BeanNameAware 是 Spring Framework 提供的一个接口,允许 Bean 实例了解自己在 Spring 容器中的 bean 名称。当一个类实现了 BeanNameAware 接口后,Spring 容器在实例化该 Bean 并注入其属性后,会调用 setBeanName() 方法,传递给 Bean 其在 Spring 配置文件中定义的 bean 名称。

示例:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;public class MyBean implements BeanNameAware {private String myBeanName;@Overridepublic void setBeanName(String name) {this.myBeanName = name;System.out.println("Bean Name is: " + name);}// ...其他方法
}

在上面的例子中,当 Spring 容器创建 MyBean 实例时,会自动调用 setBeanName() 方法,将当前 Bean 的名字传递给 myBeanName 字段。这个特性在一些需要知道自身 Bean 名称以进行特定逻辑处理的场景中会很有用。

InstantiationAwareBeanPostProcessor

它扩展了 BeanPostProcessor 接口,提供了在 Bean 实例化阶段进行介入和定制的能力。通过实现 InstantiationAwareBeanPostProcessor 接口,除非有特殊情况,否则Spring容器中大部分由Spring管理创建的Bean在实例化过程中都会受到InstantiationAwareBeanPostProcessor的监测和处理,可以实现以下功能:

  1. 自定义实例化过程

    通过重写 postProcessBeforeInstantiation(Class<?> beanClass, String beanName) 方法,在 Spring 创建 Bean 实例之前有机会自定义实例化过程,甚至可以返回一个自定义的 Bean 实例,从而替代 Spring 默认的实例化过程。
  2. 修改初始化后的 Bean 实例

    同样作为 BeanPostProcessor 的一部分,可以重写 postProcessBeforeInitialization(Object bean, String beanName) 和 postProcessAfterInitialization(Object bean, String beanName) 方法,在 Bean 初始化前后进行自定义处理。
  3. 决定是否提前暴露早期引用

    通过实现 getEarlyBeanReference(Object bean, String beanName) 方法,可以在 Bean 初始化之前决定是否提前暴露该 Bean 的早期引用给其他 Bean 使用。
  4. AOP(面向切面编程)支持

    在某些情况下,例如在实现 AOP 代理时,需要在 Bean 实例化阶段就能创建代理对象,而不是等待常规的 Bean 初始化阶段。InstantiationAwareBeanPostProcessor 为此类场景提供了支持。

示例:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;public class CustomInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if (YourCustomCondition.check(beanClass)) {return new YourCustomBeanImplementation();}return null; // 返回null表示仍然使用Spring默认的实例化方式}// ...其他BeanPostProcessor方法的实现
}

InstantiationAwareBeanPostProcessor 相对于 BeanPostProcessor 提供了更早的介入时机,允许在 Bean 实例化阶段就进行自定义处理。通过实现 InstantiationAwareBeanPostProcessor,可以实现诸如自定义实例化过程、提前修改属性值等高级定制需求。

它们在作用时机上有微妙的区别:

  1. BeanPostProcessor:

    • BeanPostProcessor 接口提供了在 Spring 容器创建 Bean 实例并完成依赖注入之后,但在调用初始化方法(如 @PostConstruct 注解的方法或者 InitializingBean 接口的 afterPropertiesSet() 方法)之前和之后执行自定义逻辑的机会。
    • 有两个关键方法:
      • postProcessBeforeInitialization(Object bean, String beanName):在 Bean 初始化前调用。
      • postProcessAfterInitialization(Object bean, String beanName):在 Bean 初始化后调用。
  2. InstantiationAwareBeanPostProcessor:

    • InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 的一个子接口,它在 Bean 实例化阶段提供了更多的介入点。
    • 在 Bean 实例化前后,除了拥有 BeanPostProcessor 的全部功能外,还提供了如下方法:
      • postProcessBeforeInstantiation(Class<?> beanClass, String beanName):在 Spring 实际创建 Bean 实例之前调用。如果这个方法返回非空对象,那么 Spring 将不再使用默认的实例化策略,而是使用返回的对象作为 Bean 实例。
      • postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName):在实例化后、初始化前修改 Bean 属性值的阶段调用,允许在注入属性值之后,初始化方法调用之前修改属性值。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年汉字小达人活动还有5个月开赛:来做18道历年选择题备考吧

现在距离2024年第11届汉字小达人比赛还有五个多月的时间&#xff0c;如何利用这段时间有条不紊地备考呢&#xff1f;我的建议是两手准备&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0c;重点是字、词、成语、古诗。阅读理解不需要。②把历年真题刷刷熟&#x…

数电期末复习(一)数制和码制

数制和码制 1.1 概述1.2 几种常用的数制1.2.1 十进制&#xff08;Decimal&#xff09;1.2.2 二进制&#xff08;Binary&#xff09;1.2.3 二-十进制之间的转换1.2.4 十六进制和八进制1.2.5 任意进制之间的转换 1.3 二进制代码1.3.1 二-十进制码(BCD Binary Coded Decimal)1.3.2…

分享一些常用的小程序免费源码

小程序支付源码 小程序注册、登录源码 自定义图片上传组件源码 java实现小程序和网页在线聊天、即时通讯 微信小程序自定义底部tabBar实例 生成微信小程序二维码 图片上传源码 下载地址&#xff1a; 看源社区 www.see-source.com

cross-env 与 vue-cli-service 的区别

cross-env 与 vue-cli-service 的区别 一、cross-env用法多环境基本内容配置 &#xff08;非必要&#xff0c;全局变量的一种方式&#xff09; 二、vue-cli-service&#xff1a;用法 一、cross-env 它是为了解决跨平台环境变量设置的问题而开发的。 cross-env是一个用于设置跨…

2023年网络安全行业:机遇与挑战并存

2023年全球网络安全人才概况 根据ISC2的《2023年全球网络安全人才调查报告》&#xff0c;全球的网络安全专业人才数量达到了550万&#xff0c;同比增长了8.7%。然而&#xff0c;这一年也见证了网络安全人才短缺达到了历史新高&#xff0c;缺口数量接近400万。尤其是亚太地区&am…

luckysheet的使用——15.复制有合并单元格的某一行的格式到一个指定空白行

在插入空白行的时候&#xff0c;如果是在画好的表格下插入&#xff0c;api提供的插入空白行会插入没有任何格式的一行&#xff0c;无法匹配合并了单元格的表格格式&#xff0c;需要手动编写api 1.找到api.js&#xff0c;在src/global中,新增一个方法 /*** 复制有合并单元格的…

ARM_day6:实现字符串数据收发函数的封装

程序代码&#xff1a; uart4.h&#xff1a; #ifndef __UART4_H__ #define __UART4_H__ #include"stm32mp1xx_gpio.h" #include"stm32mp1xx_rcc.h" #include"stm32mp1xx_uart.h" void uart4_config(); void putchar(char dat); char getchar();…

【电机参数】直流无刷电机机械转速、ud、uq、us、输出功率、相反电动势幅值、载波周期、转矩常数

【电机参数】直流无刷电机机械转速、ud、uq、us、输出功率、相反电动势幅值、载波周期、转矩常数 前言 【电机控制】直流有刷电机、无刷电机汇总——持续更新 使用工具&#xff1a; 1.示波器&#xff1a;PICO2205A 2.电桥LCR&#xff1a;VICIOR4090A 3.电流钳&#xff1a;汉泰…

接口测试相关

接口测试&#xff0c;接口 接口是数据交互的入口和出口 接口是一套规范和标准 统一设计标准 前后端相对独立 扩展型灵活 接口文档。 接口测试 接口测试环境&#xff0c;运行程序&#xff0c;自己搭建环境 接口测试插件 谷歌postman 火狐 restclient java测试工具为j…

Linux系统的磁盘管理与文件系统

目录 一、磁盘结构 1.物理结构 2.数据结构 二、MBR与磁盘分区表示 1.MBR 2.磁盘分区表示 分区的优点 分区的缺点 三、文件系统类型 1.文件系统的组成 XFS SWAP EXT4 2.磁盘管理工具 四、Linux系统添加新硬盘的步骤 一、磁盘结构 1.物理结构 所有存储的设备都在…

【面试经典 150 | 数组】最后一个单词的长度

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;遍历 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行回顾…

Android 性能优化之黑科技开道(二)

3. 其它可以黑科技优化的方向 3.1 核心线程绑定大核 3.1.1 定义 核心线程绑定大核的思路也很容易理解&#xff0c;现在的 CPU 都是多核的&#xff0c;大核的频率比小核要高不少&#xff0c;如果我们的核心线程固定运行在大核上&#xff0c;那么应用性能自然会有所提升。 核…

【Qt】Qt界面构建与对象管理:从 “Hello World“ 到内存释放

文章目录 1. 通过图形化界面创建控件2. 通过纯代码方式创建控件3. 对象树管理与内存管理小结&#xff1a; 在软件开发中&#xff0c;构建用户界面是至关重要的一步。Qt作为一个跨平台的C框架&#xff0c;提供了强大的界面构建工具和对象树管理机制&#xff0c;使得界面开发变得…

Leetcode 3123. Find Edges in Shortest Paths

Leetcode 3123. Find Edges in Shortest Paths 1. 解题思路2. 代码实现 题目链接&#xff1a;3123. Find Edges in Shortest Paths 1. 解题思路 这一题思路上的话就是一个最短路径的求解问题&#xff0c;我们使用一个堆排即可对其进行实现。 不过&#xff0c;做题的时候挺犹…

单页面首屏优化,打包后大小减少64M,加载速度快了13.6秒

需求背景 从第三方采购的vue2 ElementUI实现的云管平台&#xff0c;乙方说2011年左右就开始有这个项目了&#xff08;那时候有Vue了吗&#xff0c;思考.jpg&#xff09;。十几年的项目&#xff0c;我何德何能可以担此责任。里面的代码经过多人多年迭代可以用惨不忍睹来形容&a…

Qt做关于界面

在上位机系统中&#xff0c;经常需要显示当前软件版本&#xff0c;当前fpga版本&#xff0c;那么咱就做一个help的菜单的关于界面 解决的问题&#xff1a; 解决显示版本信息的UI Axure界面图&#xff1a; 如何实现&#xff1a; 实现文件的存储&#xff1a;QSetting来存储版…

初始jQuery

目录 前言: 1.jQuery介绍 2.引入jQuery 3.工厂函数$() 3.1使用CSS选择器获取元素&#xff1a; 3.2将原生JavaScript对象转换为jQuery对象&#xff1a; 3.3从jQuery对象转换到原生JavaScript对象&#xff1a; 4. jQuery获取元素 4.1基础选择器 4.1.1标签选择器&#xf…

【入门深入篇】本章包括条件查询、排序查询、分页查询、分页实战举例(小程序之云函数开发入门到使用发布上线实操)

1. 条件查询 假设我们需要查询年龄大于等于 18 岁的用户记录: // 云函数入口函数 exports.main = async (event, context) => {const {minAge } = event; // 从事件中获取用户提供的最小年龄try {<

玩转Virtual Box虚拟机

玩转Virtual Box虚拟机 虚拟化技术和虚拟机简介 什么是虚拟化技术&#xff1f; 虚拟化技术是将计算机的各种硬件资源予以抽象、转换、分割、组合的一种计算机技术。虚拟化技术打破了实体结构间不可切割的障碍&#xff0c;从而使用户可以按照需求重新组合硬件资源&#xff0c…

NX二次开发UF_MTX(矩阵运算)常用函数

目录 一、概述 二、函数的介绍 2.1 UF_MTX3_copy&#xff08;复制原来矩阵&#xff09; 2.2 UF_MTX3_determinant&#xff08;计算矩阵的行列式&#xff09; 2.3 UF_MTX3_identity&#xff08;单位矩阵&#xff09; 2.4 UF_MTX3_initialize&#xff08;可以根据X、Y方向向…