Spring 类型安全的配置属性

使用 @Value("${property}") 注解来注入配置属性有时会很麻烦,特别是当你要处理多个属性或你的数据是分层的。 Spring Boot提供了一种处理属性的替代方法,让强类型的Bean管理和验证你的应用程序的配置。

另请参见@Value 和类型安全配置属性之间的区别。

一、 JavaBean 属性绑定

如下面的例子所示,可以绑定一个声明了标准JavaBean属性的bean。

Java

Kotlin

@ConfigurationProperties("my.service")
public class MyProperties {private boolean enabled;private InetAddress remoteAddress;private final Security security = new Security();// getters / setters...public static class Security {private String username;private String password;private List<String> roles = new ArrayList<>(Collections.singleton("USER"));// getters / setters...}}

前面的POJO定义了以下属性。

  • my.service.enabled,默认值为`false`。
  • my.service.remote-address,其类型可由`String`强制提供。
  • my.service.security.username,有一个嵌套的 security 对象,其名称由该属性的名称决定。 特别是,那里完全没有使用类型,可以是 SecurityProperties。
  • my.service.security.password.
  • my.service.security.role,有一个 String 的集合,默认为 USER。

映射到Spring Boot中可用的 @ConfigurationProperties 类的属性,通过properties文件、YAML文件、环境变量和其他机制进行配置,这些属性是公共API,但类本身的 getters/setters 并不意味着可以直接使用(一句话,Spring也是通过getter/setter这些public方法进行设置值的,你别用)。

这样的设计依赖于一个默认的无参构造函数,getter和setter通常是必须的,因为绑定是通过标准的Java Beans property descriptor(Java内省)实现的,就像在Spring MVC中一样。 在以下情况下,可以省略setter。

