Creating Your Own Auto-configuration

如果你在一家开发共享库的公司工作,或者你在一个开源库或商业库上工作,你可能想要开发自己的自动化配置。自动化配置类可以捆绑在外部 jar 中,并且仍然会被 Spring Boot 提取。

If you work in a company that develops shared libraries, or if you work on an open-source or commercial library, you might want to develop your own auto-configuration. Auto-configuration classes can be bundled in external jars and still be picked up by Spring Boot.

自动化配置可以关联到 “starter”,既提供自动化配置代码,也提供你将与该代码一起使用的典型库。我们首先介绍生成自己的自动化配置所需的知识,然后继续介绍 typical steps required to create a custom starter

Auto-configuration can be associated to a “starter” that provides the auto-configuration code as well as the typical libraries that you would use with it. We first cover what you need to know to build your own auto-configuration and then we move on to the typical steps required to create a custom starter.

Understanding Auto-configured Beans

实现自动化配置的类用 @AutoConfiguration 进行注解。此注解本身用 @Configuration 进行元注解,使自动化配置成为标准 @Configuration 类。其他 @Conditional 注解用于约束自动化配置的应用时机。通常,自动化配置类使用 @ConditionalOnClass@ConditionalOnMissingBean 注解。这确保了仅在找到相关类且你未声明自己的 @Configuration 时才应用自动化配置。

Classes that implement auto-configuration are annotated with @AutoConfiguration. This annotation itself is meta-annotated with @Configuration, making auto-configurations standard @Configuration classes. Additional @Conditional annotations are used to constrain when the auto-configuration should apply. Usually, auto-configuration classes use @ConditionalOnClass and @ConditionalOnMissingBean annotations. This ensures that auto-configuration applies only when relevant classes are found and when you have not declared your own @Configuration.

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

You can browse the source code of {code-spring-boot-autoconfigure-src}[spring-boot-autoconfigure] to see the @AutoConfiguration classes that Spring provides (see the {code-spring-boot}/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports[META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports] file).

Locating Auto-configuration Candidates

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

Spring Boot checks for the presence of a META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports file within your published jar. The file should list your configuration classes, with one class name per line, as shown in the following example:

com.mycorp.libx.autoconfigure.LibXAutoConfiguration
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration

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

You can add comments to the imports file using the # character.

自动化配置必须通过在导入文件中命名来 only 加载。确保它们在特定软件包空间中定义,并且它们永远不会成为组件扫描的目标。此外,自动化配置类不应启用组件扫描以查找其他组件。而应该使用特定的 @Import 注解。

Auto-configurations must be loaded only by being named in the imports file. Make sure that they are defined in a specific package space and that they are never the target of component scanning. Furthermore, auto-configuration classes should not enable component scanning to find additional components. Specific @Import annotations should be used instead.

如果需要按特定顺序应用你的配置,则可以在 @AutoConfiguration 注解或专用 @AutoConfigureBefore@AutoConfigureAfter 注解中使用 {code-spring-boot-autoconfigure-src}/AutoConfiguration.java 的 beforebeforeNameafterafterName 属性。例如,如果你提供特定于 Web 的配置,则可能需要在 WebMvcAutoConfiguration 之后应用你的类。

If your configuration needs to be applied in a specific order, you can use the before, beforeName, after and afterName attributes on the {code-spring-boot-autoconfigure-src}/AutoConfiguration.java[@AutoConfiguration] annotation or the dedicated {code-spring-boot-autoconfigure-src}/AutoConfigureBefore.java[@AutoConfigureBefore] and {code-spring-boot-autoconfigure-src}/AutoConfigureAfter.java[@AutoConfigureAfter] annotations. For example, if you provide web-specific configuration, your class may need to be applied after WebMvcAutoConfiguration.

如果你想对某些自动化配置进行排序,但这些配置不应该相互直接了解,则还可以使用 @AutoConfigureOrder。该注解具有与常规 @Order 注解相同语义,但为自动化配置类提供了专用顺序。

