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,这样在容器启动时就可用。
    • 注册自定义的BeanPostProcessor、Advisor等,用于增强或修改容器中其他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.tpcf.cn/news/826875.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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方向向…