  • Map, 只要它们被初始化,就需要一个getter,但不一定需要一个setter,因为它们可以被绑定器突变。
  • Collection和array 可以通过索引(通常用YAML)或使用单个逗号分隔的值(属性)来访问。 在后一种情况下,一个setter是必须的。 我们建议总是为这类类型添加一个setter。 如果你初始化一个集合,确保它不是不可变的(如前面的例子)。
  • 如果嵌套的POJO属性被初始化(就像前面例子中的 Security 字段),就不需要setter。 如果你想让绑定器通过使用它的默认构造函数来即时创建实例,你需要一个setter。

有些人使用Project Lombok来自动添加getter和setter。 请确保Lombok不会为这样的类型生成任何特定的构造函数,因为它被容器自动用来实例化对象。

最后,只考虑标准的Java Bean属性,不支持对静态属性的绑定。

二、 构造函数绑定

上一节的例子可以用不可变的方式重写,如下例所示。

Java

@ConfigurationProperties("my.service")
public class MyProperties {// fields...public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {this.enabled = enabled;this.remoteAddress = remoteAddress;this.security = security;}// getters...public static class Security {// fields...public Security(String username, String password, @DefaultValue("USER") List<String> roles) {this.username = username;this.password = password;this.roles = roles;}// getters...}}

在这种设置中,唯一的“带参数构造函数”的存在意味着应该使用该构造函数进行绑定。 这意味着绑定器会找到一个带有你希望绑定的参数的构造函数。 如果你的类有多个构造函数,可以使用 @ConstructorBinding 注解来指定使用哪个构造函数进行构造函数绑定。 如果要为一个只有一个“带参数构造函数”的类选择不绑定构造函数,该构造函数必须用 @Autowired 来注解。 构造函数绑定可以与 Record 一起使用。 除非你的记录有多个构造函数,否则没有必要使用 @ConstructorBinding。

构造函数绑定类的嵌套成员(如上面例子中的 Security)也将通过其构造函数被绑定。

默认值可以在构造函数参数和Record组件上使用 @DefaultValue 来指定。 转换服务将被应用于将注解的 String 值强制转换为缺失属性的目标类型。

参考前面的例子,如果没有属性绑定到 Security , MyProperties 实例将包含一个 security 类型的 null 值。 为了使它包含一个非 null 的 Security 实例,即使没有属性与之绑定(当使用Kotlin时,这将要求 Security 的 username 和 password 参数被声明为 nullable,因为它们没有默认值),使用一个空的 @DefaultValue 注解。

Java

Kotlin

public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {this.enabled = enabled;this.remoteAddress = remoteAddress;this.security = security;
}

要使用构造函数绑定,该类必须使用 @EnableConfigurationProperties 或配置属性扫描来启用。 你不能对通过常规Spring机制创建的Bean使用构造函数绑定(例如 @Component Bean,通过使用 @Bean 方法创建的Bean或通过使用 @Import 加载的Bean)。

要在原生镜像中使用构造函数绑定,必须用 -parameters 参数编译该类。如果你使用 Spring Boot 的 Gradle 插件或使用 Maven 和 spring-boot-starter-parent,这将自动配置。

不建议将 java.util.Optional 与 @ConfigurationProperties 一起使用,因为它主要是作为一个返回类型使用。 因此,它并不适合配置属性注入。 为了与其他类型的属性保持一致,如果你确实声明了一个 Optional 属性,但它没有值,null 而不是一个空的 Optional 将被绑定。

三、 启用 @ConfigurationProperties 类

Spring Boot提供了绑定 @ConfigurationProperties 类型并将其注册为Bean的基础设施。 你可以在逐个类的基础上启用配置属性,或者启用配置属性扫描,其工作方式与组件扫描类似。

有时,用 @ConfigurationProperties 注解的类可能不适合扫描,例如,如果你正在开发你自己的自动配置或者你想有条件地启用它们。 在这些情况下,使用 @EnableConfigurationProperties 注解指定要处理的类型列表, 它可以注解在任何 @Configuration 类上,如下面的例子所示。

Java

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {}

Java

@ConfigurationProperties("some.properties")
public class SomeProperties {}

要使用配置属性扫描,请向你的application添加 @ConfigurationPropertiesScan 注解。 通常,它被添加到用 @SpringBootApplication 注解的main类中,但它也可以被添加到任何 @Configuration 类上。 默认情况下,扫描会从注解所在的包开始,你如果想自定义扫描其他包,可以参考如下。

Java

@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {}

当 @ConfigurationProperties Bean使用配置属性扫描或通过 @EnableConfigurationProperties 注册时,该Bean有一个常规名称:<prefix>-<fqn>,其中 <prefix> 是 @ConfigurationProperties 注解中指定的环境键前缀, <fqn> 是Bean的完全限定名称。 如果注解没有提供任何前缀,则只使用Bean的完全限定名称。

假设它在 com.example.app 包中,上面的 SomeProperties 例子的 bean 名称是 some.properties-com.example.app.SomeProperties。

我们建议 @ConfigurationProperties 只处理 environment,特别是不从上下文注入其他Bean。 对于边角案例(特殊情况),可以使用 setter 注入或框架提供的任何 *Aware 接口(如 EnvironmentAware ,如果你需要访问 Environment)。 如果你仍然想使用构造器注入其他Bean,配置属性Bean必须用 @Component 来注解,并使用基于JavaBean的属性绑定。

四、 使用 @ConfigurationProperties 类

这种配置方式与 SpringApplication 外部YAML配置配合得特别好,如以下例子所示。

my:service:remote-address: 192.168.1.1security:username: "admin"roles:- "USER"- "ADMIN"

要使用 @ConfigurationProperties Bean,你可以用与其他Bean相同的方式注入它们,如下例所示。

Java

@Service
public class MyService {private final MyProperties properties;public MyService(MyProperties properties) {this.properties = properties;}public void openConnection() {Server server = new Server(this.properties.getRemoteAddress());server.start();// ...}// ...}

使用 @ConfigurationProperties 还可以让你生成元数据文件,这些文件可以被IDE用来配置属性的“自动补全”功能。 详情见附录。

五、第三方配置

除了使用 @ConfigurationProperties 来注解一个类之外,你还可以在公共的 @Bean 方法上使用它。 当你想把属性绑定到你控制之外的第三方组件时,这样做特别有用。

要从 Environment 属性中配置一个Bean,请在其Bean注册中添加 @ConfigurationProperties ,如下例所示。

Java

@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {@Bean@ConfigurationProperties(prefix = "another")public AnotherComponent anotherComponent() {return new AnotherComponent();}}

任何用 another 前缀定义的JavaBean属性都会被映射到 AnotherComponent Bean上,其方式类似于前面的 SomeProperties 例子。

六、 宽松的绑定

Spring Boot在将 Environment 属性绑定到 @ConfigurationProperties bean时使用了一些宽松的规则,因此 Environment 属性名称和bean属性名称之间不需要完全匹配。 这很有用,常见的例子包括破折号分隔的属性名称(例如, context-path 绑定到 contextPath ),和大写的属性名称(例如,PORT 绑定到 port )。

演示一个例子,考虑以下 @ConfigurationProperties 类。

Java

@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {private String firstName;public String getFirstName() {return this.firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}}

对以上的代码来说,以下的属性名称都可以使用。

Table 3. relaxed binding

Property

Note

my.main-project.person.first-name

Kebab 风格(短横线隔开),建议在 .properties 和 YAML 文件中使用。

my.main-project.person.firstName

标准的驼峰语法。

my.main-project.person.first_name

下划线,这是一种用于 .properties 和 YAML 文件的替代格式。

MY_MAINPROJECT_PERSON_FIRSTNAME

大写格式,在使用系统环境变量时建议使用大写格式。

注解的 prefix 值 必须 是kebab风格(小写并以 - 分隔,如 my.main-project.person )。

Table 4. 每种属性源的宽松绑定规则

属性源

简单的

列表

Properties 文件

驼峰, kebab , 下划线

使用 [ ] 或逗号分隔值的标准列表语法

YAML 文件

驼峰, kebab , 下划线

标准YAML列表语法或逗号分隔的值

环境变量

大写,下划线为分隔符(见 从环境变量绑定).

Numeric values surrounded by underscores (see 从环境变量绑定)

系统属性(System properties)

驼峰, kebab , 下划线

使用 [ ] 或逗号分隔值的标准列表语法

我们建议,在可能的情况下,属性应以小写的kebab格式存储,例如 my.person.first-name=Rod 。 

绑定Map

当绑定到 Map 属性时,你可能需要使用一个特殊的括号符号,以便保留原始的 key 值。 如果key没有被 [ ] 包裹,任何非字母数字、- 或 . 的字符将被删除。

例如,考虑将以下属性绑定到一个 Map<String,String>。

Properties

Yaml

my.map.[/key1]=value1
my.map.[/key2]=value2
my.map./key3=value3

对于YAML文件,括号需要用引号包裹,以使key被正确解析。

上面的属性将绑定到一个 Map ,/key1,/key2 和 key3 作为map的key。 斜线已经从 key3 中删除,因为它没有被方括号包裹。

当绑定到标量值时,带有 . 的键不需要用 [] 包裹。 标量值包括枚举和所有 java.lang 包中的类型,除了 Object 。 将 a.b=c 绑定到 Map<String, String> 将保留键中的 . ,并返回一个带有 {"a.b"="c"} Entry的Map。 对于任何其他类型,如果你的 key 包含 . ,你需要使用括号符号。 例如,将 a.b=c 绑定到 Map<String, Object> 将返回一个带有 {"a"={"b"="c"} entry的Map,而 [a.b]=c 将返回一个带有 {"a.b"="c"} entry 的Map。

从环境变量绑定

例如,Linux shell变量只能包含字母(a 到 z 或 A 到 Z )、数字( 0 到 9 )或下划线字符( _ )。 按照惯例,Unix shell变量的名称也将采用大写字母。

Spring Boot宽松的绑定规则被设计为尽可能地与这些命名限制兼容。

要将规范形式的属性名称转换为环境变量名称,你可以遵循这些规则。

  • 用下划线(_)替换点(.)。
  • 删除任何破折号(-)。
  • 转换为大写字母。

例如,配置属性 spring.main.log-startup-info 将是一个名为 SPRING_MAIN_LOGSTARTUPINFO 的环境变量。

环境变量也可以在绑定到对象列表(List)时使用。 要绑定到一个 List,在变量名称中,元素编号(索引)应该用下划线包裹。

例如,配置属性 my.service[0].other 将使用一个名为 MY_SERVICE_0_OTHER 的环境变量。

七、 合并复杂的类型

当List被配置在多个地方时,覆盖的作用是替换整个list。

例如,假设一个 MyPojo 对象的 name 和 description 属性默认为 null。 下面的例子从 MyProperties 中暴露了一个 MyPojo 对象的列表。

Java

@ConfigurationProperties("my")
public class MyProperties {private final List<MyPojo> list = new ArrayList<>();public List<MyPojo> getList() {return this.list;}}

考虑以下配置。

Properties

Yaml

my.list[0].name=my name
my.list[0].description=my description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name

如果 dev 配置文件未被激活,MyProperties.list 包含一个 MyPojo 条目,如之前定义的那样。 然而,如果 dev 配置文件被激活,list 仍然只包含一个条目(name 为 my another name,description为 null)。 这种配置不会在列表中添加第二个 MyPojo 实例,也不会合并项目。

当一个 List 在多个配置文件中被指定时,将使用具有最高优先级的那个(并且只有那个)。 考虑下面的例子。

Properties

Yaml

my.list[0].name=my name
my.list[0].description=my description
my.list[1].name=another name
my.list[1].description=another description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name

在前面的例子中,如果 dev 配置文件是激活的,MyProperties.list 包含 一个 MyPojo 条目(name 是 my another name,description是 null)。 对于YAML,逗号分隔的列表和YAML列表都可以用来完全覆盖列表的内容。

对于 Map 属性,你可以用从多个来源获取的属性值进行绑定。 然而,对于多个来源中的同一属性,使用具有最高优先级的那个。 下面的例子从 MyProperties 暴露了一个 Map<String, MyPojo>。

Java

Kotlin

@ConfigurationProperties("my")
public class MyProperties {private final Map<String, MyPojo> map = new LinkedHashMap<>();public Map<String, MyPojo> getMap() {return this.map;}}

考虑以下配置。

Properties

Yaml

my.map.key1.name=my name 1
my.map.key1.description=my description 1
#---
spring.config.activate.on-profile=dev
my.map.key1.name=dev name 1
my.map.key2.name=dev name 2
my.map.key2.description=dev description 2

如果 dev 配置文件没有激活,MyProperties.map 包含一个key为 key1 的条目(name为 my name 1 ,description为 my description 1 )。 然而,如果 dev 配置文件被激活,map 包含两个条目,key为 key1 (name为 dev name 1,description为 my description 1 )和 key2(name为 dev name 2,description为 dev description 2)。

前面的合并规则适用于所有属性源的属性,而不仅仅是文件。

八、属性(Properties)转换

当Spring Boot与 @ConfigurationProperties Bean绑定时,它试图将外部application properties强制改为正确的类型。 如果你需要自定义类型转换,你可以提供一个 ConversionService bean(Bean的名称为 conversionService )或自定义属性编辑器(通过 CustomEditorConfigurer bean)或自定义 Converters Bean(使用 @ConfigurationPropertiesBinding 注解)。

由于这个Bean是在应用程序生命周期的早期被请求的,请确保限制你的 ConversionService 所使用的依赖关系。 通常情况下,你所需要的任何依赖关系在创建时可能没有完全初始化。 如果你的自定义 ConversionService 不需要配置keys coercion,你可能想重命名它,并且只依赖用 @ConfigurationPropertiesBinding 限定的自定义转换器。

转换为 Duration

Spring Boot对表达持续时间有专门的支持。 如果你公开了一个 java.time.Duration 属性,application properties中的以下格式就可用。

  • 普通的 long (使用毫秒作为默认单位,除非指定了 @DurationUnit )。
  • 标准的ISO-8601格式 由 java.time.Duration 使用。
  • 一个更易读的格式,其中值和单位是耦合的(10s 表示10秒)。

请考虑以下例子。

Java

@ConfigurationProperties("my")
public class MyProperties {@DurationUnit(ChronoUnit.SECONDS)private Duration sessionTimeout = Duration.ofSeconds(30);private Duration readTimeout = Duration.ofMillis(1000);// getters / setters...}

要指定一个30秒的会话超时, 30 、 PT30S 和 30s 都是等价的。 读取超时为500ms,可以用以下任何一种形式指定。 500, PT0.5S 和 500ms.

你也可以使用如下支持的时间单位。

  • ns 纳秒
  • us 微秒
  • ms 毫秒
  • s 秒
  • m 分
  • h 小时
  • d 天

默认单位是毫秒,可以使用 @DurationUnit 来重写,如上面的例子所示。

如果你喜欢使用构造函数绑定,同样的属性可以被暴露出来,如下面的例子所示。

Java

@ConfigurationProperties("my")
public class MyProperties {// fields...public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,@DefaultValue("1000ms") Duration readTimeout) {this.sessionTimeout = sessionTimeout;this.readTimeout = readTimeout;}// getters...}

 如果你要升级一个 Long 的属性,如果它不是毫秒,请确保定义单位(使用 @DurationUnit )。 这样做提供了一个透明的升级路径,同时支持更丰富的格式

转换为期间(Period)

除了duration,Spring Boot还可以使用 java.time.Period 类型。 以下格式可以在application properties中使用。

  • 一个常规的 int 表示法(使用天作为默认单位,除非指定了 @PeriodUnit )。
  • 标准的ISO-8601格式 由 java.time.Period 使用。
  • 一个更简单的格式,其中值和单位对是耦合的( 1y3d 表示1年3天)。

支持下列简单的单位格式。

  • y 年
  • m 月
  • w 周
  • d 日

java.time.Period 类型实际上从未存储过周数,它是一个快捷方式,意味着 “7天”。

转换为数据大小(Data Sizes)

Spring Framework有一个 DataSize 值类型,以字节为单位表达大小。 如果你公开了一个 DataSize 属性,application properties中的以下格式就可用。

  • 一个常规的 long 表示(使用字节作为默认单位,除非指定了 @DataSizeUnit)。
  • 一个更易读的格式,其中值和单位是耦合的(10MB 意味着10兆字节)。

考虑以下例子。

Java

Kotlin

@ConfigurationProperties("my")
public class MyProperties {@DataSizeUnit(DataUnit.MEGABYTES)private DataSize bufferSize = DataSize.ofMegabytes(2);private DataSize sizeThreshold = DataSize.ofBytes(512);// getters/setters...}

要指定一个10兆字节(Mb)的缓冲区大小, 10 和 10MB 是等价的。 256字节的大小阈值可以指定为 256 或 256B。

你也可以使用如下这些支持的单位。

  • B 字节
  • KB KB
  • MB MB
  • GB GB
  • TB TB

默认单位是字节,可以使用 @DataSizeUnit 来重写,如上面的例子所示。

如果你喜欢使用构造函数绑定,同样的属性可以被暴露出来,如下面的例子所示。

Java

@ConfigurationProperties("my")
public class MyProperties {// fields...public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,@DefaultValue("512B") DataSize sizeThreshold) {this.bufferSize = bufferSize;this.sizeThreshold = sizeThreshold;}// getters...}

如果你正在升级一个 Long 属性,确保定义单位(使用 @DataSizeUnit),如果它不是字节。 这样做提供了一个透明的升级路径,同时支持更丰富的格式。 

九、@ConfigurationProperties 校验

只要使用Spring的 @Validated 注解,Spring Boot就会尝试验证 @ConfigurationProperties 类。 你可以直接在你的配置类上使用JSR-303的 jakarta.validation 约束注解。 要做到这一点,请确保你的classpath上有一个兼容的JSR-303实现,然后将约束注解添加到你的字段中,如下面的例子所示。

Java

@ConfigurationProperties("my.service")
@Validated
public class MyProperties {@NotNullprivate InetAddress remoteAddress;// getters/setters...}

你也可以通过在 configuration properties 的 @Bean 方法上注解 @Validated 来触发验证。 

为了确保总是为嵌套的属性触发验证,即使没有找到属性,相关的字段必须用 @Valid 来注释。 下面的例子建立在前面的 MyProperties 的基础上。

Java

@ConfigurationProperties("my.service")
@Validated
public class MyProperties {@NotNullprivate InetAddress remoteAddress;@Validprivate final Security security = new Security();// getters/setters...public static class Security {@NotEmptyprivate String username;// getters/setters...}}

你也可以通过创建一个名为 configurationPropertiesValidator 的bean定义来添加一个自定义的Spring Validator。 @Bean 方法应该被声明为 static。 配置属性验证器是在应用程序生命周期的早期创建的,将 @Bean 方法声明为静态,可以让Bean的创建不需要实例化 @Configuration 类。 这样做可以避免过早实例化可能引起的任何问题。

spring-boot-actuator 模块包括一个暴露所有 @ConfigurationProperties Bean 的端点。 你可以通过浏览器访问 /actuator/configprops 或使用相应的JMX端点。 详情见"生产就绪"部分。

十、@ConfigurationProperties vs. @Value

@Value 注解是一个核心的容器功能,它不提供与类型安全的配置属性相同的功能。 下表总结了 @ConfigurationProperties 和 @Value 所支持的功能。

功能

@ConfigurationProperties

@Value

宽松绑定

Yes

有限制 (见 下文注释)

支持 Meta-data

Yes

No

SpEL 表达式

No

Yes

如果你确实想使用 @Value,我们建议你使用属性名称的规范形式(仅使用小写字母的kebab-case)来引用属性名称。 这将允许Spring Boot使用与 宽松绑定 @ConfigurationProperties 时相同的逻辑。

例如,@Value("${demo.item-price}") 将从 application.properties 文件中获取 demo.item-price 和 demo.itemPrice 形式,以及从系统环境中获取 DEMO_ITEMPRICE。 如果你用 @Value("${demo.itemPrice}") 代替,demo.item-price 和 DEMO_ITEMPRICE 将不会被考虑。

如果你为你自己的组件定义了一组配置键,我们建议你将它们分组在一个用 @ConfigurationProperties 注解的POJO中。 这样做将为你提供结构化的、类型安全的对象,你可以将其注入到你自己的bean中。

来自应用application property 文件的 SpEL 表达式在解析这些文件和填充environment时不会被处理。 然而,可以在 @Value 中写一个 SpEL 表达式。 如果来自应用程序属性文件的属性值是一个 SpEL 表达式,它将在被 @Value 消费时被解析。

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

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

相关文章

Android 面试题 避免OOM(内存优化)三

&#x1f525; OOM介绍&#xff08;out of memory 内存溢出&#xff09;&#x1f525; Android和java中都会出现由于不良代码引起的内存泄露&#xff0c;为了使Android应用程序能够快速高效的运行&#xff0c;Android每个应用程序都会有专门Dalvik虚拟机实例来运行&#xff0c;…

【机器学习】机器学习中的“本体”概念

一、说明 在机器学习中&#xff0c;本体越来越多地用于提供基于相似性分析和场景知识的 ML 模型。 在传统的基于标签的定义中&#xff0c;对象往往是孤立的&#xff0c;可扩展性差&#xff0c;存在重复的可能性&#xff0c;对象之间的关系无法体现。在基于本体的定义中&#xf…

4_Apollo4BlueLite电源管理

1.Cortex-M4 Power Modes Apollo4BlueLite支持以下4种功耗模式&#xff1a; ▪ High Performance Active (not a differentiated power mode for the Cortex-M4) ▪ Active ▪ Sleep ▪ Deep Sleep &#xff08;1&#xff09;High Performance Mode 高性能模式不是arm定…

【深度学习】以图搜索- 2021sota repVgg来抽取向量 + facebook的faiss的做特征检索, 从环境搭建到运行案例从0到1

文章目录 前言安装小试牛刀用repVgg抽取向量构建Faiss索引进行相似性搜索本项目延伸其它项目拓展总结 前言 Faiss的全称是Facebook AI Similarity Search。 这是一个开源库&#xff0c;针对高维空间中的海量数据&#xff0c;提供了高效且可靠的检索方法。 暴力检索耗时巨大&a…

最全的3D动画软件介绍来了!良心总结9款3D动画制作必备软件

现在&#xff0c;市面上流行着的3D动画软件如此之多&#xff0c;以至于很难敲定到底哪一款更适合自己或自己的团队。本篇文章带来了一些热门的、被视为行业标准的3D动画软件的介绍&#xff0c;帮助您更好地做出选择。 不仅如此&#xff0c;您还能从文章中了解到在数字内容创建…

html/javascript-表格的创建和使用

html中表格的创建和使用 一 摘要二 使用html table标签创建表格&#xff08;在html文件中&#xff09;三 使用javascript创建表格&#xff08;在js文件中&#xff09;四 表格属性的设置&#xff1a;4.1. 右边框的设置&#xff1a;4.2. 只给表格单元格加右边框4.3. 动态设置右边…

费舍尔线性分辩分析(Fisher‘s Linear Discriminant Analysis, FLDA)

费舍尔线性分辩分析(Fisher’s Linear Discriminant Analysis, FLDA) 目录 费舍尔线性分辩分析(Fishers Linear Discriminant Analysis, FLDA)1. 问题描述2. 二分类情况3. 多分类情况4. 代码实现4.1 二分类情况4.2 多分类情况 5. 参考资料 1. 问题描述 为解决两个或多个类别的…

PS - Photoshop 抠图与剪贴蒙版功能与 Stable Diffusion 重绘

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131978632 Photoshop 的剪贴蒙版是一种将上层图层的内容限制在下层图层的形状范围内的方法&#xff0c;也就是说&#xff0c;上层图层只能在下层图…

【备战csp-j】 csp常考题型详解(1)

一.计算机基础知识 1. 微型计算机的问世是由于( ) 的出现。 A.中小规模集成电路 B.晶体管电路 C.(超)大规模集成电路 D.电子管电路 答案&#xff1a; C 解析&#xff1a; 年代 元件 第一代 1946&#xff0d;1958 电子管 第二代 1959&#xff0d;1964 晶体管 …

32.选择器

选择器 html部分 <div class"toggle-container"><input type"checkbox" id"good" class"toggle"><label for"good" class"label"><div class"ball"></div></label&…

云原生训练营课程大纲

第一部分&#xff1a;Go 语****言基础 模块一&#xff1a;Go 语言特性 教学目标&#xff1a; 理解 Go 语言基本语法 理解 Go 语言常用数据类型 理解 Go 语言常用小技巧 深入理解 Go 语言的多线程编程 针对的用户痛点&#xff1a; 云原生从业者因为未熟练掌握 Go 语言&#…

bash sh 和 ./ 的区别

bash&#xff1a; 这是Bash shell的解释器。当你使用bash script.sh运行脚本时&#xff0c;你是在告诉系统使用Bash解释器来执行脚本。这意味着脚本中的所有Bash特性都可以使用。 sh&#xff1a; 这是Bourne shell的解释器。当你使用sh script.sh运行脚本时&#xff0c;你是在告…

HTML的基础知识

HTML&#xff08;超文本标记语言&#xff09;是一种用于创建网页的标记语言。它提供了一套标记&#xff08;标签&#xff09;和元素&#xff08;元素&#xff09;的规范&#xff0c;用于描述网页结构和内容的呈现方式。HTML 文件是由一系列的标签组成&#xff0c;这些标签用于定…

uni-app云打包(android)(自有证书、云端证书、公共测试证书)

一、进入云打包入口 发行->原生App-云打包 二、证书选择 1、使用自有证书 ①进入香蕉云编&#xff08;这里采用的证书从香蕉云编进行生成&#xff09; 香蕉云编-app打包上架工具类平台 ②进入页面选择“生成签名证书”->"立即创建证书" ③选择“安卓证书生…

数字人会成为文旅行业的新增量吗?写实数字人定制包含哪些技术?

近年来&#xff0c;各大文旅机构均在围绕数字人展开了文旅营销创作&#xff0c;凭借着写实数字人定制技术&#xff0c;将数字人的人设、功能以及才艺得到创新&#xff0c;并由此在文旅形态上展开了诸多尝试。 比如会唱山歌多才多艺的数字人刘三姐&#xff0c;使用多种语言推介…

OrderApplication

目录 1 OrderApplication 2 /// 获提交订单页面数据 2.1.1 //设置会员信息 2.1.2 //获取订单商品信息 2.1.3 //获取收货地址 2.1.4 //发票信息 OrderApplication#region web公共方法

windows环境下adb 下载和配置,连接手机。

ADB下载地址&#xff1a; https://adbdownload.com/ 选择下载windows系统的。 下载后解压&#xff0c;查看adb.exe所在的目录&#xff0c;如下 这里将路径复制下来&#xff1a;D:\ADB 配置到系统环境变量中。 然后再打开cmd&#xff0c;输入adb version查看版本。 出现…

ThinkPHP8知识详解:ThinkPHP8是什么?

欢迎你来到PHP服务网学习最新的ThinkPHP8开发教程&#xff0c;本文介绍一下ThinkPHP8是什么&#xff1f; 1、ThinkPHP8是ThinkPHP框架的最新版本&#xff0c;它在之前版本的基础上进行了改进和优化。它采用了现代化的设计理念和架构&#xff0c;提供了更好的性能和更丰富的功能…

【机器学习】Linear Regression

Model Representation 1、问题描述2、表示说明3、数据绘图4、模型函数5、预测总结附录 1、问题描述 一套 1000 平方英尺 (sqft) 的房屋售价为300,000美元&#xff0c;一套 2000 平方英尺的房屋售价为500,000美元。这两点将构成我们的数据或训练集。面积单位为 1000 平方英尺&a…

【ubuntu|内核】ubuntu 22.04修改内核为指定版本

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 ubuntu 22.04 安装指定内核 1. 正文 查看已安装的内核镜像 dpkg --get-selections | grep linux-image1.1 安装指定版本的内核 安装镜像 sudo apt-g…