龙空技术网

「SpringBoot」如何实现一个SpringBoot的starter

岭南阿呆 267

前言:

此时大家对“c语言void value not ignored”都比较关切,咱们都需要学习一些“c语言void value not ignored”的相关文章。那么小编同时在网上收集了一些有关“c语言void value not ignored””的相关知识,希望小伙伴们能喜欢,同学们一起来学习一下吧!

简概

官网文档:

主要步骤

编写 Java Config

@Configuration

添加条件

@Conditional

绑定⾃动配置

META-INF/spring.factories条件注解

条件注解

@Conditional

类条件

@ConditionalOnClass@ConditionalOnMissingClass

属性条件

@ConditionalOnProperty

Bean 条件

@ConditionalOnBean@ConditionalOnMissingBean@ConditionalOnSingleCandidate

资源条件

@ConditionalOnResource

Web 应⽤条件

@ConditionalOnWebApplication@ConditionalOnNotWebApplication

其他条件

@ConditionalOnExpression@ConditionalOnJava@ConditionalOnJndi详述

官网地址:

自动配置类可以捆绑在外部jar中,并依旧可以被Spring Boot获取。

自动配置可以与一个“starter”相关联,该starter提供自动配置代码以及与之一起使用的典型库。我们首先介绍构建自己的自动配置所需的知识,然后继续介绍创建自定义启动器所需的典型步骤

理解Auto-configured Beans

实现自动配置的类使用@AutoConfiguration注解。该注解本身使用@Configuration进行元注解,使自动配置成为标准的@Configuration类。可以通过附加@Conditional注解用于约束何时应用自动配置。通常,自动配置类使用@ConditionalOnClass和@ConditionalOnMissingBean注解。这确保了自动配置只在找到相关类并且没有声明自己的@Configuration时才会应用。

你可以浏览 spring-boot-autoconfigure 的源代码来查看Spring提供的@AutoConfiguration类(参见 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件)。

定位 Auto-configuration “人选”

SpringBoot 检查你发布的jar包中META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports file是否存在。该文件应该列出你的配置类,每行一个类名,如下例所示:

com.mycorp.libx.autoconfigure.LibXAutoConfigurationcom.mycorp.libx.autoconfigure.LibXWebAutoConfiguration

可以使用#字符向导入文件添加注释

只能通过在导入文件中命名来加载自动配置。确保它们定义在特定的包空间中,并且它们永远不是组件扫描的目标。此外,自动配置类不应该启用组件扫描来查找其他组件,应该使用特定的@Imports。

如果您的配置需要以特定的顺序应用,您可以在@AutoConfiguration注解上使用before、beforeName、after和afterName属性或使用特制的@AutoConfigureBefore@AutoConfigureBefore注解。例如,如果您提供特定于web的配置,您的类可能需要在WebMvcAutoConfiguration之后应用。

如果您想为某些彼此间没有直接了解(或者说不清楚彼此间存在)的自动配置指定顺序,您还可以使用@AutoConfigureOrder。该注解与常规的@Order注解具有相同的语义,但为自动配置类提供了专用的顺序。

条件注解

您几乎总是希望在自动配置类中包含一个或多个@Conditional注解。@ConditionalOnMissingBean注解是一个常见的例子,用于允许开发人员在不满意您的默认值时覆盖自动配置

Spring Boot包含许多@Conditional注解,您可以在自己的代码(注解@Configuration的类或单独的@Bean方法)上重用这些注解。这些注解包括:

Class ConditionsBean ConditionsProperty ConditionsResource ConditionsWeb Application ConditionsSpEL Expression Conditions测试自动配置

自动配置可能受到许多因素的影响:用户配置(@Bean定义和环境自定义)、条件评估(特定库的存在),以及其他。具体地说,每个测试都应该创建一个定义良好的ApplicationContext,它表示这些定制的组合。ApplicationContextRunner提供了一种很好的方法来实现这一点。

ApplicationContextRunner通常被定义为测试类的一个字段,用于收集基本的公共配置。下面的例子确保了MyServiceAutoConfiguration总是被调用:

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()        .withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration.class));

如果必须定义多个自动配置,则不需要对它们的声明进行排序,因为调用它们的顺序与运行应用程序时完全相同。

每个测试都可以使用运行程序来表示一个特定的用例。例如,下面的示例调用一个用户配置(UserConfiguration)并检查自动配置是否正确地退出。调用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 {    @Bean    MyService myCustomService() {        return new MyService("mine");    }}

也可以轻松地自定义Environment,如下面的示例所示:

@Testvoid serviceNameCanBeConfigured() {    this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {        assertThat(context).hasSingleBean(MyService.class);        assertThat(context.getBean(MyService.class).getName()).isEqualTo("test123");    });}

runner还可以用来显示ConditionEvaluationReport。报告可以打印INFO或DEBUG级别的日志。下面的示例演示如何使用ConditionEvaluationReportLoggingListener在自动配置测试中打印报告。