If you want to order certain auto-configurations that should not have any direct knowledge of each other, you can also use @AutoConfigureOrder. That annotation has the same semantic as the regular @Order annotation but provides a dedicated order for auto-configuration classes.

与标准 @Configuration 类一样,应用自动化配置类的顺序只影响它们 Bean 定义的顺序。随后创建这些 Bean 的顺序不受影响,并且由每个 Bean 的依赖关系和任何 @DependsOn 关系决定。

As with standard @Configuration classes, the order in which auto-configuration classes are applied only affects the order in which their beans are defined. The order in which those beans are subsequently created is unaffected and is determined by each bean’s dependencies and any @DependsOn relationships.

Condition Annotations

你几乎总想在自动化配置类上包含一个或多个 @Conditional 注解。@ConditionalOnMissingBean 注解是一个常见示例,用于允许开发人员在对默认值不满意时覆盖自动化配置。

You almost always want to include one or more @Conditional annotations on your auto-configuration class. The @ConditionalOnMissingBean annotation is one common example that is used to allow developers to override auto-configuration if they are not happy with your defaults.

Spring Boot 包含许多 @Conditional 注解,你可以通过注解 @Configuration 类或 @Bean 单个方法在自己的代码中重复使用这些注解。这些注解包括:

Spring Boot includes a number of @Conditional annotations that you can reuse in your own code by annotating @Configuration classes or individual @Bean methods. These annotations include:

Class Conditions

@ConditionalOnClass@ConditionalOnMissingClass 注释根据特定类的存在或不存在将 @Configuration 类包含在内。由于使用 ASM 解析注释元数据,因此您可以使用 value 属性引用实际类,即使该类可能实际上未出现在正在运行的应用程序类路径中。如果您更愿意使用 String 值指定类名,则还可以使用 name 属性。

The @ConditionalOnClass and @ConditionalOnMissingClass annotations let @Configuration classes be included based on the presence or absence of specific classes. Due to the fact that annotation metadata is parsed by using ASM, you can use the value attribute to refer to the real class, even though that class might not actually appear on the running application classpath. You can also use the name attribute if you prefer to specify the class name by using a String value.

此机制不适用于 @Bean 方法,在该方法中通常返回类型是条件的目标:在方法上的条件应用之前,JVM 将加载类并可能处理类不存在时将失败的方法引用。

This mechanism does not apply the same way to @Bean methods where typically the return type is the target of the condition: before the condition on the method applies, the JVM will have loaded the class and potentially processed method references which will fail if the class is not present.

要处理此场景,可以使用单独的 @Configuration 类来隔离条件,如下例所示:

To handle this scenario, a separate @Configuration class can be used to isolate the condition, as shown in the following example:

如果你使用 @ConditionalOnClass@ConditionalOnMissingClass 作为元注释的一部分来编写自己的组合注释,则必须在这种情况中使用 name,因为它不处理所引用的类。

If you use @ConditionalOnClass or @ConditionalOnMissingClass as a part of a meta-annotation to compose your own composed annotations, you must use name as referring to the class in such a case is not handled.

Bean Conditions

@ConditionalOnBean@ConditionalOnMissingBean 注释允许基于特定 bean 的存在或不存在包含 bean。你可以使用 value 属性按类型指定 bean,或使用 name 按名称指定 bean。search 属性允许你在搜索 bean 时限定应考虑的 ApplicationContext 层次结构。

The @ConditionalOnBean and @ConditionalOnMissingBean annotations let a bean be included based on the presence or absence of specific beans. You can use the value attribute to specify beans by type or name to specify beans by name. The search attribute lets you limit the ApplicationContext hierarchy that should be considered when searching for beans.

当放置在 @Bean 方法上时,目标类型默认为该方法的返回类型,如下例所示:

When placed on a @Bean method, the target type defaults to the return type of the method, as shown in the following example:

