自定义Spring Boot Starter(官网文档解读)
摘要
本文将详细介绍自定义 Spring Boot Starter 的完整过程。要构建自定义 Starter,首先需掌握 Spring Boot 中 @Auto-configuration
以及相关注解的工作原理,同时了解 Spring Boot 提供的一系列条件注解。在具备这些知识基础后,再按照特定步骤完成自定义 Starter 的开发,最后对其进行测试。接下来,让我们基于官网文档,深入学习具体内容。
@AutoConfiguration
@AutoConfiguration
是 Spring Boot 3.0 引入的一个注解,用于标记自动配置类。自动配置类的主要作用是根据类路径中的依赖、配置属性等条件,自动为应用程序配置所需的 Bean。它替代了早期版本中的 @Configuration
和 @EnableAutoConfiguration
组合,让自动配置类的定义更加清晰和简洁。
代码示例
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;@AutoConfiguration
public class MyAutoConfiguration {@Beanpublic MyService myService() {return new MyService();}
}
在这个示例中,MyAutoConfiguration
类被标记为自动配置类,其中定义了一个 MyService
的 Bean。当 Spring Boot 应用启动时,会自动扫描并加载这个自动配置类,创建 MyService
的实例。
Spring Boot 自动配置类的配置
加载
-
我们需要在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 配置文件中,加入我们的自动配置类,每个配置类占一行,从而让Spring Boot 加载自动配置类。
-
可以使用
#
字符在该文件中添加注释。 -
若自动配置类不是顶级类,其类名应使用
$
分隔其与包含类,如com.example.Outer$NestedAutoConfiguration
。 -
自动配置类必须通过在
imports
文件中列出类名来加载。要确保它们定义在特定的包空间中,且永远不会成为组件扫描的目标。此外,自动配置类不应使用组件扫描来查找其他组件,而应使用特定的@Import
注解。
顺序设置
-
@AutoConfiguration
注解属性:若配置需要按特定顺序应用,可使用@AutoConfiguration
注解的before
、beforeName
、after
和afterName
属性,或使用专门的@AutoConfigureBefore
和@AutoConfigureAfter
注解。例如,若提供特定的 Web 配置,可能需要在WebMvcAutoConfiguration
之后应用该配置类。 -
@AutoConfigureOrder
注解:若要对彼此无直接关联的某些自动配置类进行排序,可使用@AutoConfigureOrder
注解。该注解与常规的@Order
注解语义相同,但专门用于自动配置类。 -
与标准的
@Configuration
类一样,自动配置类的应用顺序仅影响其定义 Bean 的顺序,而后续创建这些 Bean 的顺序不受影响,创建顺序由每个 Bean 的依赖关系和任何@DependsOn
关系决定。 -
带顺序的自动配置代码示例
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;// 第一个自动配置类,创建 ServiceOne
@AutoConfiguration
public class ServiceOneAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic ServiceOne serviceOne() {return new ServiceOne();}
}// 第二个自动配置类,使用 @AutoConfiguration 的 after 属性,在 ServiceOneAutoConfiguration 之后配置
@AutoConfiguration(after = ServiceOneAutoConfiguration.class)
public class ServiceTwoAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic ServiceTwo serviceTwo() {return new ServiceTwo();}
}// 第三个自动配置类,使用 @AutoConfigureOrder 注解进行排序
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.core.Ordered;@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@AutoConfiguration
public class ServiceThreeAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic ServiceThree serviceThree() {return new ServiceThree();}
}
弃用与替换
-
在开发过程中,有时需要对自动配置类进行弃用并提供替代方案,例如更改自动配置类所在的包名。
-
由于自动配置类可能会在
before/after
排序和排除项中被引用,因此需要额外创建一个文件来告知 Spring Boot 如何处理替换操作。具体做法是创建一个名为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.replacements
的文件,在其中指明旧类和新类之间的映射关系。替换示例:
person.wend.springbootlearnexample.config.MyAutoConfiguration=person.wend.springbootlearnexample.config.auto.MyAutoConfiguration
-
同时,
AutoConfiguration.imports
文件也需要更新,使其仅引用替换后的新类,以确保 Spring Boot 在进行自动配置时能正确加载最新的配置类。
条件注解
在进行自动配置时,SpringBoot 包含六类@Conditional注解。可通过对 @Configuration
类或单个 @Bean
方法添加这些注解,在自定义代码中复用。这些注解包括:
-
类条件注解(Class Conditions)
-
Bean 条件注解(Bean Conditions)
-
属性条件注解(Property Conditions)
-
资源条件注解(Resource Conditions)
-
Web 应用条件注解(Web Application Conditions)
-
SpEL 表达式条件注解(SpEL Expression Conditions)
类条件注解
-
@ConditionalOnClass:@ConditionalOnClass
注解用于指定只有当类路径中存在指定的类时,被注解的配置类或@Bean
方法才会生效。这在需要根据特定依赖是否存在来决定是否进行配置时非常有用。例如,当项目引入了某个库时,才加载与之相关的配置。 -
@ConditionalOnMissingClass:@ConditionalOnMissingClass
注解与@ConditionalOnClass
注解相反,它用于指定只有当类路径中不存在指定的类时,被注解的配置类或@Bean
方法才会生效。这在需要避免某些配置在特定类存在时生效的场景中非常有用。 -
示例代码
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;// 模拟某个库中的类
class SomeLibraryClass {}@Configuration
@ConditionalOnClass(SomeLibraryClass.class)
public class MyConfig {@Beanpublic MyService myService() {return new MyService();}
}class MyService {}
-
@ConditionalOnClass
和@ConditionalOnMissingClass
注解通过检查类路径中特定类的存在与否,为 Spring Boot 应用的配置提供了灵活的条件加载机制,有助于根据不同的依赖环境进行动态配置。
Bean 条件注解
-
@ConditionalOnBean
和@ConditionalOnMissingBean
注解可根据特定 Bean 是否存在来决定是否包含某个 Bean。 -
使用
value
属性按类型指定 Bean -
使用
name
属性按名称指定 Bean -
search
属性可用于限制在搜索 Bean 时应考虑的ApplicationContext
层次结构 -
示例代码
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;@AutoConfiguration
public class MyAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic SomeService someService() {return new SomeService();}
}
-
在上述示例中,如果
ApplicationContext
中尚未包含SomeService
类型的 Bean,那么someService
Bean 将会被创建。
属性条件注解
-
@ConditionalOnProperty
注解可根据 Spring 环境属性来决定是否包含配置。使用prefix
和name
属性指定要检查的属性。默认情况下,任何存在且不等于false
的属性都会匹配。还可以使用havingValue
和matchIfMissing
属性进行更高级的检查。若name
属性中指定了多个名称,则所有属性都必须通过测试条件才会匹配。 -
代码示例
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class PropertyConfig {@Bean@ConditionalOnProperty(prefix = "myapp", name = "enabled", havingValue = "true")public MyService myService() {return new MyService();}
}class MyService {}
-
在
application.properties
中配置myapp.enabled=true
时,myService
Bean 才会被创建。
资源条件注解
-
@ConditionalOnResource
注解只有在特定资源存在时才会包含配置。可以使用 Spring 常用约定指定资源,如file:/home/user/test.dat
。
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ResourceConfig {@Bean@ConditionalOnResource(resources = "classpath:test.properties")public ResourceService resourceService() {return new ResourceService();}
}class ResourceService {}
-
当类路径下存在
test.properties
文件时,resourceService
Bean 才会被创建。
Web 应用条件注解
-
@ConditionalOnWebApplication
和@ConditionalOnNotWebApplication
注解根据应用是否为 Web 应用来决定是否包含配置。基于 Servlet 的 Web 应用是指使用Spring WebApplicationContext
、定义了会话作用域或具有ConfigurableWebEnvironment
的应用;响应式 Web 应用是指使用ReactiveWebApplicationContext
或具有ConfigurableReactiveWebEnvironment
的应用。 -
@ConditionalOnWarDeployment
和@ConditionalOnNotWarDeployment
注解根据应用是否为部署到 Servlet 容器的传统 WAR 应用来决定是否包含配置。对于使用嵌入式 Web 服务器运行的应用,此条件不匹配。
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class WebAppConfig {@Bean@ConditionalOnWebApplicationpublic WebService webService() {return new WebService();}
}class WebService {}
-
当应用是 Web 应用时,
webService
Bean 才会被创建。
SpEL 表达式条件注解
-
@ConditionalOnExpression
注解根据 SpEL 表达式的结果来决定是否包含配置。但在表达式中引用 Bean 会导致该 Bean 在上下文刷新处理的早期初始化,从而使该 Bean 无法进行后处理(如配置属性绑定),其状态可能不完整。
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class SpELConfig {@Bean@ConditionalOnExpression("#{systemProperties['java.version'].startsWith('17')}")public Java17Service java17Service() {return new Java17Service();}
}class Java17Service {}
-
当 Java 版本以
17
开头时,java17Service
Bean 才会被创建。
测试自动配置
自动配置受用户配置(如@Bean
定义和Environment
自定义)、条件评估(特定库是否存在)等因素影响。每个测试都应创建一个定义良好的ApplicationContext。
ApplicationContextRunner
是实现此目标的好方法。
ApplicationContextRunner
-
ApplicationContextRunner通常被定义为测试类的一个字段,用于收集基本的通用配置。以下示例确保
MyServiceAutoConfiguration
始终调用:
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration.class));
-
若有多个自动配置,无需排序,调用顺序与运行应用时相同。
-
每个测试可用运行器表示特定用例,如调用用户配置(
UserConfiguration
)并检查自动配置是否正确退出,@Test
方法中使用withUserConfiguration
和run
回调上下文结合AssertJ
进行断言。
@Testvoid defaultServiceBacksOff() {this.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {assertThat(context).hasSingleBean(MyService.class);assertThat(context).getBean("myCustomService").isSameAs(context.getBean(MyService.class));});}@Configuration(proxyBeanMethods = false)static class UserConfiguration {@BeanMyService myCustomService() {return new MyService("mine");}}
-
可轻松自定义
Environment
,如withPropertyValues
方法设置属性值并进行断言。
@Testvoid serviceNameCanBeConfigured() {this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {assertThat(context).hasSingleBean(MyService.class);assertThat(context.getBean(MyService.class).getName()).isEqualTo("test123");});}
-
运行器可用于显示
ConditionEvaluationReport
,通过ConditionEvaluationReportLoggingListener
设置日志级别打印报告。
class MyConditionEvaluationReportingTests {@Testvoid autoConfigTest() {new ApplicationContextRunner().withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO)).run((context) -> {// Test something...});}}
模拟 Web 环境
若测试仅在 servlet 或反应式 Web 应用程序上下文中运行的自动配置,可分别使用WebApplicationContextRunner
或ReactiveWebApplicationContextRunner
。
-
WebApplicationContextRunner代码示例:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.test.StepVerifier;public class ReactiveAutoConfigurationTest {private final ReactiveWebApplicationContextRunner reactiveWebContextRunner = new ReactiveWebApplicationContextRunner().withConfiguration(AutoConfigurations.of(MyReactiveAutoConfiguration.class));@Testvoid testReactiveAutoConfiguration() {reactiveWebContextRunner.run((ApplicationContext context) -> {// 断言上下文中存在 MyReactiveService 的 BeanassertThat(context).hasSingleBean(MyReactiveService.class);MyReactiveService myReactiveService = context.getBean(MyReactiveService.class);// 调用反应式服务类的方法并使用 StepVerifier 进行断言StepVerifier.create(myReactiveService.sayHello()).expectNext("Hello from MyReactiveService in Reactive context").verifyComplete();});}
}
-
ReactiveWebApplicationContextRunner代码示例:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.test.StepVerifier;public class ReactiveAutoConfigurationTest {private final ReactiveWebApplicationContextRunner reactiveWebContextRunner = new ReactiveWebApplicationContextRunner().withConfiguration(AutoConfigurations.of(MyReactiveAutoConfiguration.class));@Testvoid testReactiveAutoConfiguration() {reactiveWebContextRunner.run((ApplicationContext context) -> {// 断言上下文中存在 MyReactiveService 的 BeanassertThat(context).hasSingleBean(MyReactiveService.class);MyReactiveService myReactiveService = context.getBean(MyReactiveService.class);// 调用反应式服务类的方法并使用 StepVerifier 进行断言StepVerifier.create(myReactiveService.sayHello()).expectNext("Hello from MyReactiveService in Reactive context").verifyComplete();});}
}
覆盖类路径
使用FilteredClassLoader
可测试运行时特定类和 / 或包不存在时的情况,如通过withClassLoader
方法设置类加载器并断言自动配置是否正确禁用。
@Testvoid serviceIsIgnoredIfLibraryIsNotPresent() {this.contextRunner.withClassLoader(new FilteredClassLoader(MyService.class)).run((context) -> assertThat(context).doesNotHaveBean("myService"));}
创建自定义Starter的步骤
典型的 Spring Boot Starter 包含用于自动配置和定制特定技术(以 “acme” 为例)基础设施的代码。为实现易于扩展,会在专用命名空间中向环境暴露多个配置键,并且提供单一的 “starter” 依赖,方便用户快速上手。
-
acme:“acme” 是一个占位符,用来代表任意一种技术、框架、库或者服务。“acme” 代表开发者想要自动配置和定制其基础设施的目标技术。例如,这个技术可能是 Redis、MongoDB、RabbitMQ 等,“acme” 在这里可以理解成一个泛指的、可以被替换为具体技术的抽象概念。
自定义 Starter 的组成
-
自动配置模块(autoconfigure module):包含针对 “acme” 的自动配置代码。
-
Starter 模块:依赖于自动配置模块,同时包含 “acme” 以及其他常用的额外依赖。简而言之,添加该 Starter 应能提供使用相应库所需的一切。
模块分离的考量
-
分离的优势:将自动配置和 Starter 分成两个模块并非必要,但当 “acme” 存在多种变体、选项或可选功能时,进行分离是更好的选择。这样可以明确表明某些功能是可选的,并且能够定制一个对这些可选依赖有特定选择的 Starter。同时,其他人可以仅依赖自动配置模块,按照自己的需求定制 Starter。
-
合并的情况:如果自动配置相对简单,且没有可选功能,将两个模块合并到 Starter 中也是可行的。
Starter 的命名规则
-
官方Starter:Spring-Boot 官方的Starter 都统一以 spring-boot-starter-* 格式命名,其中
*
是特定类型的应用程序。此命名结构旨在帮助您在需要查找启动器时使用。许多 IDE 中的 Maven 集成允许您按名称搜索依赖项。例如,安装了适当的 Eclipse 或 Spring Tools 插件后,您可以按ctrl-space
POM 编辑器并键入“spring-boot-starter”以获取完整列表。 -
三方库或自建Starter:第三方启动器不应以
spring-boot
开头,因为它是为官方 Spring Boot 工件保留的。通常正确的写法是,名为thirdpartyproject
的第三方启动器项目,通常其定义的Starter应命名为thirdpartyproject-spring-boot-starter
。
配置键
命名空间使用规范
如果自定义的 Starter 提供配置键,要使用独特的命名空间,切勿将配置键置于 Spring Boot 已使用的命名空间(如 server
、management
、spring
等)中。因为后续 Spring Boot 可能会修改这些命名空间,从而导致模块出现问题。一般来说,应使用自己拥有的命名空间作为配置键的前缀,例如 acme
。
-
配置示例
acme.my-project.person.first-name=John acme.my-project.person.last-name=Smith acme.my-project.person.version=1.0.0
配置键文档化
-
使用
@ConfigurationProperties
注解类:为保证配置键有文档记录,需为@ConfigurationProperties
注解类中的每个属性添加字段 Javadoc。
@ConfigurationProperties("acme")
public class AcmeProperties {/*** Whether to check the location of acme resources.*/private boolean checkLocation = true;/*** Timeout for establishing a connection to the acme server.*/private Duration loginTimeout = Duration.ofSeconds(3);// getters/setters ...public boolean isCheckLocation() {return this.checkLocation;}public void setCheckLocation(boolean checkLocation) {this.checkLocation = checkLocation;}public Duration getLoginTimeout() {return this.loginTimeout;}public void setLoginTimeout(Duration loginTimeout) {this.loginTimeout = loginTimeout;}}
-
配置示例展示了
AcmeProperties
类,包含checkLocation
和loginTimeout
等属性,并为每个属性添加了说明性的 Javadoc。 -
记录类的处理方式:若使用
@ConfigurationProperties
注解记录类(record class),需通过类级别的 Javadoc 标签@param
来提供记录组件的描述,因为记录类没有显式的实例字段来放置常规的字段级 Javadoc。
描述规范
为确保描述的一致性,需遵循以下规则:
-
描述开头不要使用 “The” 或 “A”。
-
对于布尔类型,描述以 “Whether” 或 “Enable” 开头。
-
对于基于集合的类型,描述以 “Comma - separated list” 开头。
-
使用
Duration
类型而非long
类型,若默认单位不是毫秒,需描述默认单位,如 “If a duration suffix is not specified, seconds will be used”。 -
除非默认值需在运行时确定,否则描述中不要提供默认值。
元数据生成
要触发元数据生成,以便 IDE 能为配置键提供辅助功能。可以查看生成的元数据文件 META - INF/spring-configuration-metadata.json
,确保配置键有恰当的文档记录。在兼容的 IDE 中使用自定义的 Starter 也是验证元数据质量的好方法。
“autoconfigure” 模块
“autoconfigure” 模块包含了使用某个库所需的一切必要内容。它可能包含配置键定义(例如使用 @ConfigurationProperties
注解),以及可用于进一步自定义组件初始化方式的回调接口。
-
依赖设置:应该将对该库的依赖标记为可选的。这样做可以更轻松地将 “autoconfigure” 模块包含到项目中。因为当依赖被标记为可选时,库本身不会被提供,默认情况下 Spring Boot 会跳过对相关自动配置的加载。
-
在 Maven 项目中,通过在
pom.xml
文件里的<dependency>
标签中添加<optional>true</optional>
来将依赖标记为可选。
-
<dependencies><!-- 其他依赖 --><dependency><groupId>com.example</groupId><artifactId>your-library</artifactId><version>1.0.0</version><optional>true</optional></dependency>
</dependencies>
-
自动配置元数据文件:Spring Boot 使用注解处理器将自动配置的条件收集到一个元数据文件(
META - INF/spring-autoconfigure-metadata.properties
)中。如果该文件存在,Spring Boot 会使用它来提前过滤掉不匹配的自动配置,从而提高应用的启动时间。 -
Maven 构建配置:在使用 Maven 进行项目构建时,需要将编译器插件(版本 3.12.0 或更高)配置为把
spring-boot-autoconfigure-processor
添加到注解处理器路径中。
<project><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessorPaths><path><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure-processor</artifactId></path></annotationProcessorPaths></configuration></plugin></plugins></build>
</project>
Starter 模块的本质与作用
Starter 本质上是一个空的 JAR 文件,其主要作用是提供使用相关库所需的必要依赖,可被视为关于启动使用该库所需依赖的一种推荐组合。
-
spring-boot-starter 示例:
-
Starter 依赖添加原则:
-
避免主观臆断:当你开发一个 Spring Boot Starter 时,不要想当然地认为引入这个 Starter 的项目是什么样的情况。比如说,不能觉得所有用你这个 Starter 的项目都有某些特定的配置或者已经引入了某些其他库。如果这个 Starter 所自动配置的库在正常使用的时候还需要其他的 Starter 配合,那你就得把这些额外需要的 Starter 清楚地告诉别人。
-
合理选择默认依赖:要是你要自动配置的库有很多可以选择的依赖,这时候选一套合适的默认依赖就挺难办的。你得保证 Starter 里只放那些在大家平时用这个库的时候一定会用到的依赖,那些可有可无的依赖就别放进去了。
-
-
Starter 依赖要求
-
Starter 模块必须直接或间接引用 Spring Boot 核心 Starter(
spring-boot- starter
)。若项目仅使用自定义 Starter 创建,由于核心 Starter 的存在,Spring Boot 的核心功能仍能正常使用。如果自定义 Starter 依赖于其他已包含核心 Starter 的 Starter,则无需再额外添加核心 Starter 依赖。
-
参考文献
Creating Your Own Auto-configuration :: Spring Boot
相关文章:
自定义Spring Boot Starter(官网文档解读)
摘要 本文将详细介绍自定义 Spring Boot Starter 的完整过程。要构建自定义 Starter,首先需掌握 Spring Boot 中 Auto-configuration 以及相关注解的工作原理,同时了解 Spring Boot 提供的一系列条件注解。在具备这些知识基础后,再按照特定步…...
开发 picgo-plugin-huawei 插件,解决华为云社区外链限制问题
开发 picgo-plugin-huawei 插件,解决华为云社区外链限制问题 在技术博客平台中,外链的使用常常受到限制,这给我们的写作和内容展示带来了一定的不便。为了应对这一问题,我开发了 picgo-plugin-huawei 插件,它能够有效…...
最长回文子串
标题 1.1 问题描述 给你一个字符串 s,找到 s 中最长的回文子串。 1.2 示例 1.2.1 示例1 输入:s “babad” 输出:“bab” 解释:“aba” 同样是符合题意的答案。 1.2.2 示例2 输入:s “cbbd” 输出:“bb…...
JavaSE学习笔记26-集合(Collection)
集合 Java 中的集合(Collection)是 Java 标准库中非常重要的一部分,用于存储和操作一组对象。Java 集合框架(Java Collections Framework)提供了一套丰富的接口和类,用于处理各种数据结构,如列…...
开源神器KRR:用数据驱动K8s资源优化
引言:云原生时代的资源管理之痛 在Kubernetes集群中,过度配置导致资源浪费与配置不足引发稳定性风险的矛盾始终存在。CNCF调研显示,企业平均有35%的云资源处于闲置状态。本文将揭秘开源神器KRR(Kubernetes Resource Recommender),通过数据驱动方式实现精准资源配置,实测…...
微信小程序:多菜单栏设计效果
一、实现效果 二、代码 wxml 编辑前端界面,步骤 菜单逻辑: 逐步取出数组中的项,首先取出顶部菜单项,然后选中后取出选中的底部数据(左侧菜单+右侧内容),然后点击左侧菜单取出选中的左侧菜单对应的右侧内容 ①这里我的数据是全部封装到一个数组对象的,首先我的循环…...
网络安全-js安全知识点与XSS常用payloads
简介 JavaScript 是一种轻量级的编程语言,定义了HTML的行为。它与Java的关系类似周杰和周杰伦的关系(即没有关系)。 用法 HTML 中的脚本必须位于 <script> 与 </script> 标签之间。 脚本可被放置在 HTML 页面的 <body>…...
无人机实战系列(二)本地摄像头 + Depth-Anything V2
这篇文章介绍了如何在本地运行 Depth-Anything V2,因为我使用的无人机是Tello,其本身仅提供了一个单目视觉相机,在众多单目视觉转 Depth 的方案中我选择了 Depth-Anything V2,这个库的强大在于其基于深度学习模型将单目视觉以较低…...
[杂学笔记]工厂模式、多态、内存空间区域划分、cp指令破坏软连接问题、UDP如何实现可靠传输、滑动窗口的原理、进程与线程、线程之间的通信
目录 1.工厂模式 2.多态 3.内存空间区域划分 4.cp指令破坏软连接问题 5.UDP实现可靠传输 6.滑动窗口的原理 7.进程与线程 8.线程之间的通信 1.工厂模式 工厂模式是一种创建对象的设计模式。它提供了一种创建对象的方式,将对象的创建和使用分离,通…...
【IEEE出版,往届会后3个月EI检索 | 西华大学主办 | 中英文期刊、SCI期刊推荐】第四届能源、电力与电气国际学术会议(ICEPET 2025)
第四届能源、电力与电气国际学术会议(ICEPET 2025)由西华大学主办,西华大学能源与动力工程学院、西华大学电气与电子信息学院、西华大学航空航天学院、流体及动力机械教育部重点实验室、流体机械及工程四川省重点实验室、四川省水电能源动力装…...
【AI+智造】DeepSeek价值重构:当采购与物控遇上数字化转型的化学反应
作者:Odoo技术开发/资深信息化负责人 日期:2025年2月24日 引言:从事企业信息化工作16年,我见证过无数企业从手工台账到ERP系统的跨越。但真正让采购和物控部门脱胎换骨的,是融合了Deepseek AI的Odoo数字化解决方案——…...
1.适配器模式
概述 适配器模式:将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。 适配器模式在业务场景中非常有用,尤其是在系统集成、接口兼容性处理以及代码复用等场景。以下是一个实际的业务场景示例: 业务场景…...
选择排序(详解)c++
选择排序(Selection Sort)是⼀种特别直观的排序算法。每次找出未排序序列中最⼩的元素,然后放进有序序列的后⾯ 算法思想: 每次找出未排序序列中最小的元素,然后放进有序序列的后面 在数组中完成选择排序 落实到代码的时候就两步:找最小交换 …...
[java基础-JVM篇]1_JVM自动内存管理
JVM内存管理涉及但不限于类加载、对象分配、垃圾回收等,本篇主要记录运行时数据区域与对象相关内容。 内容主要来源《深入理解Java虚拟机:JVM高级特性与最佳实践》与官方文档,理解与表述错漏之处恳请各位大佬指正。 目录 运行时数据区域 栈 栈…...
python-leetcode 42.验证二叉搜索树
题目: 给定二叉树的根节点root,判断是否是一个有效二叉搜索树 有效二叉搜索树: 1.节点的左子树只包含小于当前节点的树 2.节点的右子树只包含大于当前节点的树 3.所有左子树和右子树自身必须也是二叉搜索树 方法一:递归 如果该二叉树的…...
Unity Shader 学习13:屏幕后处理 - 使用高斯模糊的Bloom辉光效果
目录 一、基本的后处理流程 - 以将画面转化为灰度图为例 1. C#调用shader 2. Shader实现效果 二、Bloom辉光效果 1. 主要变量 2. Shader效果 (1)提取较亮区域 - pass1 (2)高斯模糊 - pass2&3 (3ÿ…...
【Bluedroid】AVRCP 连接源码分析(三)
接着上一篇【Bluedroid】AVRCP 连接源码分析(一)-CSDN博客,继续AVRCP连接的源码分析。 AVRC_OpenBrowse /packages/modules/Bluetooth/system/stack/avrc/avrc_api.cc /******************************************************************************** Function …...
图数据库Neo4j面试内容整理-约束(Constraint)
约束(Constraint) 是数据库中用于确保数据一致性和完整性的一种机制。它限制了数据的某些方面,确保特定条件得到满足。在 Neo4j 中,约束主要用于确保图数据的一致性,防止插入不符合规则的数据。约束通常与索引一起使用,但它们的功能和目的有所不同。 1. Neo4j 中的约束类…...
QUdpSocket的readyRead信号只触发一次
问题 QUdpSocket的readyRead信号只触发一次。 原因 on_readyRead槽函数里必须读出现有数据后,才能触发新的事件。 解决办法 在on_readyRead槽函数里取出数据。 void MainWindow::on_readyRead() {qDebug() << "on_readyRead in";while (m_udp…...
使用Windbg调试目标进程排查C++软件异常的一般步骤与要点分享
目录 1、概述 2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序 2.1、将Windbg附加到已经启动起来的目标进程上 2.2、用Windbg启动目标程序 2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去 3、分析实例说明 …...
深度解析:大模型在多显卡服务器下的通信机制与分布式训练——以DeepSeek、Ollama和vLLM为例
一、引言:大模型与多显卡的必然结合 随着大模型参数规模突破千亿级(如GPT-4、DeepSeek),单显卡的显存容量与算力已无法满足需求。多显卡并行计算成为训练与推理的核心技术,其核心挑战在于高效通信与负载均衡。本文以国…...
爬虫基础入门之爬取豆瓣电影Top250-Re正则的使用
网址:豆瓣电影 Top 250 本案例所需要的模块 requests (用于发送HTTP请求)re (用于字符串匹配和操作) 确定需要爬取的数据 : 电影的名称电影的年份电影的评分电影评论人数 一. 发送请求 模拟浏览器向服务器发送请求 准备工作 -分析页面: F12 or 右击点击检查 查看…...
【R安装包报错】在conda环境下用R语言命令安装R包报错
报错如下: gnu/include/c/11.2.0/ctime:80:11: error: ‘timespec_get’ has not been declared in ‘::’ 80 | using ::timespec_get; | ^~~~~~~~~~~~ 修改 报错原因:如果使用的是conda安装的g,可能与系统库不兼容。尝试 切换到系统默认编…...
基于STM32单片机设计的宠物喂食监控系统
1. 项目开发背景 随着宠物数量的增加,尤其是人们对宠物的养护需求日益增多,传统的人工喂养和管理方式难以满足现代养宠生活的需求。人们越来越希望通过智能化手段提高宠物养护的质量和效率,特别是对于宠物喂食、饮水、温湿度控制等方面的智能…...
Minio分布式多节点多驱动器集群部署
Minio分布式多节点多驱动器集群部署 Minio分布式多节点多驱动器集群部署节点规划先决条件开放防火墙端口设置主机名更新域名映射文件时间同步存储要求内存要求 增加虚拟机磁盘(所有机器都要执行)部署分布式 MinIO测试上传与预览测试高可用MinIO 配置限制模拟单节点磁盘故障模拟…...
Web前端开发——HTML基础
本系列博客声明,根据本人所学书籍和网上的一些资料共同磨合,写下web前端系列的博客 HTML基础 一、HTML基本概述[^1]二、HTML大体认知1.HTML基本结构2.HTML 语法格式 三、THML常用标记[^2]1.文本标记(1)标题(2…...
《计算机视觉》——图像拼接
图像拼接 图像拼接是将多幅有重叠区域的图像合并成一幅全景或更大视角图像的技术,以下为你详细介绍: 原理:图像拼接的核心原理是基于图像之间的特征匹配。首先,从每幅图像中提取独特的特征点,如角点、边缘点等&#x…...
zookeeper从入门到精通
一、入门基础 1.1 什么是 ZooKeeper ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,后成为 Apache 的顶级项目。它为分布式应用提供了高效、可靠的协调服务,例如统一命名服务、配置管理、分布式锁、集群管理等。ZooKeeper 的数据模型类…...
2.2 添加注释
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 注释是为了方便理解代码含义而添加的简短的解释性说明。在编译时,编辑器不会将注释加入最终生成的文件中,不…...
具有快慢思考的语言调节机器人操作
24年1月来自华东师范大学、美的集团和上海大学的论文“Language-Conditioned Robotic Manipulation with Fast and Slow Thinking”。 语言调节机器人操作,旨在将自然语言指令转化为可执行动作,从简单的“拾取和放置”到需要意图识别和视觉推理的任务。…...
美颜相机1.0
项目开发步骤 1 界面开发 美颜相机界面构成: 标题 尺寸 关闭方式 位置 可视化 2 创建主函数调用界面方法 3 添加两个面板 一个是按钮面板一个是图片面板 用JPanel 4 添加按钮到按钮面吧【注意:此时要用初始化按钮面板的方法initBtnPanel 并且将按钮添…...
Css3重点知识讲解
选择器 优先级: id 选择器 > 类选择器 > 标签选择器 类选择器: .myClass {color: blue; }id 选择器(全局唯一): #myId {color: green; }标签选择器: p {color: red; }层次选择器: /…...
[Web 安全] Web 安全攻防 - 学习手册
关联专栏:[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01:Web 安全攻防 —— 信息收集篇 Web 信息收集 — 手动收集域名信息 Web 信息收集 — 手动收集 IP 信息 Web 信息收集 — 端口服务信息收集 Web 信息收集 — 自动化信息收集 — ShuiZe 水泽 We…...
nextjs的记录一些小东西
1. 格式化时间:使用date-fns库 npm install date-fns 在组建中创建date.js import { parseISO, format } from date-fnsexport default function Date({ dateString }) {const date parseISO(dateString)return <time dateTime{dateString}>{format(date,…...
故障诊断 | PID搜索算法优化CatBoost故障诊断(MatlabPython)
目录 效果一览文章概述故障诊断 | PID搜索算法优化CatBoost故障诊断(Matlab&Python)PID搜索算法优化CatBoost故障诊断PID搜索算法优化CatBoost故障诊断一、引言1.1、研究背景与意义1.2、研究现状1.3、研究目的与内容二、CatBoost算法概述2.1、CatBoost算法原理2.2、CatBo…...
探索关键领域的AI工具:机器学习、深度学习、计算机视觉与自然语言处理
引言 在人工智能(AI)迅猛发展的今天,机器学习(ML)、深度学习(DL)、计算机视觉(CV)和自然语言处理(NLP)已经成为解决复杂问题的关键技术。无论是自动驾驶车辆的视觉识别,还是智能助手的对话理解,这些技术都在改变着世界。本文将介绍在各个领域…...
使用 DeepSeek 生成流程图、甘特图与思维导图:结合 Typora 和 XMind 的高效工作流
在现代工作与学习中,可视化工具如流程图、甘特图和思维导图能够极大地提升信息整理与表达的效率。本文将详细介绍如何使用 DeepSeek 生成 Mermaid 文本,结合 Typora 快速生成流程图和甘特图,并通过 Markdown 格式生成思维导图,最终…...
11、集合框架
一、简介 Java集合框架位于java.util包中 Collection是Set和List的父类,Collections是工具类,提供了对集合进行排序、遍历等多种算法的实现。 ArrayList: 有序(放进去顺序和拿出来顺序一致),可重复 HashSet: 无序(放进去顺序和拿出来顺序不…...
从入门到精通Rust:资源库整理
今天给大家分享一些优质的Rust语言学习资源,适合不同水平的学习者。前三个官方资源是我Rust语言的启蒙老师,非常平易近人。 官方资源 The Rust Programming Language (The Book) 链接: https://doc.rust-lang.org/book/ 简介: 官方权威指南,…...
Spring Boot 项目启动命令大全:参数详解与高阶用法
Spring Boot 项目启动命令大全:参数详解与高阶用法 一、基础启动命令 默认启动命令 java -jar xxx.jar适用场景:开发环境快速启动,使用默认配置(端口 8080,内存由 JVM 自动分配)。 指定 JVM 内存参数 java…...
c++day4
作业 #include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory>using namespace std; class S{ private:int a;int b; public:S(i…...
应对LLM应用中的AI幻觉,如何通过Token对数概率预测LLM的可靠性
应对LLM应用中的AI幻觉 如何通过Token对数概率预测LLM的可靠性 内容: 1. 相关机器学习(ML)概念回顾(精准度/召回率,LLM直觉) 2. 使用序列对数概率度量作为LLM信心 3. 通过案例研究结果过滤低质量LLM输出…...
Openwrt路由器操作系统
一、什么是 OpenWrt? OpenWrt 是一个基于 Linux 的开源操作系统,主要设计用于嵌入式设备,尤其是路由器。与其说是传统的路由器固件,不如说它是一个路由器操作系统。 传统的路由器固件通常由路由器厂商开发,功能相对固…...
基于SpringBoot的“流浪动物救助系统”的设计与实现(源码+数据库+文档+PPT)
基于SpringBoot的“流浪动物救助系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 局部E-R图 系统首页界面 系统…...
Ansible 学习笔记
这里写自定义目录标题 基本架构文件结构安装查看版本 Ansible 配置相关文件主机清单写法 基本架构 Ansible 是基于Python实现的,默认使用22端口, 文件结构 安装 查看用什么语言写的用一下命令 查看版本 Ansible 配置相关文件 主机清单写法...
(六)趣学设计模式 之 代理模式!
目录 一、啥是代理模式?二、为什么要用代理模式?三、代理模式的实现方式1. 静态代理2. JDK动态代理3. CGLIB动态代理 四、三种代理的对比五、代理模式的优缺点六、代理模式的应用场景七、总结 🌟我的其他文章也讲解的比较有趣😁&a…...
【CSS】HTML元素布局基础总结
HTML默认布局和元素显示 CSS 元素显示 { HTML 默认布局: 流式布局 { 从左到右,从上到下 随页面宽度变化动态排列元素 文档流:整个 H T M L 文档的流式布局 HTML 元素分为 { 块级元素 :默认占满一行 行内元素 :在行内最…...
【JavaScript】什么是JavaScript?以及常见的概念
作为 JavaScript 初学者,想要更好地理解这门语言,需要从核心概念、实践练习和项目实战三个方面入手。下面是详细的学习路线和方法,帮助你系统性地掌握 JavaScript。 一、理解 JavaScript 的核心概念 JavaScript 是一门动态、弱类型的编程语言…...
为什么要将PDF转换为CSV?CSV是Excel吗?
在企业和数据管理的日常工作中,PDF文件和CSV文件承担着各自的任务。PDF通常用于传输和展示静态的文档,而CSV因其简洁、易操作的特性,广泛应用于数据存储和交换。如果需要从PDF中提取、分析或处理数据,转换为CSV格式可能是一个高效…...
P1038 [NOIP 2003 提高组] 神经网络
题目描述 在兰兰的模型中,神经网络就是一张有向图,图中的节点称为神经元,而且两个神经元之间至多有一条边相连,下图是一个神经元的例子: 神经元(编号为 i) 图中,X1∼X3 是信息…...