import org.junit.jupiter.api.Test;import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;import org.springframework.boot.logging.LogLevel;import org.springframework.boot.test.context.runner.ApplicationContextRunner;class MyConditionEvaluationReportingTests {    @Test    void autoConfigTest() {        new ApplicationContextRunner()            .withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO))            .run((context) -> {                    // Test something...            });    }}
模拟Web上下文

如果需要测试只在servlet或响应式web应用程序上下文中运行的自动配置,可使用WebApplicationContextRunner或ReactiveWebApplicationContextRunner。

重写类路径

还可以测试当特定的类和/或包在运行时不存在时会发生什么。Spring引导附带一个FilteredClassLoader,运行程序可以很容易地使用它。在下面的例子中,我们断言如果MyService不存在,自动配置将被正确禁用:

@Testvoid serviceIsIgnoredIfLibraryIsNotPresent() {    this.contextRunner.withClassLoader(new FilteredClassLoader(MyService.class))            .run((context) -> assertThat(context).doesNotHaveBean("myService"));}
创建自己的starter

一个典型的Spring Boot启动程序包含自动配置和定制给定技术基础结构的代码,我们称之为“acme”。为了使其易于扩展,可以向环境公开专用名称空间中的许多配置键。最后,提供了一个“starter”依赖项,以帮助用户尽可能容易地启动。

具体来说,一个自定义starter可以包含以下内容:

包含“acme”的自动配置代码的自动配置模块。启动模块,它提供对自动配置模块的依赖项、“acme”以及通常用到的任何其他依赖项。简而言之,添加的starter应该提供开始使用该库所需的一切。

这两个模块的分离是没有必要的。如果“acme”有几种风格、选项或可选特性,那么最好将自动配置分开,因为您可以清楚地表达一些特性是可选的事实。此外,您还可以编写一个“starter”,提供关于这些可选依赖项的意见。同时,其他人只能依靠自动配置模块,用不同的意见制作自己的“starter”。

如果自动配置相对简单,没有可选特性,那么合并启动器中的两个模块绝对是一个选择。

“starter”的命名

您应该确保为“starter”程序提供适当的名称空间。不要以spring-boot开头模块名,即使使用不同的Maven groupId。我们可能会在未来为您自动配置的东西提供官方支持。

根据经验,应该以“starter”的名称命名组合模块。例如,假设您正在为“acme”创建一个“starter”,并将自动配置模块命名为acme-spring-boot,将“starter”命名为acme-spring-boot-starter。如果您只有一个模块组合了这两个模块,则将其命名为acme-spring-boot-starter。

配置的键名

如果您的启动器提供配置键,请为它们使用唯一的名称空间。特别是,不要将您的键包含在Spring Boot使用的名称空间中(例如server、management、Spring等等)。如果您使用相同的名称空间,将来我们可能会以破坏模块的方式修改这些名称空间。根据经验,所有键的前缀都要有自己的名称空间(例如acme)。

在配置键对应的属性上记得加上对应的javadoc说明,确保其含义被记录下来,如下面的示例所示:

import java.time.Duration;import org.springframework.boot.context.properties.ConfigurationProperties;@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);    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;    }}

对于带@ConfigurationProperties的字段,您应该只使用纯文本的javadoc,因为它们在添加到JSON之前不会被处理。

以下是我们内部遵循的一些规则,以确保描述的一致性:

不要以“the”或“A”开头。对于布尔类型,以“Whether”或“Enable”开始描述。对于基于集合的类型,在描述开头使用"Comma-separated list"使用java.time.Duration而不是long,如果默认单位与毫秒不同,则描述默认单位,例如"If a duration suffix is not specified, seconds will be used".不要在描述中提供默认值,除非必须在运行时确定它。

确保触发元数据生成,这样IDE辅助也可以用于键。你可能想要检查生成的元数据(META-INF/spring-configuration-metadata.json),以确保你的键被正确记录。在兼容的IDE中使用自己的 starter 也是验证元数据质量的好方法。

“自动配置”模块

autoconfigure模块包含开始使用库所需的所有内容。它还可能包含配置键定义(如@ConfigurationProperties)和任何回调接口,可用于进一步定制组件初始化的方式。

您应该将库的依赖项标记为可选的,这样您就可以更容易地在项目中包含自动配置模块。如果这样做,则不会提供库,默认情况下,Spring Boot会退出。

Spring Boot使用注解处理器在元数据文件(META-INF/spring-autoconfigure-metadata.properties)中收集自动配置的条件。如果该文件存在,它将用于主动过滤不匹配的自动配置,这将提高启动时间。

使用Maven构建时,建议在包含自动配置的模块中添加以下依赖项:

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-autoconfigure-processor</artifactId>    <optional>true</optional></dependency>

如果你已经在你的应用中直接定义了自动配置,请确保配置spring-boot-maven-plugin以防止重新打包目标将依赖项添加到fat jar中:

<project>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>                <configuration>                    <excludes>                        <exclude>                            <groupId>org.springframework.boot</groupId>                            <artifactId>spring-boot-autoconfigure-processor</artifactId>                        </exclude>                    </excludes>                </configuration>            </plugin>        </plugins>    </build></project>

在Gradle中,依赖项应该在annotationProcessor配置中声明,如下例所示:

dependencies {    annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"}
Starter 模块

starter其实是一个空的jar。它的唯一目的是提供使用库所需的依赖项。你可以把它看作是一种关于如何开始的固执的观点。

不要对添加starter的项目做任何假设。如果要自动配置的库通常需要其他启动程序,也要提到它们。如果可选依赖项的数量很高,那么提供一组适当的默认依赖项可能会比较困难,因为您应该避免包含对库的典型使用来说不必要的依赖项。换句话说,您不应该包含可选的依赖项。

无论哪种方式,你的starter必须直接或间接引用核心Spring Boot starter(spring-boot-starter,但如果你的starter依赖于另一个starter,就不需要添加它)。如果一个项目只使用你自定义的starter创建,Spring Boot的核心特性将因核心启动程序的出现而得到表彰。

标签: #c语言void value not ignored