在前面的示例中,如果 ApplicationContext 中尚未包含类型为 SomeService 的 bean,则将创建 someService bean。

In the preceding example, the someService bean is going to be created if no bean of type SomeService is already contained in the ApplicationContext.

你需要非常仔细地考虑 bean 定义的添加顺序,因为这些条件是根据到目前为止处理的内容进行评估的。因此,我们建议仅对自动配置类使用 @ConditionalOnBean@ConditionalOnMissingBean 注释(因为在添加任何用户定义的 bean 定义之后,这些注释保证加载)。

You need to be very careful about the order in which bean definitions are added, as these conditions are evaluated based on what has been processed so far. For this reason, we recommend using only @ConditionalOnBean and @ConditionalOnMissingBean annotations on auto-configuration classes (since these are guaranteed to load after any user-defined bean definitions have been added).

@ConditionalOnBean@ConditionalOnMissingBean 不会阻止创建 @Configuration 类。在类级别使用这些条件与使用注释标记每个包含的 @Bean 方法之间的唯一区别在于,如果条件不匹配,前者将阻止将 @Configuration 类注册为 bean。

@ConditionalOnBean and @ConditionalOnMissingBean do not prevent @Configuration classes from being created. The only difference between using these conditions at the class level and marking each contained @Bean method with the annotation is that the former prevents registration of the @Configuration class as a bean if the condition does not match.

在声明 @Bean 方法时,在方法的返回类型中尽可能提供更多类型信息。例如,如果你的 bean 的具体类实现了接口,则 bean 方法的返回类型应该是具体类而不是该接口。在 @Bean 方法中尽可能提供更多类型信息非常重要,因为它们的评估只能依赖于方法签名中可用的类型信息。

When declaring a @Bean method, provide as much type information as possible in the method’s return type. For example, if your bean’s concrete class implements an interface the bean method’s return type should be the concrete class and not the interface. Providing as much type information as possible in @Bean methods is particularly important when using bean conditions as their evaluation can only rely upon to type information that is available in the method signature.

Property Conditions

@ConditionalOnProperty 注释允许基于 Spring Environment 属性包含配置。使用 prefixname 属性指定应检查的属性。默认情况下,将匹配任何存在且不等于 false 的属性。你还可以通过使用 havingValuematchIfMissing 属性创建更高级的检查。

The @ConditionalOnProperty annotation lets configuration be included based on a Spring Environment property. Use the prefix and name attributes to specify the property that should be checked. By default, any property that exists and is not equal to false is matched. You can also create more advanced checks by using the havingValue and matchIfMissing attributes.

Resource Conditions

@ConditionalOnResource 注释仅在存在特定资源时才能包含配置。可以使用通常的 Spring 约定指定资源,如下例所示:file:/home/user/test.dat

The @ConditionalOnResource annotation lets configuration be included only when a specific resource is present. Resources can be specified by using the usual Spring conventions, as shown in the following example: file:/home/user/test.dat.

Web Application Conditions

@ConditionalOnWebApplication@ConditionalOnNotWebApplication 注释允许根据应用程序是否是 Web 应用程序包含配置。基于 servlet 的 Web 应用程序是指使用 Spring WebApplicationContext、定义 session 作用域或有 ConfigurableWebEnvironment 的任何应用程序。反应式 Web 应用程序是指使用 ReactiveWebApplicationContext 或有 ConfigurableReactiveWebEnvironment 的任何应用程序。

The @ConditionalOnWebApplication and @ConditionalOnNotWebApplication annotations let configuration be included depending on whether the application is a web application. A servlet-based web application is any application that uses a Spring WebApplicationContext, defines a session scope, or has a ConfigurableWebEnvironment. A reactive web application is any application that uses a ReactiveWebApplicationContext, or has a ConfigurableReactiveWebEnvironment.

@ConditionalOnWarDeployment@ConditionalOnNotWarDeployment 注释允许根据应用程序是否是部署到 servlet 容器的传统 WAR 应用程序包含配置。此条件不适用于使用嵌入式 Web 服务器运行的应用程序。

The @ConditionalOnWarDeployment and @ConditionalOnNotWarDeployment annotations let configuration be included depending on whether the application is a traditional WAR application that is deployed to a servlet container. This condition will not match for applications that are run with an embedded web server.

SpEL Expression Conditions

@ConditionalOnExpression 注释允许根据 {url-spring-framework-docs}/core/expressions.html[SpEL 表达式] 的结果包含配置。

The @ConditionalOnExpression annotation lets configuration be included based on the result of a {url-spring-framework-docs}/core/expressions.html[SpEL expression].

在表达式中引用 bean 将导致在上下文字符串处理非常早地初始化该 bean。因此,该 bean 将不符合进行后期处理(例如配置属性绑定)的条件,并且其状态可能不完整。

Referencing a bean in the expression will cause that bean to be initialized very early in context refresh processing. As a result, the bean won’t be eligible for post-processing (such as configuration properties binding) and its state may be incomplete.

Testing your Auto-configuration

自动配置会受到许多因素的影响:用户配置(@Bean 定义和 Environment 自定)、条件评估(特定库的存在)等。具体来说,每个测试都应该创建一个明确定义的 ApplicationContext,它表示那些自定的组合。ApplicationContextRunner 提供了一个实现这一目标的好方法。

An auto-configuration can be affected by many factors: user configuration (@Bean definition and Environment customization), condition evaluation (presence of a particular library), and others. Concretely, each test should create a well defined ApplicationContext that represents a combination of those customizations. ApplicationContextRunner provides a great way to achieve that.

在原生映像中运行测试时,ApplicationContextRunner 不起作用。

ApplicationContextRunner doesn’t work when running the tests in a native image.

ApplicationContextRunner`通常定义为测试类的一个字段,用于收集基础、通用配置。以下示例确保总是调用 `MyServiceAutoConfiguration

ApplicationContextRunner is usually defined as a field of the test class to gather the base, common configuration. The following example makes sure that MyServiceAutoConfiguration is always invoked:

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

If multiple auto-configurations have to be defined, there is no need to order their declarations as they are invoked in the exact same order as when running the application.

每个测试都可以使用 runner 来表示特定的用例。例如,以下示例调用用户配置 (UserConfiguration) 并检查自动配置是否正确关闭。调用 run 提供了一个回调上下文,可与 AssertJ 一起使用。

Each test can use the runner to represent a particular use case. For instance, the sample below invokes a user configuration (UserConfiguration) and checks that the auto-configuration backs off properly. Invoking run provides a callback context that can be used with AssertJ.

还可以轻松自定义 Environment,如下例所示:

It is also possible to easily customize the Environment, as shown in the following example:

该 runner 还可用于显示 ConditionEvaluationReport。该报告可以在 `INFO`或 `DEBUG`级别打印。以下示例展示了如何使用 `ConditionEvaluationReportLoggingListener`在自动配置测试中打印报告。

The runner can also be used to display the ConditionEvaluationReport. The report can be printed at INFO or DEBUG level. The following example shows how to use the ConditionEvaluationReportLoggingListener to print the report in auto-configuration tests.

Simulating a Web Context

如果您需要测试仅在 servlet 或响应式 web 应用程序上下文中运行的自动配置,请分别使用 WebApplicationContextRunnerReactiveWebApplicationContextRunner

If you need to test an auto-configuration that only operates in a servlet or reactive web application context, use the WebApplicationContextRunner or ReactiveWebApplicationContextRunner respectively.

Overriding the Classpath

还可以测试在运行时不存在特定类和/或包时会发生的情况。Spring Boot 随附一个 FilteredClassLoader,该 runner 可以轻松使用它。在以下示例中,我们断言如果 MyService 不存在,则自动配置将被正确实用禁用:

It is also possible to test what happens when a particular class and/or package is not present at runtime. Spring Boot ships with a FilteredClassLoader that can easily be used by the runner. In the following example, we assert that if MyService is not present, the auto-configuration is properly disabled:

Creating Your Own Starter

一个典型的 Spring Boot starter 包含用于自动配置和自定义给定技术基础设施的代码,我们称之为“acme”。为了使其易于扩展,可以将专用命名空间中的一些配置键公开给环境。最后,提供一个“starter”依赖项,以帮助用户尽可能轻松地入门。

A typical Spring Boot starter contains code to auto-configure and customize the infrastructure of a given technology, let’s call that "acme". To make it easily extensible, a number of configuration keys in a dedicated namespace can be exposed to the environment. Finally, a single "starter" dependency is provided to help users get started as easily as possible.

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

Concretely, a custom starter can contain the following:

  • The autoconfigure module that contains the auto-configuration code for "acme".

  • The starter module that provides a dependency to the autoconfigure module as well as "acme" and any additional dependencies that are typically useful. In a nutshell, adding the starter should provide everything needed to start using that library.

这两个模块中的分离绝不是必需的。如果“acme”有几个类型、选项或可选特性,那么最好将自动配置分开,因为您可以清楚地表示某些特性是可选的。此外,您可以创建 starter 来说明对这些可选依赖项的观点。同时,其他人只能依赖 `autoconfigure`模块并用不同的观点制定自己的 starter。

This separation in two modules is in no way necessary. If "acme" has several flavors, options or optional features, then it is better to separate the auto-configuration as you can clearly express the fact some features are optional. Besides, you have the ability to craft a starter that provides an opinion about those optional dependencies. At the same time, others can rely only on the autoconfigure module and craft their own starter with different opinions.

如果自动配置相对简单且没有可选特性,则将 starter 中的两个模块合并肯定是一种选择。

If the auto-configuration is relatively straightforward and does not have optional features, merging the two modules in the starter is definitely an option.

Naming

您应确保为 starter 提供适当的命名空间。不要以 `spring-boot`开头模块名称,即使您使用不同的 Maven `groupId`也是如此。我们可能在将来为要在其中进行自动配置的事物提供官方支持。

You should make sure to provide a proper namespace for your starter. Do not start your module names with spring-boot, even if you use a different Maven groupId. We may offer official support for the thing you auto-configure in the future.

一般而言,您应当以启动器命名合并模块。例如,假定您正在为“acme”创建启动器,并将自动配置模块命名为 acme-spring-boot,将启动器命名为 acme-spring-boot-starter。如果您只有一个模块将两者结合在一起,那么应将它命名为 acme-spring-boot-starter

As a rule of thumb, you should name a combined module after the starter. For example, assume that you are creating a starter for "acme" and that you name the auto-configure module acme-spring-boot and the starter acme-spring-boot-starter. If you only have one module that combines the two, name it acme-spring-boot-starter.

Configuration keys

如果您的启动器提供配置键,请为它们使用唯一的命名空间。特别是,请勿将您的键包含在 Spring Boot 使用的命名空间中(例如 servermanagementspring`等)。如果您使用相同的命名空间,我们可能会将来以破坏您的模块的方式修改这些命名空间。一般而言,使用您自己的命名空间为所有键加上前缀(例如 `acme)。

If your starter provides configuration keys, use a unique namespace for them. In particular, do not include your keys in the namespaces that Spring Boot uses (such as server, management, spring, and so on). If you use the same namespace, we may modify these namespaces in the future in ways that break your modules. As a rule of thumb, prefix all your keys with a namespace that you own (for example acme).

确保通过为每个属性添加字段 javadoc 文档化配置键,如下面的示例所示:

Make sure that configuration keys are documented by adding field javadoc for each property, as shown in the following example:

您应该只将纯文本与 `@ConfigurationProperties`字段 Javadoc 一起使用,因为在将它们添加到 JSON 之前不会对其进行处理。

You should only use plain text with @ConfigurationProperties field Javadoc, since they are not processed before being added to the JSON.

以下是在内部遵循的一些规则以确保描述一致:

Here are some rules we follow internally to make sure descriptions are consistent:

  • Do not start the description by "The" or "A".

  • For boolean types, start the description with "Whether" or "Enable".

  • For collection-based types, start the description with "Comma-separated list"

  • Use java.time.Duration rather than long and describe the default unit if it differs from milliseconds, such as "If a duration suffix is not specified, seconds will be used".

  • Do not provide the default value in the description unless it has to be determined at runtime.

确保 trigger meta-data generation,以使 IDE 帮助也适用于您的键。您可能需要查看生成的元数据 (META-INF/spring-configuration-metadata.json) 以确保您的键已正确记录。在兼容的 IDE 中使用您自己的启动器也是验证元数据质量的好主意。

Make sure to trigger meta-data generation so that IDE assistance is available for your keys as well. You may want to review the generated metadata (META-INF/spring-configuration-metadata.json) to make sure your keys are properly documented. Using your own starter in a compatible IDE is also a good idea to validate that quality of the metadata.

The “autoconfigure” Module

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

The autoconfigure module contains everything that is necessary to get started with the library. It may also contain configuration key definitions (such as @ConfigurationProperties) and any callback interface that can be used to further customize how the components are initialized.

您应将对该库的依赖项标记为可选的,以便可以更轻松地在项目中包含 `autoconfigure`模块。如果您这样做,则不会提供该库,并且默认情况下,Spring Boot 会进行备份。

You should mark the dependencies to the library as optional so that you can include the autoconfigure module in your projects more easily. If you do it that way, the library is not provided and, by default, Spring Boot backs off.

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

Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file (META-INF/spring-autoconfigure-metadata.properties). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time.

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

When building with Maven, it is recommended to add the following dependency in a module that contains auto-configurations:

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

如果您已在应用程序中直接定义自动配置,请确保配置 `spring-boot-maven-plugin`以防止 `repackage`目标向 uber jar 中添加依赖项:

If you have defined auto-configurations directly in your application, make sure to configure the spring-boot-maven-plugin to prevent the repackage goal from adding the dependency into the uber 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`配置中声明依赖项,如下面的示例所示:

With Gradle, the dependency should be declared in the annotationProcessor configuration, as shown in the following example:

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

Starter Module

启动器实际上是一个空 jar。它的唯一目的是提供与该库协同工作的必要依赖项。您可以将其视为开始所需内容的一种观点。

The starter is really an empty jar. Its only purpose is to provide the necessary dependencies to work with the library. You can think of it as an opinionated view of what is required to get started.

请不要对添加启动程序的项目做出假设。如果您要自动配置的库通常需要其他启动程序,请也提及它们。如果可选依赖项的数量很大,则提供一组适当的 `@`1 依赖项可能很困难,因为您应该避免包含对于库的典型用途来说不必要的依赖项。换句话说,您不应该包含可选的依赖项。

Do not make assumptions about the project in which your starter is added. If the library you are auto-configuring typically requires other starters, mention them as well. Providing a proper set of default dependencies may be hard if the number of optional dependencies is high, as you should avoid including dependencies that are unnecessary for a typical usage of the library. In other words, you should not include optional dependencies.

无论哪种方式,您的启动程序都必须直接或间接引用核心 Spring Boot 启动程序 (`@`2)(如果您的启动程序依赖另一个启动程序,则无需添加它)。如果只创建了自定义启动程序的项目,Spring Boot 的核心功能将通过核心启动程序的存在得到尊重。

Either way, your starter must reference the core Spring Boot starter (spring-boot-starter) directly or indirectly (there is no need to add it if your starter relies on another starter). If a project is created with only your custom starter, Spring Boot’s core features will be honoured by the presence of the core starter.