Migrate to Antora

Closes gh-33766
This commit is contained in:
Phillip Webb
2024-03-20 15:36:10 -07:00
468 changed files with 9831 additions and 8255 deletions

View File

@@ -17,7 +17,7 @@ def versions = [:]
new File(projectDir.parentFile, "gradle.properties").withInputStream {
def properties = new Properties()
properties.load(it)
["assertj", "commonsCodec", "hamcrest", "junitJupiter", "kotlin", "maven"].each {
["assertj", "commonsCodec", "hamcrest", "junitJupiter", "kotlin", "maven", "snakeYaml"].each {
versions[it] = properties[it + "Version"]
}
}
@@ -42,20 +42,23 @@ dependencies {
implementation(platform("org.springframework:spring-framework-bom:${versions.springFramework}"))
implementation("com.diffplug.gradle:goomph:3.37.2")
implementation("com.fasterxml.jackson.core:jackson-databind:${versions.jackson}")
implementation("com.github.node-gradle:gradle-node-plugin:3.5.1")
implementation("com.gradle:gradle-enterprise-gradle-plugin:3.12.1")
implementation("com.tngtech.archunit:archunit:1.0.0")
implementation("commons-codec:commons-codec:${versions.commonsCodec}")
implementation("de.undercouch.download:de.undercouch.download.gradle.plugin:5.5.0")
implementation("io.spring.gradle.antora:spring-antora-plugin:0.0.1")
implementation("io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}")
implementation("io.spring.nohttp:nohttp-gradle:0.0.11")
implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1")
implementation("org.apache.maven:maven-embedder:${versions.maven}")
implementation("org.asciidoctor:asciidoctor-gradle-jvm:3.3.2")
implementation("org.antora:gradle-antora-plugin:1.0.0")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}")
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:${versions.kotlin}")
implementation("org.springframework:spring-context")
implementation("org.springframework:spring-core")
implementation("org.springframework:spring-web")
implementation("io.spring.nohttp:nohttp-gradle:0.0.11")
implementation("org.yaml:snakeyaml:${versions.snakeYaml}")
testImplementation("org.assertj:assertj-core:${versions.assertj}")
testImplementation("org.hamcrest:hamcrest:${versions.hamcrest}")

View File

@@ -0,0 +1,155 @@
/*
* Copyright 2023-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.github.gradle.node.NodeExtension;
import io.spring.gradle.antora.GenerateAntoraYmlPlugin;
import io.spring.gradle.antora.GenerateAntoraYmlTask;
import org.antora.gradle.AntoraExtension;
import org.antora.gradle.AntoraPlugin;
import org.antora.gradle.AntoraTask;
import org.gradle.api.Project;
import org.gradle.api.file.RegularFile;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.TaskContainer;
import org.springframework.boot.build.antora.AntoraAsciidocAttributes;
import org.springframework.boot.build.antora.Extensions;
import org.springframework.boot.build.antora.GenerateAntoraPlaybook;
import org.springframework.boot.build.bom.BomExtension;
import org.springframework.boot.build.constraints.ExtractVersionConstraints;
import org.springframework.util.Assert;
/**
* Conventions that are applied in the presence of the {@link AntoraPlugin} and
* {@link GenerateAntoraYmlPlugin}.
*
* @author Phillip Webb
*/
public class AntoraConventions {
private static final String DEPENDENCIES_PATH = ":spring-boot-project:spring-boot-dependencies";
private static final String ANTORA_VERSION = "3.2.0-alpha.4";
private static final String ANTORA_SOURCE_DIR = "src/docs/antora";
private static final List<String> NAV_FILES = List.of("nav.adoc", "local-nav.adoc");
void apply(Project project) {
project.getPlugins().withType(AntoraPlugin.class, (antoraPlugin) -> apply(project, antoraPlugin));
}
private void apply(Project project, AntoraPlugin antoraPlugin) {
ExtractVersionConstraints dependencyVersionsTask = addDependencyVersionsTask(project);
project.getPlugins().apply(GenerateAntoraYmlPlugin.class);
TaskContainer tasks = project.getTasks();
GenerateAntoraPlaybook generateAntoraPlaybookTask = tasks.create("generateAntoraPlaybook",
GenerateAntoraPlaybook.class);
tasks.withType(GenerateAntoraYmlTask.class, (generateAntoraYmlTask) -> configureGenerateAntoraYmlTask(project,
generateAntoraYmlTask, dependencyVersionsTask));
tasks.withType(AntoraTask.class,
(antoraTask) -> configureAntoraTask(project, antoraTask, generateAntoraPlaybookTask));
project.getExtensions().configure(AntoraExtension.class, (antoraExtension) -> {
RegularFileProperty outputFile = generateAntoraPlaybookTask.getOutputFile();
configureAntoraExtension(project, antoraExtension, outputFile);
});
project.getExtensions()
.configure(NodeExtension.class, (nodeExtension) -> configureNodeExtension(project, nodeExtension));
}
private ExtractVersionConstraints addDependencyVersionsTask(Project project) {
return project.getTasks()
.create("dependencyVersions", ExtractVersionConstraints.class,
(task) -> task.enforcedPlatform(DEPENDENCIES_PATH));
}
private void configureGenerateAntoraYmlTask(Project project, GenerateAntoraYmlTask generateAntoraYmlTask,
ExtractVersionConstraints dependencyVersionsTask) {
generateAntoraYmlTask.getOutputs().doNotCacheIf("getAsciidocAttributes() changes output", (task) -> true);
generateAntoraYmlTask.dependsOn(dependencyVersionsTask);
generateAntoraYmlTask.setProperty("componentName", "spring-boot");
generateAntoraYmlTask.setProperty("outputFile",
new File(project.getBuildDir(), "generated/docs/antora-yml/antora.yml"));
generateAntoraYmlTask.setProperty("yml", getDefaultYml(project));
generateAntoraYmlTask.doFirst((task) -> generateAntoraYmlTask.getAsciidocAttributes()
.putAll(project.provider(() -> getAsciidocAttributes(project, dependencyVersionsTask))));
}
private Map<String, ?> getDefaultYml(Project project) {
String navFile = null;
for (String candidate : NAV_FILES) {
if (project.file(ANTORA_SOURCE_DIR + "/" + candidate).exists()) {
Assert.state(navFile == null, "Multiple nav files found");
navFile = candidate;
}
}
Map<String, Object> defaultYml = new LinkedHashMap<>();
defaultYml.put("title", "Spring Boot");
if (navFile != null) {
defaultYml.put("nav", List.of(navFile));
}
return defaultYml;
}
private Map<String, String> getAsciidocAttributes(Project project,
ExtractVersionConstraints dependencyVersionsTask) {
BomExtension bom = (BomExtension) project.project(DEPENDENCIES_PATH).getExtensions().getByName("bom");
Map<String, String> dependencyVersions = dependencyVersionsTask.getVersionConstraints();
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(project, bom, dependencyVersions);
return attributes.get();
}
private void configureAntoraTask(Project project, AntoraTask antoraTask,
GenerateAntoraPlaybook generateAntoraPlaybookTask) {
antoraTask.setGroup("Documentation");
antoraTask.getDependsOn().add(generateAntoraPlaybookTask);
project.getPlugins()
.withType(JavaBasePlugin.class,
(javaBasePlugin) -> project.getTasks()
.getByName(JavaBasePlugin.CHECK_TASK_NAME)
.dependsOn(antoraTask));
}
private void configureAntoraExtension(Project project, AntoraExtension antoraExtension,
Provider<RegularFile> playbook) {
antoraExtension.getVersion().convention(ANTORA_VERSION);
antoraExtension.getPackages().convention(Extensions.packages());
antoraExtension.getPlaybook().convention(playbook.map(RegularFile::getAsFile));
if (project.getGradle().getStartParameter().getLogLevel() != LogLevel.DEBUG) {
antoraExtension.getOptions().add("--quiet");
}
else {
antoraExtension.getOptions().addAll("--log-level", "all");
}
}
private void configureNodeExtension(Project project, NodeExtension nodeExtension) {
File buildDir = project.getBuildDir();
nodeExtension.getWorkDir().set(buildDir.toPath().resolve(".gradle/nodejs").toFile());
nodeExtension.getNpmWorkDir().set(buildDir.toPath().resolve(".gradle/npm").toFile());
}
}

View File

@@ -1,159 +0,0 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask;
import org.asciidoctor.gradle.jvm.AsciidoctorJExtension;
import org.asciidoctor.gradle.jvm.AsciidoctorJPlugin;
import org.asciidoctor.gradle.jvm.AsciidoctorTask;
import org.gradle.api.JavaVersion;
import org.gradle.api.Project;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.Sync;
import org.springframework.boot.build.artifacts.ArtifactRelease;
import org.springframework.util.StringUtils;
/**
* Conventions that are applied in the presence of the {@link AsciidoctorJPlugin}. When
* the plugin is applied:
*
* <ul>
* <li>All warnings are made fatal.
* <li>The version of AsciidoctorJ is upgraded to 2.4.3.
* <li>An {@code asciidoctorExtensions} configuration is created.
* <li>For each {@link AsciidoctorTask} (HTML only):
* <ul>
* <li>A task is created to sync the documentation resources to its output directory.
* <li>{@code doctype} {@link AsciidoctorTask#options(Map) option} is configured.
* <li>The {@code backend} is configured.
* </ul>
* <li>For each {@link AbstractAsciidoctorTask} (HTML and PDF):
* <ul>
* <li>{@link AsciidoctorTask#attributes(Map) Attributes} are configured to enable
* warnings for references to missing attributes, the GitHub tag, the Artifactory repo for
* the current version, etc.
* <li>{@link AbstractAsciidoctorTask#baseDirFollowsSourceDir() baseDirFollowsSourceDir()}
* is enabled.
* <li>{@code asciidoctorExtensions} is added to the task's configurations.
* </ul>
* </ul>
*
* @author Andy Wilkinson
* @author Scott Frederick
*/
class AsciidoctorConventions {
private static final String ASCIIDOCTORJ_VERSION = "2.4.3";
private static final String EXTENSIONS_CONFIGURATION_NAME = "asciidoctorExtensions";
void apply(Project project) {
project.getPlugins().withType(AsciidoctorJPlugin.class, (asciidoctorPlugin) -> {
makeAllWarningsFatal(project);
upgradeAsciidoctorJVersion(project);
createAsciidoctorExtensionsConfiguration(project);
project.getTasks()
.withType(AbstractAsciidoctorTask.class,
(asciidoctorTask) -> configureAsciidoctorTask(project, asciidoctorTask));
});
}
private void makeAllWarningsFatal(Project project) {
project.getExtensions().getByType(AsciidoctorJExtension.class).fatalWarnings(".*");
}
private void upgradeAsciidoctorJVersion(Project project) {
project.getExtensions().getByType(AsciidoctorJExtension.class).setVersion(ASCIIDOCTORJ_VERSION);
}
private void createAsciidoctorExtensionsConfiguration(Project project) {
project.getConfigurations().create(EXTENSIONS_CONFIGURATION_NAME, (configuration) -> {
project.getConfigurations()
.matching((candidate) -> "dependencyManagement".equals(candidate.getName()))
.all(configuration::extendsFrom);
configuration.getDependencies()
.add(project.getDependencies()
.create("io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.5"));
configuration.getDependencies()
.add(project.getDependencies().create("org.asciidoctor:asciidoctorj-pdf:1.5.3"));
});
}
private void configureAsciidoctorTask(Project project, AbstractAsciidoctorTask asciidoctorTask) {
asciidoctorTask.configurations(EXTENSIONS_CONFIGURATION_NAME);
configureCommonAttributes(project, asciidoctorTask);
configureOptions(asciidoctorTask);
configureForkOptions(asciidoctorTask);
asciidoctorTask.baseDirFollowsSourceDir();
createSyncDocumentationSourceTask(project, asciidoctorTask);
if (asciidoctorTask instanceof AsciidoctorTask task) {
boolean pdf = task.getName().toLowerCase().contains("pdf");
String backend = (!pdf) ? "spring-html" : "spring-pdf";
task.outputOptions((outputOptions) -> outputOptions.backends(backend));
}
}
private void configureCommonAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
ArtifactRelease artifacts = ArtifactRelease.forProject(project);
Map<String, Object> attributes = new HashMap<>();
attributes.put("attribute-missing", "warn");
attributes.put("github-tag", determineGitHubTag(project));
attributes.put("artifact-release-type", artifacts.getType());
attributes.put("artifact-download-repo", artifacts.getDownloadRepo());
attributes.put("revnumber", null);
asciidoctorTask.attributes(attributes);
}
// See https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/597
private void configureForkOptions(AbstractAsciidoctorTask asciidoctorTask) {
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
asciidoctorTask.forkOptions((options) -> options.jvmArgs("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED",
"--add-opens", "java.base/java.io=ALL-UNNAMED"));
}
}
private String determineGitHubTag(Project project) {
String version = "v" + project.getVersion();
return (version.endsWith("-SNAPSHOT")) ? "main" : version;
}
private void configureOptions(AbstractAsciidoctorTask asciidoctorTask) {
asciidoctorTask.options(Collections.singletonMap("doctype", "book"));
}
private Sync createSyncDocumentationSourceTask(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Sync syncDocumentationSource = project.getTasks()
.create("syncDocumentationSourceFor" + StringUtils.capitalize(asciidoctorTask.getName()), Sync.class);
File syncedSource = new File(project.getBuildDir(), "docs/src/" + asciidoctorTask.getName());
syncDocumentationSource.setDestinationDir(syncedSource);
syncDocumentationSource.from("src/docs/");
asciidoctorTask.dependsOn(syncDocumentationSource);
asciidoctorTask.getInputs()
.dir(syncedSource)
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("synced source");
asciidoctorTask.setSourceDir(project.relativePath(new File(syncedSource, "asciidoc/")));
return syncDocumentationSource;
}
}

View File

@@ -16,7 +16,7 @@
package org.springframework.boot.build;
import org.asciidoctor.gradle.jvm.AsciidoctorJPlugin;
import org.antora.gradle.AntoraPlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaBasePlugin;
@@ -32,8 +32,8 @@ import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
* When the {@link MavenPublishPlugin} is applied, the conventions in
* {@link MavenPublishingConventions} are applied.
*
* When the {@link AsciidoctorJPlugin} is applied, the conventions in
* {@link AsciidoctorConventions} are applied.
* When the {@link AntoraPlugin} is applied, the conventions in {@link AntoraConventions}
* are applied.
*
* @author Andy Wilkinson
* @author Christoph Dreis
@@ -46,7 +46,7 @@ public class ConventionsPlugin implements Plugin<Project> {
new NoHttpConventions().apply(project);
new JavaConventions().apply(project);
new MavenPublishingConventions().apply(project);
new AsciidoctorConventions().apply(project);
new AntoraConventions().apply(project);
new KotlinConventions().apply(project);
new WarConventions().apply(project);
new EclipseConventions().apply(project);

View File

@@ -0,0 +1,162 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.antora;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.gradle.api.Project;
import org.springframework.boot.build.artifacts.ArtifactRelease;
import org.springframework.boot.build.bom.BomExtension;
import org.springframework.boot.build.bom.Library;
import org.springframework.util.Assert;
/**
* Generates Asciidoctor attributes for use with Antora.
*
* @author Phillip Webb
*/
public class AntoraAsciidocAttributes {
private static final String DASH_SNAPSHOT = "-SNAPSHOT";
private final String version;
private final boolean latestVersion;
private final ArtifactRelease artifactRelease;
private final List<Library> libraries;
private final Map<String, String> dependencyVersions;
private final Map<String, ?> projectProperties;
public AntoraAsciidocAttributes(Project project, BomExtension dependencyBom,
Map<String, String> dependencyVersions) {
this.version = String.valueOf(project.getVersion());
this.latestVersion = Boolean.valueOf(String.valueOf(project.findProperty("latestVersion")));
this.artifactRelease = ArtifactRelease.forProject(project);
this.libraries = dependencyBom.getLibraries();
this.dependencyVersions = dependencyVersions;
this.projectProperties = project.getProperties();
}
AntoraAsciidocAttributes(String version, boolean latestVersion, List<Library> libraries,
Map<String, String> dependencyVersions, Map<String, ?> projectProperties) {
this.version = version;
this.latestVersion = latestVersion;
this.artifactRelease = ArtifactRelease.forVersion(version);
this.libraries = (libraries != null) ? libraries : Collections.emptyList();
this.dependencyVersions = (dependencyVersions != null) ? dependencyVersions : Collections.emptyMap();
this.projectProperties = (projectProperties != null) ? projectProperties : Collections.emptyMap();
}
public Map<String, String> get() {
Map<String, String> attributes = new LinkedHashMap<>();
addGitHubAttributes(attributes);
addVersionAttributes(attributes);
addUrlArtifactRepository(attributes);
addUrlLibraryLinkAttributes(attributes);
addPropertyAttributes(attributes);
return attributes;
}
private void addGitHubAttributes(Map<String, String> attributes) {
attributes.put("github-repo", "spring-projects/spring-boot");
attributes.put("github-ref", determineGitHubRef());
}
private String determineGitHubRef() {
int snapshotIndex = this.version.lastIndexOf(DASH_SNAPSHOT);
if (snapshotIndex == -1) {
return "v" + this.version;
}
if (this.latestVersion) {
return "main";
}
String versionRoot = this.version.substring(0, snapshotIndex);
int lastDot = versionRoot.lastIndexOf('.');
return versionRoot.substring(0, lastDot) + ".x";
}
private void addVersionAttributes(Map<String, String> attributes) {
this.libraries.forEach((library) -> {
String name = "version-" + library.getLinkRootName();
String value = library.getVersion().toString();
attributes.put(name, value);
});
attributes.put("version-native-build-tools", (String) this.projectProperties.get("nativeBuildToolsVersion"));
attributes.put("version-graal", (String) this.projectProperties.get("graalVersion"));
addSpringDataDependencyVersion(attributes, "spring-data-commons");
addSpringDataDependencyVersion(attributes, "spring-data-couchbase");
addSpringDataDependencyVersion(attributes, "spring-data-elasticsearch");
addSpringDataDependencyVersion(attributes, "spring-data-jdbc");
addSpringDataDependencyVersion(attributes, "spring-data-jpa");
addSpringDataDependencyVersion(attributes, "spring-data-mongodb");
addSpringDataDependencyVersion(attributes, "spring-data-neo4j");
addSpringDataDependencyVersion(attributes, "spring-data-r2dbc");
addSpringDataDependencyVersion(attributes, "spring-data-rest", "spring-data-rest-core");
}
private void addSpringDataDependencyVersion(Map<String, String> attributes, String artifactId) {
addSpringDataDependencyVersion(attributes, artifactId, artifactId);
}
private void addSpringDataDependencyVersion(Map<String, String> attributes, String name, String artifactId) {
String version = this.dependencyVersions.get("org.springframework.data:" + artifactId);
Assert.notNull(version, () -> "No version found for Spring Data artificat " + artifactId);
attributes.put("version-" + name, version);
}
private void addUrlArtifactRepository(Map<String, String> attributes) {
attributes.put("url-artifact-repository", this.artifactRelease.getDownloadRepo());
}
private void addUrlLibraryLinkAttributes(Map<String, String> attributes) {
this.libraries.forEach((library) -> {
String prefix = "url-" + library.getLinkRootName() + "-";
library.getLinks().forEach((name, link) -> attributes.put(prefix + name, link));
});
}
private void addPropertyAttributes(Map<String, String> attributes) {
Properties properties = new Properties() {
@Override
public synchronized Object put(Object key, Object value) {
// Put directly because order is important for us
return attributes.put(key.toString(), value.toString());
}
};
try (InputStream in = getClass().getResourceAsStream("antora-asciidoc-attributes.properties")) {
properties.load(in);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.antora;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* Antora and Asciidoc extensions used by Spring Boot.
*
* @author Phillip Webb
*/
public final class Extensions {
private static final String ROOT_COMPONENT_EXTENSION = "@springio/antora-extensions/root-component-extension";
private static final List<Extension> antora;
static {
List<Extension> extensions = new ArrayList<>();
extensions.add(new Extension("@springio/antora-extensions", "1.8.2", ROOT_COMPONENT_EXTENSION,
"@springio/antora-extensions/static-page-extension"));
extensions.add(new Extension("@springio/antora-xref-extension", "1.0.0-alpha.3"));
extensions.add(new Extension("@springio/antora-zip-contents-collector-extension", "1.0.0-alpha.2"));
antora = List.copyOf(extensions);
}
private static final List<Extension> asciidoc;
static {
List<Extension> extensions = new ArrayList<>();
extensions.add(new Extension("@asciidoctor/tabs", "1.0.0-beta.6"));
extensions
.add(new Extension("@springio/asciidoctor-extensions", "1.0.0-alpha.10", "@springio/asciidoctor-extensions",
"@springio/asciidoctor-extensions/configuration-properties-extension",
"@springio/asciidoctor-extensions/section-ids-extension"));
asciidoc = List.copyOf(extensions);
}
private static final Map<String, String> localOverrides = Collections.emptyMap();
private Extensions() {
}
public static Map<String, String> packages() {
Map<String, String> packages = new TreeMap<>();
antora.stream().forEach((extension) -> packages.put(extension.name(), extension.version()));
asciidoc.stream().forEach((extension) -> packages.put(extension.name(), extension.version()));
return Collections.unmodifiableMap(packages);
}
static List<Map<String, Object>> antora(Consumer<AntoraExtensionsConfiguration> extensions) {
AntoraExtensionsConfiguration result = new AntoraExtensionsConfiguration(
antora.stream().flatMap(Extension::names).sorted().toList());
extensions.accept(result);
return result.config();
}
static List<String> asciidoc() {
return asciidoc.stream().flatMap(Extension::names).sorted().toList();
}
private record Extension(String name, String version, String... includeNames) {
Stream<String> names() {
return (this.includeNames.length != 0) ? Arrays.stream(this.includeNames) : Stream.of(this.name);
}
}
static final class AntoraExtensionsConfiguration {
private Map<String, Map<String, Object>> extensions = new TreeMap<>();
private AntoraExtensionsConfiguration(List<String> names) {
names.forEach((name) -> this.extensions.put(name, null));
}
void xref(Consumer<Xref> xref) {
xref.accept(new Xref());
}
void zipContentsCollector(Consumer<ZipContentsCollector> zipContentsCollector) {
zipContentsCollector.accept(new ZipContentsCollector());
}
void rootComponent(Consumer<RootComponent> rootComponent) {
rootComponent.accept(new RootComponent());
}
List<Map<String, Object>> config() {
List<Map<String, Object>> config = new ArrayList<>();
Map<String, Map<String, Object>> orderedExtensions = new LinkedHashMap<>(this.extensions);
// The root component extension must be last
Map<String, Object> rootComponentConfig = orderedExtensions.remove(ROOT_COMPONENT_EXTENSION);
orderedExtensions.put(ROOT_COMPONENT_EXTENSION, rootComponentConfig);
orderedExtensions.forEach((name, customizations) -> {
Map<String, Object> extensionConfig = new LinkedHashMap<>();
extensionConfig.put("require", localOverrides.getOrDefault(name, name));
if (customizations != null) {
extensionConfig.putAll(customizations);
}
config.add(extensionConfig);
});
return List.copyOf(config);
}
abstract class Customizer {
private final String name;
Customizer(String name) {
this.name = name;
}
protected void customize(String key, Object value) {
AntoraExtensionsConfiguration.this.extensions.computeIfAbsent(this.name, (name) -> new TreeMap<>())
.put(key, value);
}
}
class Xref extends Customizer {
Xref() {
super("@springio/antora-xref-extension");
}
void stub(List<String> stub) {
if (stub != null && !stub.isEmpty()) {
customize("stub", stub);
}
}
}
class ZipContentsCollector extends Customizer {
ZipContentsCollector() {
super("@springio/antora-zip-contents-collector-extension");
}
void versionFile(String versionFile) {
customize("version_file", versionFile);
}
void locations(Path... locations) {
locations(Arrays.stream(locations).map(Path::toString).toList());
}
private void locations(List<String> locations) {
customize("locations", locations);
}
void alwaysInclude(Map<String, String> alwaysInclude) {
if (alwaysInclude != null && !alwaysInclude.isEmpty()) {
customize("always_include", List.of(new TreeMap<>(alwaysInclude)));
}
}
}
class RootComponent extends Customizer {
RootComponent() {
super(ROOT_COMPONENT_EXTENSION);
}
void name(String name) {
customize("root_component_name", name);
}
}
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.antora;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ProjectDependency;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
/**
* Task to generate a local Antora playbook.
*
* @author Phillip Webb
*/
public abstract class GenerateAntoraPlaybook extends DefaultTask {
private static final String ANTORA_SOURCE_DIR = "src/docs/antora";
private static final String GENERATED_DOCS = "build/generated/docs/";
@OutputFile
public abstract RegularFileProperty getOutputFile();
@Input
public abstract Property<String> getContentSourceConfiguration();
@Input
@Optional
public abstract ListProperty<String> getXrefStubs();
@Input
@Optional
public abstract MapProperty<String, String> getAlwaysInclude();
public GenerateAntoraPlaybook() {
setGroup("Documentation");
setDescription("Generates an Antora playbook.yml file for local use");
getOutputFile().convention(getProject().getLayout()
.getBuildDirectory()
.file("generated/docs/antora-playbook/antora-playbook.yml"));
getContentSourceConfiguration().convention("antoraContent");
}
@TaskAction
public void writePlaybookYml() throws IOException {
File file = getOutputFile().get().getAsFile();
file.getParentFile().mkdirs();
try (FileWriter out = new FileWriter(file)) {
createYaml().dump(getData(), out);
}
}
@Input
final Map<String, Object> getData() throws IOException {
Map<String, Object> data = loadPlaybookTemplate();
addExtensions(data);
addSources(data);
addDir(data);
return data;
}
@SuppressWarnings("unchecked")
private Map<String, Object> loadPlaybookTemplate() throws IOException {
try (InputStream resource = getClass().getResourceAsStream("antora-playbook-template.yml")) {
return createYaml().loadAs(resource, LinkedHashMap.class);
}
}
@SuppressWarnings("unchecked")
private void addExtensions(Map<String, Object> data) {
Map<String, Object> antora = (Map<String, Object>) data.get("antora");
antora.put("extensions", Extensions.antora((extensions) -> {
extensions.xref((xref) -> xref.stub(getXrefStubs().getOrElse(Collections.emptyList())));
extensions.zipContentsCollector((zipContentsCollector) -> {
zipContentsCollector.versionFile("gradle.properties");
String locationName = getProject().getName() + "-${version}-${name}-${classifier}.zip";
Path antoraContent = getRelativeProjectPath()
.resolve(GENERATED_DOCS + "antora-content/" + locationName);
Path antoraDepenencies = getRelativeProjectPath()
.resolve(GENERATED_DOCS + "antora-dependencies-content/" + locationName);
zipContentsCollector.locations(antoraContent, antoraDepenencies);
zipContentsCollector.alwaysInclude(getAlwaysInclude().getOrNull());
});
extensions.rootComponent((rootComponent) -> rootComponent.name("spring-boot"));
}));
Map<String, Object> asciidoc = (Map<String, Object>) data.get("asciidoc");
asciidoc.put("extensions", Extensions.asciidoc());
}
private void addSources(Map<String, Object> data) {
List<Map<String, Object>> contentSources = getList(data, "content.sources");
contentSources.add(createContentSource());
}
private Map<String, Object> createContentSource() {
Map<String, Object> source = new LinkedHashMap<>();
Path playbookPath = getOutputFile().get().getAsFile().toPath().getParent();
Path antoraSrc = getProjectPath(getProject()).resolve(ANTORA_SOURCE_DIR);
StringBuilder url = new StringBuilder(".");
relativizeFromRootProject(playbookPath).normalize().forEach((path) -> url.append("/.."));
source.put("url", url.toString());
source.put("branches", "HEAD");
source.put("version", getProject().getVersion().toString());
Set<String> startPaths = new LinkedHashSet<>();
addAntoraContentStartPaths(startPaths);
startPaths.add(relativizeFromRootProject(antoraSrc).toString());
source.put("start_paths", startPaths.stream().toList());
return source;
}
private void addAntoraContentStartPaths(Set<String> startPaths) {
Configuration configuration = getProject().getConfigurations().findByName("antoraContent");
if (configuration != null) {
for (ProjectDependency dependency : configuration.getAllDependencies().withType(ProjectDependency.class)) {
Path path = dependency.getDependencyProject().getProjectDir().toPath();
startPaths.add(relativizeFromRootProject(path).resolve(ANTORA_SOURCE_DIR).toString());
}
}
}
private void addDir(Map<String, Object> data) {
Path playbookDir = toRealPath(getOutputFile().get().getAsFile().toPath()).getParent();
Path outputDir = toRealPath(getProject().getBuildDir().toPath().resolve("site"));
data.put("output", Map.of("dir", "./" + playbookDir.relativize(outputDir).toString()));
}
@SuppressWarnings("unchecked")
private <T> List<T> getList(Map<String, Object> data, String location) {
return (List<T>) get(data, location);
}
@SuppressWarnings("unchecked")
private Object get(Map<String, Object> data, String location) {
Object result = data;
String[] keys = location.split("\\.");
for (String key : keys) {
result = ((Map<String, Object>) result).get(key);
}
return result;
}
private Yaml createYaml() {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setPrettyFlow(true);
return new Yaml(options);
}
private Path getRelativeProjectPath() {
return relativizeFromRootProject(getProjectPath(getProject()));
}
private Path relativizeFromRootProject(Path subPath) {
Path rootProjectPath = getProjectPath(getProject().getRootProject());
return rootProjectPath.relativize(subPath).normalize();
}
private Path getProjectPath(Project project) {
return toRealPath(project.getProjectDir().toPath());
}
private Path toRealPath(Path path) {
try {
return Files.exists(path) ? path.toRealPath() : path;
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,24 +26,18 @@ import org.gradle.api.Project;
*/
public final class ArtifactRelease {
private static final String SNAPSHOT = "snapshot";
private static final String MILESTONE = "milestone";
private static final String RELEASE = "release";
private static final String SPRING_REPO = "https://repo.spring.io/%s";
private static final String MAVEN_REPO = "https://repo.maven.apache.org/maven2";
private final String type;
private final Type type;
private ArtifactRelease(String type) {
private ArtifactRelease(Type type) {
this.type = type;
}
public String getType() {
return this.type;
return this.type.toString().toLowerCase();
}
public String getDownloadRepo() {
@@ -51,24 +45,34 @@ public final class ArtifactRelease {
}
public boolean isRelease() {
return RELEASE.equals(this.type);
return this.type == Type.RELEASE;
}
public static ArtifactRelease forProject(Project project) {
return new ArtifactRelease(determineReleaseType(project));
return forVersion(project.getVersion().toString());
}
private static String determineReleaseType(Project project) {
String version = project.getVersion().toString();
int modifierIndex = version.lastIndexOf('-');
if (modifierIndex == -1) {
return RELEASE;
public static ArtifactRelease forVersion(String version) {
return new ArtifactRelease(Type.forVersion(version));
}
enum Type {
SNAPSHOT, MILESTONE, RELEASE;
static Type forVersion(String version) {
int modifierIndex = version.lastIndexOf('-');
if (modifierIndex == -1) {
return RELEASE;
}
String type = version.substring(modifierIndex + 1);
if (type.startsWith("M") || type.startsWith("RC")) {
return MILESTONE;
}
return SNAPSHOT;
}
String type = version.substring(modifierIndex + 1);
if (type.startsWith("M") || type.startsWith("RC")) {
return MILESTONE;
}
return SNAPSHOT;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,9 +89,9 @@ public class DocumentAutoConfigurationClasses extends DefaultTask {
for (AutoConfigurationClass autoConfigurationClass : autoConfigurationClasses.classes) {
writer.println();
writer.printf("| {spring-boot-code}/spring-boot-project/%s/src/main/java/%s.java[`%s`]%n",
writer.printf("| {code-spring-boot}/spring-boot-project/%s/src/main/java/%s.java[`%s`]%n",
autoConfigurationClasses.module, autoConfigurationClass.path, autoConfigurationClass.name);
writer.printf("| {spring-boot-api}/%s.html[javadoc]%n", autoConfigurationClass.path);
writer.printf("| xref:api:java/%s.html[javadoc]%n", autoConfigurationClass.path);
}
writer.println("|===");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.artifacts.ComponentMetadataDetails;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.DependencyConstraint;
import org.gradle.api.artifacts.DependencyConstraintMetadata;
import org.gradle.api.artifacts.dsl.DependencyHandler;
@@ -64,10 +65,9 @@ public class ExtractVersionConstraints extends DefaultTask {
}
public void enforcedPlatform(String projectPath) {
this.configuration.getDependencies()
.add(getProject().getDependencies()
.enforcedPlatform(
getProject().getDependencies().project(Collections.singletonMap("path", projectPath))));
Dependency project = getProject().getDependencies().project(Map.of("path", projectPath));
Dependency dependency = getProject().getDependencies().enforcedPlatform(project);
this.configuration.getDependencies().add(dependency);
this.projectPaths.add(projectPath);
}
@@ -104,9 +104,8 @@ public class ExtractVersionConstraints extends DefaultTask {
}
private void extractVersionProperties(String projectPath) {
Object bom = getProject().project(projectPath).getExtensions().getByName("bom");
BomExtension bomExtension = (BomExtension) bom;
for (Library lib : bomExtension.getLibraries()) {
BomExtension bom = (BomExtension) getProject().project(projectPath).getExtensions().getByName("bom");
for (Library lib : bom.getLibraries()) {
String versionProperty = lib.getVersionProperty();
if (versionProperty != null) {
this.versionProperties.add(new VersionProperty(lib.getName(), versionProperty));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -102,11 +102,7 @@ class Snippets {
private void writeAsciidoc(Path outputDirectory, Snippet snippet, Asciidoc asciidoc) throws IOException {
String[] parts = (snippet.getAnchor()).split("\\.");
Path path = outputDirectory;
for (int i = 0; i < parts.length; i++) {
String name = (i < parts.length - 1) ? parts[i] : parts[i] + ".adoc";
path = path.resolve(name);
}
Path path = outputDirectory.resolve(parts[parts.length - 1] + ".adoc");
createDirectory(path.getParent());
Files.deleteIfExists(path);
try (OutputStream outputStream = Files.newOutputStream(path)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,7 +50,7 @@ public class DocumentDevtoolsPropertyDefaults extends DefaultTask {
this.outputFile = getProject().getObjects().fileProperty();
this.outputFile.convention(getProject().getLayout()
.getBuildDirectory()
.file("docs/generated/using/devtools-property-defaults.adoc"));
.file("generated/docs/using/devtools-property-defaults.adoc"));
Map<String, String> dependency = new HashMap<>();
dependency.put("path", ":spring-boot-project:spring-boot-devtools");
dependency.put("configuration", "propertyDefaults");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,7 +92,7 @@ public class DocumentPluginGoals extends DefaultTask {
writer.println("| Goal | Description");
writer.println();
for (Mojo mojo : plugin.getMojos()) {
writer.printf("| <<%s,%s:%s>>%n", goalSectionId(mojo), plugin.getGoalPrefix(), mojo.getGoal());
writer.printf("| xref:%s[%s:%s]%n", goalSectionId(mojo, false), plugin.getGoalPrefix(), mojo.getGoal());
writer.printf("| %s%n", mojo.getDescription());
writer.println();
}
@@ -102,11 +102,9 @@ public class DocumentPluginGoals extends DefaultTask {
private void documentMojo(Plugin plugin, Mojo mojo) throws IOException {
try (PrintWriter writer = new PrintWriter(new FileWriter(new File(this.outputDir, mojo.getGoal() + ".adoc")))) {
String sectionId = goalSectionId(mojo);
writer.println();
writer.println();
String sectionId = goalSectionId(mojo, true);
writer.printf("[[%s]]%n", sectionId);
writer.printf("= `%s:%s`%n", plugin.getGoalPrefix(), mojo.getGoal());
writer.printf("= `%s:%s`%n%n", plugin.getGoalPrefix(), mojo.getGoal());
writer.printf("`%s:%s:%s`%n", plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion());
writer.println();
writer.println(mojo.getDescription());
@@ -114,37 +112,43 @@ public class DocumentPluginGoals extends DefaultTask {
List<Parameter> requiredParameters = parameters.stream().filter(Parameter::isRequired).toList();
String detailsSectionId = sectionId + ".parameter-details";
if (!requiredParameters.isEmpty()) {
writer.println();
writer.println();
writer.println();
writer.printf("[[%s.required-parameters]]%n", sectionId);
writer.println("== Required parameters");
writer.println();
writeParametersTable(writer, detailsSectionId, requiredParameters);
}
List<Parameter> optionalParameters = parameters.stream()
.filter((parameter) -> !parameter.isRequired())
.toList();
if (!optionalParameters.isEmpty()) {
writer.println();
writer.println();
writer.println();
writer.printf("[[%s.optional-parameters]]%n", sectionId);
writer.println("== Optional parameters");
writer.println();
writeParametersTable(writer, detailsSectionId, optionalParameters);
}
writer.println();
writer.println();
writer.println();
writer.printf("[[%s]]%n", detailsSectionId);
writer.println("== Parameter details");
writer.println();
writeParameterDetails(writer, parameters, detailsSectionId);
}
}
private String goalSectionId(Mojo mojo) {
private String goalSectionId(Mojo mojo, boolean innerReference) {
String goalSection = this.goalSections.get(mojo.getGoal());
if (goalSection == null) {
throw new IllegalStateException("Goal '" + mojo.getGoal() + "' has not be assigned to a section");
}
String sectionId = goalSection + "." + mojo.getGoal() + "-goal";
return sectionId;
return (!innerReference) ? goalSection + "#" + sectionId : sectionId;
}
private void writeParametersTable(PrintWriter writer, String detailsSectionId, List<Parameter> parameters) {
@@ -236,10 +240,10 @@ public class DocumentPluginGoals extends DefaultTask {
private String typeNameToJavadocLink(String shortName, String name) {
if (name.startsWith("org.springframework.boot.maven")) {
return "{spring-boot-docs}/maven-plugin/api/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
return "xref:maven-plugin:api/java/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
}
if (name.startsWith("org.springframework.boot")) {
return "{spring-boot-docs}/api/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
return "xref:api:java/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
}
return shortName;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -158,7 +158,7 @@ public class MavenPluginPlugin implements Plugin<Project> {
DocumentPluginGoals task = project.getTasks().create("documentPluginGoals", DocumentPluginGoals.class);
File pluginXml = new File(generatePluginDescriptorTask.getOutputs().getFiles().getSingleFile(), "plugin.xml");
task.setPluginXml(pluginXml);
task.setOutputDir(new File(project.getBuildDir(), "docs/generated/goals/"));
task.setOutputDir(new File(project.getBuildDir(), "generated/docs/maven-plugin-goals/"));
task.dependsOn(generatePluginDescriptorTask);
}

View File

@@ -0,0 +1,80 @@
# === INCLUDE-CODE LOCATIONS ===
include-java=ROOT:example$java/org/springframework/boot/docs
include-kotlin= ROOT:example$kotlin/org/springframework/boot/docs
# === URLs ===
url-ant-docs=https://ant.apache.org/manual
url-buildpacks-docs=https://buildpacks.io/docs
url-dynatrace-docs=https://docs.dynatrace.com/docs
url-dynatrace-docs-shortlink={url-dynatrace-docs}/shortlink
url-github-raw=https://raw.githubusercontent.com/{github-repo}/{github-ref}
url-github-issues=https://github.com/{github-repo}/issues
url-github-wiki=https://github.com/{github-repo}/wiki
url-github=https://github.com/{github-repo}
url-graal-docs=https://www.graalvm.org/{version-graal}/reference-manual
url-graal-docs-native-image={url-graal-docs}/native-image
url-gradle-docs=https://docs.gradle.org/current/userguide
url-gradle-docs-application-plugin={url-gradle-docs}/application_plugin.html
url-gradle-docs-groovy-plugin={url-gradle-docs}/groovy_plugin.html
url-gradle-docs-java-plugin={url-gradle-docs}/java_plugin.html
url-gradle-docs-war-plugin={url-gradle-docs}/war_plugin.html
url-gradle-dsl=https://docs.gradle.org/current/dsl
url-gradle-javadoc=https://docs.gradle.org/current/javadoc
url-kotlin-docs-kotlin-plugin={url-kotlin-docs}/using-gradle.html
url-micrometer-docs-concepts={url-micrometer-docs}/concepts
url-micrometer-docs-implementations={url-micrometer-docs}/implementations
url-download-liberica-nik=https://bell-sw.com/pages/downloads/native-image-kit/#/nik-22-17
url-native-build-tools-docs=https://graalvm.github.io/native-build-tools/{version-native-build-tools}
url-native-build-tools-docs-gradle-plugin={url-native-build-tools-docs}/gradle-plugin.html
url-native-build-tools-docs-maven-plugin={url-native-build-tools-docs}/maven-plugin.html
url-paketo-docs=https://paketo.io/docs
url-paketo-docs-java-buildpack={url-paketo-docs}/buildpacks/language-family-buildpacks/java
url-spring-boot-for-apache-geode-docs=https://docs.spring.io/spring-boot-data-geode-build/2.0.x/reference/html5
url-spring-boot-for-apache-geode-site=https://github.com/spring-projects/spring-boot-data-geode
url-spring-data-cassandra-site=https://spring.io/projects/spring-data-cassandra
url-spring-data-commons-javadoc=https://docs.spring.io/spring-data/commons/docs/{version-spring-data-commons}/api
url-spring-data-couchbase-docs=https://docs.spring.io/spring-data/couchbase/reference/{version-spring-data-couchbase}
url-spring-data-couchbase-site=https://spring.io/projects/spring-data-couchbase
url-spring-data-elasticsearch-docs=https://docs.spring.io/spring-data/elasticsearch/reference/{version-spring-data-elasticsearch}
url-spring-data-elasticsearch-site=https://spring.io/projects/spring-data-elasticsearch
url-spring-data-envers-site=https://spring.io/projects/spring-data-envers
url-spring-data-gemfire-site=https://spring.io/projects/spring-data-gemfire
url-spring-data-geode-site=https://spring.io/projects/spring-data-geode
url-spring-data-jdbc-docs=https://docs.spring.io/spring-data/relational/reference/{version-spring-data-jdbc}
url-spring-data-jpa-javadoc=https://docs.spring.io/spring-data/jpa/docs/{version-spring-data-jpa}/api
url-spring-data-jpa-site=https://spring.io/projects/spring-jpa
url-spring-data-jpa-docs=https://docs.spring.io/spring-data/jpa/reference/{version-spring-data-jpa}
url-spring-data-ldap-site=https://spring.io/projects/spring-data-ldap
url-spring-data-mongodb-javadoc=https://docs.spring.io/spring-data/mongodb/docs/{version-spring-data-mongodb}/api
url-spring-data-mongodb-site=https://spring.io/projects/spring-data-mongodb
url-spring-data-mongodb-docs=https://docs.spring.io/spring-data/mongodb/reference/{version-spring-data-mongodb}
url-spring-data-neo4j-docs=https://docs.spring.io/spring-data/neo4j/reference/{version-spring-data-neo4j}
url-spring-data-neo4j-site=https://spring.io/projects/spring-data-neo4j
url-spring-data-r2dbc-javadoc=https://docs.spring.io/spring-data/r2dbc/docs/{version-spring-data-r2dbc}/api
url-spring-data-r2dbc-docs=https://docs.spring.io/spring-data/relational/reference/{version-spring-data-r2dbc}
url-spring-data-redis-site=https://spring.io/projects/spring-data-redis
url-spring-data-rest-javadoc=https://docs.spring.io/spring-data/rest/docs/{version-spring-data-rest}/api
url-spring-data-site=https://spring.io/projects/spring-data
# === API References ===
apiref-gradle-plugin-boot-build-image=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.html
apiref-gradle-plugin-boot-jar=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootJar.html
apiref-gradle-plugin-boot-run=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/run/BootRun.html
apiref-gradle-plugin-boot-war=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootWar.html
apiref-gradle-plugin-boot-build-info=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.html
apiref-openjdk=https://docs.oracle.com/en/java/javase/17/docs/api
# === Code Links ===
code-spring-boot=https://github.com/{github-repo}/tree/{github-ref}
code-spring-boot-src={code-spring-boot}/spring-boot-project/spring-boot/src/main/java/org/springframework/boot
code-spring-boot-actuator-autoconfigure-src={code-spring-boot}/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure
code-spring-boot-actuator-src={code-spring-boot}/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate
code-spring-boot-autoconfigure-src={code-spring-boot}/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure
code-spring-boot-devtools-src={code-spring-boot}/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools
code-spring-boot-test-autoconfigure-src={code-spring-boot}/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure
code-spring-boot-latest=https://github.com/{github-repo}/tree/main

View File

@@ -0,0 +1,27 @@
antora:
extensions:
site:
title: Spring Boot
content:
sources: []
asciidoc:
sourcemap: true
attributes:
chomp: all
hide-uri-scheme: '@'
page-pagination: ''
page-stackoverflow-url: https://stackoverflow.com/tags/spring-boot
tabs-sync-option: '@'
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
- '@springio/asciidoctor-extensions/configuration-properties-extension'
- '@springio/asciidoctor-extensions/section-ids-extension'
urls:
latest_version_segment: ''
runtime:
log:
failure_level: warn
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.11/ui-bundle.zip

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.antora;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
import org.springframework.boot.build.bom.Library;
import org.springframework.boot.build.bom.Library.Group;
import org.springframework.boot.build.bom.Library.LibraryVersion;
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
import org.springframework.boot.build.bom.Library.VersionAlignment;
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AntoraAsciidocAttributes}.
*
* @author Phillip Webb
*/
class AntoraAsciidocAttributesTests {
@Test
void githubRefWhenReleasedVersionIsTag() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("github-ref", "v1.2.3");
}
@Test
void githubRefWhenLatestSnapshotVersionIsMainBranch() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", true, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("github-ref", "main");
}
@Test
void githubRefWhenOlderSnapshotVersionIsBranch() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", false, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("github-ref", "1.2.x");
}
@Test
void githubRefWhenOlderSnapshotHotFixVersionIsBranch() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3.1-SNAPSHOT", false, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("github-ref", "1.2.3.x");
}
@Test
void versionReferenceFromLibrary() {
Library library = mockLibrary(Collections.emptyMap());
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3.1-SNAPSHOT", false, List.of(library),
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("version-spring-framework", "1.2.3");
}
@Test
void versionReferenceFromSpringDataDependencyVersion() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("version-spring-data-mongodb", "1.2.3");
}
@Test
void versionNativeBuildTools() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
mockDependencyVersions(), Map.of("nativeBuildToolsVersion", "3.4.5"));
assertThat(attributes.get()).containsEntry("version-native-build-tools", "3.4.5");
}
@Test
void urlArtifactReposiroryWhenRelease() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("url-artifact-repository", "https://repo.maven.apache.org/maven2");
}
@Test
void urlArtifactReposiroryWhenMilestone() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-M1", true, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("url-artifact-repository", "https://repo.spring.io/milestone");
}
@Test
void urlArtifactReposiroryWhenSnapshot() {
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", true, null,
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("url-artifact-repository", "https://repo.spring.io/snapshot");
}
@Test
void urlLinksFromLibrary() {
Map<String, Function<LibraryVersion, String>> links = new LinkedHashMap<>();
links.put("site", (version) -> "https://example.com/site/" + version);
links.put("docs", (version) -> "https://example.com/docs/" + version);
Library library = mockLibrary(links);
AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3.1-SNAPSHOT", false, List.of(library),
mockDependencyVersions(), null);
assertThat(attributes.get()).containsEntry("url-spring-framework-site", "https://example.com/site/1.2.3")
.containsEntry("url-spring-framework-docs", "https://example.com/docs/1.2.3");
}
@Test
void linksFromProperties() {
Map<String, String> attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", true, null,
mockDependencyVersions(), null)
.get();
assertThat(attributes).containsEntry("include-java", "ROOT:example$java/org/springframework/boot/docs");
assertThat(attributes).containsEntry("url-spring-data-cassandra-site",
"https://spring.io/projects/spring-data-cassandra");
List<String> keys = new ArrayList<>(attributes.keySet());
assertThat(keys.indexOf("include-java")).isLessThan(keys.indexOf("code-spring-boot-latest"));
}
private Library mockLibrary(Map<String, Function<LibraryVersion, String>> links) {
String name = "Spring Framework";
String calendarName = null;
LibraryVersion version = new LibraryVersion(DependencyVersion.parse("1.2.3"));
List<Group> groups = Collections.emptyList();
List<ProhibitedVersion> prohibitedVersion = Collections.emptyList();
boolean considerSnapshots = false;
VersionAlignment versionAlignment = null;
String linkRootName = null;
Library library = new Library(name, calendarName, version, groups, prohibitedVersion, considerSnapshots,
versionAlignment, linkRootName, links);
return library;
}
private Map<String, String> mockDependencyVersions() {
Map<String, String> versions = new LinkedHashMap<>();
addMockSpringDataVersion(versions, "spring-data-commons");
addMockSpringDataVersion(versions, "spring-data-couchbase");
addMockSpringDataVersion(versions, "spring-data-elasticsearch");
addMockSpringDataVersion(versions, "spring-data-jdbc");
addMockSpringDataVersion(versions, "spring-data-jpa");
addMockSpringDataVersion(versions, "spring-data-mongodb");
addMockSpringDataVersion(versions, "spring-data-neo4j");
addMockSpringDataVersion(versions, "spring-data-r2dbc");
addMockSpringDataVersion(versions, "spring-data-rest-core");
return versions;
}
private void addMockSpringDataVersion(Map<String, String> versions, String artifactId) {
versions.put("org.springframework.data:" + artifactId, "1.2.3");
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.antora;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import org.gradle.api.Project;
import org.gradle.testfixtures.ProjectBuilder;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.util.function.ThrowingConsumer;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link GenerateAntoraPlaybook}.
*
* @author Phillip Webb
*/
class GenerateAntoraPlaybookTests {
@TempDir
File temp;
@Test
void writePlaybookGeneratesExpectedContent() throws Exception {
writePlaybookYml((task) -> {
task.getXrefStubs().addAll("appendix:.*", "api:.*", "reference:.*");
task.getAlwaysInclude().set(Map.of("name", "test", "classifier", "local-aggregate-content"));
});
Path actual = this.temp.toPath()
.resolve("rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml");
System.out.println(Files.readString(actual));
assertThat(actual).hasSameTextualContentAs(
Path.of("src/test/resources/org/springframework/boot/build/antora/expected-playbook.yml"));
}
private void writePlaybookYml(ThrowingConsumer<GenerateAntoraPlaybook> customizer) throws Exception {
File rootProjectDir = new File(this.temp, "rootproject").getCanonicalFile();
rootProjectDir.mkdirs();
Project rootProject = ProjectBuilder.builder().withProjectDir(rootProjectDir).build();
File projectDir = new File(rootProjectDir, "project");
projectDir.mkdirs();
Project project = ProjectBuilder.builder().withProjectDir(projectDir).withParent(rootProject).build();
GenerateAntoraPlaybook task = project.getTasks().create("generateAntoraPlaybook", GenerateAntoraPlaybook.class);
customizer.accept(task);
task.writePlaybookYml();
}
}

View File

@@ -153,7 +153,6 @@ class ArchitectureCheckTests {
Resource root = resolver.getResource("classpath:org/springframework/boot/build/architecture/" + name);
FileSystemUtils.copyRecursively(root.getFile(),
new File(projectDir, "classes/org/springframework/boot/build/architecture/" + name));
}
private interface Callback<T> {

View File

@@ -0,0 +1,50 @@
antora:
extensions:
- require: '@springio/antora-extensions/static-page-extension'
- require: '@springio/antora-xref-extension'
stub:
- appendix:.*
- api:.*
- reference:.*
- require: '@springio/antora-zip-contents-collector-extension'
always_include:
- classifier: local-aggregate-content
name: test
locations:
- project/build/generated/docs/antora-content/test-${version}-${name}-${classifier}.zip
- project/build/generated/docs/antora-dependencies-content/test-${version}-${name}-${classifier}.zip
version_file: gradle.properties
- require: '@springio/antora-extensions/root-component-extension'
root_component_name: spring-boot
site:
title: Spring Boot
content:
sources:
- url: ./../../../../..
branches: HEAD
version: unspecified
start_paths:
- project/src/docs/antora
asciidoc:
sourcemap: true
attributes:
chomp: all
hide-uri-scheme: '@'
page-pagination: ''
page-stackoverflow-url: https://stackoverflow.com/tags/spring-boot
tabs-sync-option: '@'
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
- '@springio/asciidoctor-extensions/configuration-properties-extension'
- '@springio/asciidoctor-extensions/section-ids-extension'
urls:
latest_version_segment: ''
runtime:
log:
failure_level: warn
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.11/ui-bundle.zip
output:
dir: ./../../../site

View File

@@ -64,12 +64,6 @@ anchors:
build_number: "${BUILD_JOB_NAME}-${BUILD_NAME}"
disable_checksum_uploads: true
threads: 8
artifact_set:
- include:
- "/**/spring-boot-docs-*.zip"
properties:
"zip.type": "docs"
"zip.deployed": "false"
slack-fail-params: &slack-fail-params
text: >
:concourse-failed: <!here> <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>

View File

@@ -1,4 +1,5 @@
version=3.3.0-SNAPSHOT
latestVersion=true
org.gradle.caching=true
org.gradle.parallel=true
@@ -6,6 +7,7 @@ org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
assertjVersion=3.25.3
commonsCodecVersion=1.16.1
graalVersion=22.3
hamcrestVersion=2.2
jacksonVersion=2.17.0
junitJupiterVersion=5.10.2

View File

@@ -1,6 +1,6 @@
plugins {
id "java-library"
id "org.asciidoctor.jvm.convert"
id "org.antora"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.conventions"
@@ -11,13 +11,10 @@ plugins {
description = "Spring Boot Actuator AutoConfigure"
configurations {
documentation
antoraContent
}
dependencies {
asciidoctorExtensions("org.springframework.restdocs:spring-restdocs-asciidoctor")
asciidoctorExtensions("io.spring.asciidoctor:spring-asciidoctor-extensions-section-ids")
api(project(":spring-boot-project:spring-boot-actuator"))
api(project(":spring-boot-project:spring-boot"))
api(project(":spring-boot-project:spring-boot-autoconfigure"))
@@ -195,38 +192,6 @@ dependencies {
}
}
task dependencyVersions(type: org.springframework.boot.build.constraints.ExtractVersionConstraints) {
enforcedPlatform(":spring-boot-project:spring-boot-dependencies")
}
asciidoctor {
sources {
include "index.adoc"
}
}
task asciidoctorPdf(type: org.asciidoctor.gradle.jvm.AsciidoctorTask) {
sources {
include "index.adoc"
}
}
task zip(type: Zip) {
dependsOn asciidoctor, asciidoctorPdf
duplicatesStrategy "fail"
from(asciidoctorPdf.outputDir) {
into "pdf"
rename { "spring-boot-actuator-web-api.pdf" }
}
from(asciidoctor.outputDir) {
into "htmlsingle"
}
}
artifacts {
documentation zip
}
tasks.named("test") {
jvmArgs += "--add-opens=java.base/java.net=ALL-UNNAMED"
filter {
@@ -235,28 +200,46 @@ tasks.named("test") {
}
def documentationTest = tasks.register("documentationTest", Test) {
jvmArgs += "--add-opens=java.base/java.net=ALL-UNNAMED"
filter {
includeTestsMatching("org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation.*")
}
jvmArgs += "--add-opens=java.base/java.net=ALL-UNNAMED"
outputs.dir("${buildDir}/generated-snippets")
predictiveSelection {
enabled = false
}
}
tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) {
dependsOn dependencyVersions
doFirst {
def versionConstraints = dependencyVersions.versionConstraints
def toAntoraVersion = version -> {
String formatted = version.split("\\.").take(2).join('.')
return version.endsWith("-SNAPSHOT") ? formatted + "-SNAPSHOT" : formatted
}
def integrationVersion = versionConstraints["org.springframework.integration:spring-integration-core"]
String integrationDocs = String.format("https://docs.spring.io/spring-integration/reference/%s", toAntoraVersion(integrationVersion))
attributes "spring-integration-docs": integrationDocs
def antoraActuatorRestApiLocalAggregateContent = tasks.register("antoraActuatorRestApiLocalAggregateContent", Zip) {
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
archiveClassifier = "actuator-rest-api-local-aggregate-content"
from(tasks.getByName("generateAntoraYml")) {
into "modules"
}
dependsOn documentationTest
inputs.dir("${buildDir}/generated-snippets").withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("generatedSnippets")
}
def antoraActuatorRestApiAggregateContent = tasks.register("antoraActuatorRestApiAggregateContent", Zip) {
dependsOn documentationTest
inputs.dir("${buildDir}/generated-snippets")
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("generatedSnippets")
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
archiveClassifier = "actuator-rest-api-aggregate-content"
from("${buildDir}/generated-snippets") {
into "modules/api/partials/rest/actuator"
}
}
tasks.named("generateAntoraPlaybook") {
alwaysInclude = [name: "actuator-rest-api", classifier: "local-aggregate-content"]
dependsOn antoraActuatorRestApiLocalAggregateContent
}
tasks.named("antora") {
inputs.files(antoraActuatorRestApiAggregateContent)
}
artifacts {
antoraContent antoraActuatorRestApiAggregateContent
}

View File

@@ -0,0 +1,6 @@
name: spring-boot
ext:
zip_contents_collector:
include:
- name: actuator-rest-api
classifier: aggregate-content

View File

@@ -0,0 +1 @@
include::api:partial$nav-actuator-rest-api.adoc[]

View File

@@ -1,36 +1,40 @@
[[audit-events]]
= Audit Events (`auditevents`)
The `auditevents` endpoint provides information about the application's audit events.
[[audit-events.retrieving]]
== Retrieving Audit Events
To retrieve the audit events, make a `GET` request to `/actuator/auditevents`, as shown in the following curl-based example:
include::{snippets}/auditevents/filtered/curl-request.adoc[]
include::partial$rest/actuator/auditevents/filtered/curl-request.adoc[]
The preceding example retrieves `logout` events for the principal, `alice`, that occurred after 09:37 on 7 November 2017 in the UTC timezone.
The resulting response is similar to the following:
include::{snippets}/auditevents/filtered/http-response.adoc[]
include::partial$rest/actuator/auditevents/filtered/http-response.adoc[]
[[audit-events.retrieving.query-parameters]]
=== Query Parameters
The endpoint uses query parameters to limit the events that it returns.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/auditevents/filtered/query-parameters.adoc[]
include::partial$rest/actuator/auditevents/filtered/query-parameters.adoc[]
[[audit-events.retrieving.response-structure]]
=== Response Structure
The response contains details of all of the audit events that matched the query.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/auditevents/all/response-fields.adoc[]
include::partial$rest/actuator/auditevents/all/response-fields.adoc[]

View File

@@ -1,25 +1,28 @@
[[beans]]
= Beans (`beans`)
The `beans` endpoint provides information about the application's beans.
[[beans.retrieving]]
== Retrieving the Beans
To retrieve the beans, make a `GET` request to `/actuator/beans`, as shown in the following curl-based example:
include::{snippets}/beans/curl-request.adoc[]
include::partial$rest/actuator/beans/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/beans/http-response.adoc[]
include::partial$rest/actuator/beans/http-response.adoc[]
[[beans.retrieving.response-structure]]
=== Response Structure
The response contains details of the application's beans.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/beans/response-fields.adoc[]
include::partial$rest/actuator/beans/response-fields.adoc[]

View File

@@ -1,78 +1,86 @@
[[caches]]
= Caches (`caches`)
The `caches` endpoint provides access to the application's caches.
[[caches.all]]
== Retrieving All Caches
To retrieve the application's caches, make a `GET` request to `/actuator/caches`, as shown in the following curl-based example:
include::{snippets}/caches/all/curl-request.adoc[]
include::partial$rest/actuator/caches/all/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/caches/all/http-response.adoc[]
include::partial$rest/actuator/caches/all/http-response.adoc[]
[[caches.all.response-structure]]
=== Response Structure
The response contains details of the application's caches.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/caches/all/response-fields.adoc[]
include::partial$rest/actuator/caches/all/response-fields.adoc[]
[[caches.named]]
== Retrieving Caches by Name
To retrieve a cache by name, make a `GET` request to `/actuator/caches/\{name}`, as shown in the following curl-based example:
include::{snippets}/caches/named/curl-request.adoc[]
include::partial$rest/actuator/caches/named/curl-request.adoc[]
The preceding example retrieves information about the cache named `cities`.
The resulting response is similar to the following:
include::{snippets}/caches/named/http-response.adoc[]
include::partial$rest/actuator/caches/named/http-response.adoc[]
[[caches.named.query-parameters]]
=== Query Parameters
If the requested name is specific enough to identify a single cache, no extra parameter is required.
Otherwise, the `cacheManager` must be specified.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/caches/named/query-parameters.adoc[]
include::partial$rest/actuator/caches/named/query-parameters.adoc[]
[[caches.named.response-structure]]
=== Response Structure
The response contains details of the requested cache.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/caches/named/response-fields.adoc[]
include::partial$rest/actuator/caches/named/response-fields.adoc[]
[[caches.evict-all]]
== Evict All Caches
To clear all available caches, make a `DELETE` request to `/actuator/caches` as shown in the following curl-based example:
include::{snippets}/caches/evict-all/curl-request.adoc[]
include::partial$rest/actuator/caches/evict-all/curl-request.adoc[]
[[caches.evict-named]]
== Evict a Cache by Name
To evict a particular cache, make a `DELETE` request to `/actuator/caches/\{name}` as shown in the following curl-based example:
include::{snippets}/caches/evict-named/curl-request.adoc[]
include::partial$rest/actuator/caches/evict-named/curl-request.adoc[]
NOTE: As there are two caches named `countries`, the `cacheManager` has to be provided to specify which `Cache` should be cleared.
@@ -80,9 +88,10 @@ NOTE: As there are two caches named `countries`, the `cacheManager` has to be pr
[[caches.evict-named.request-structure]]
=== Request Structure
If the requested name is specific enough to identify a single cache, no extra parameter is required.
Otherwise, the `cacheManager` must be specified.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/caches/evict-named/query-parameters.adoc[]
include::partial$rest/actuator/caches/evict-named/query-parameters.adoc[]

View File

@@ -1,25 +1,28 @@
[[conditions]]
= Conditions Evaluation Report (`conditions`)
The `conditions` endpoint provides information about the evaluation of conditions on configuration and auto-configuration classes.
[[conditions.retrieving]]
== Retrieving the Report
To retrieve the report, make a `GET` request to `/actuator/conditions`, as shown in the following curl-based example:
include::{snippets}/conditions/curl-request.adoc[]
include::partial$rest/actuator/conditions/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/conditions/http-response.adoc[]
include::partial$rest/actuator/conditions/http-response.adoc[]
[[conditions.retrieving.response-structure]]
=== Response Structure
The response contains details of the application's condition evaluation.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/conditions/response-fields.adoc[]
include::partial$rest/actuator/conditions/response-fields.adoc[]

View File

@@ -1,40 +1,44 @@
[[configprops]]
= Configuration Properties (`configprops`)
The `configprops` endpoint provides information about the application's `@ConfigurationProperties` beans.
[[configprops.retrieving]]
== Retrieving All @ConfigurationProperties Beans
To retrieve all of the `@ConfigurationProperties` beans, make a `GET` request to `/actuator/configprops`, as shown in the following curl-based example:
include::{snippets}/configprops/all/curl-request.adoc[]
include::partial$rest/actuator/configprops/all/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/configprops/all/http-response.adoc[]
include::partial$rest/actuator/configprops/all/http-response.adoc[]
[[configprops.retrieving.response-structure]]
=== Response Structure
The response contains details of the application's `@ConfigurationProperties` beans.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/configprops/all/response-fields.adoc[]
include::partial$rest/actuator/configprops/all/response-fields.adoc[]
[[configprops.retrieving-by-prefix]]
== Retrieving @ConfigurationProperties Beans By Prefix
To retrieve the `@ConfigurationProperties` beans mapped under a certain prefix, make a `GET` request to `/actuator/configprops/\{prefix}`, as shown in the following curl-based example:
include::{snippets}/configprops/prefixed/curl-request.adoc[]
include::partial$rest/actuator/configprops/prefixed/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/configprops/prefixed/http-response.adoc[]
include::partial$rest/actuator/configprops/prefixed/http-response.adoc[]
NOTE: The `\{prefix}` does not need to be exact, a more general prefix will return all beans mapped under that prefix stem.
@@ -42,8 +46,9 @@ NOTE: The `\{prefix}` does not need to be exact, a more general prefix will retu
[[configprops.retrieving-by-prefix.response-structure]]
=== Response Structure
The response contains details of the application's `@ConfigurationProperties` beans.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/configprops/prefixed/response-fields.adoc[]
include::partial$rest/actuator/configprops/prefixed/response-fields.adoc[]

View File

@@ -1,49 +1,57 @@
[[env]]
= Environment (`env`)
The `env` endpoint provides information about the application's `Environment`.
[[env.entire]]
== Retrieving the Entire Environment
To retrieve the entire environment, make a `GET` request to `/actuator/env`, as shown in the following curl-based example:
include::{snippets}/env/all/curl-request.adoc[]
include::partial$rest/actuator/env/all/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/env/all/http-response.adoc[]
include::partial$rest/actuator/env/all/http-response.adoc[]
NOTE: Sanitization of sensitive values has been switched off for this example.
[[env.entire.response-structure]]
=== Response Structure
The response contains details of the application's `Environment`.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/env/all/response-fields.adoc[]
include::partial$rest/actuator/env/all/response-fields.adoc[]
[[env.single-property]]
== Retrieving a Single Property
To retrieve a single property, make a `GET` request to `/actuator/env/{property.name}`, as shown in the following curl-based example:
include::{snippets}/env/single/curl-request.adoc[]
include::partial$rest/actuator/env/single/curl-request.adoc[]
The preceding example retrieves information about the property named `com.example.cache.max-size`.
The resulting response is similar to the following:
include::{snippets}/env/single/http-response.adoc[]
include::partial$rest/actuator/env/single/http-response.adoc[]
NOTE: Sanitization of sensitive values has been switched off for this example.
[[env.single-property.response-structure]]
=== Response Structure
The response contains details of the requested property.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/env/single/response-fields.adoc[]
include::partial$rest/actuator/env/single/response-fields.adoc[]

View File

@@ -1,25 +1,28 @@
[[flyway]]
= Flyway (`flyway`)
The `flyway` endpoint provides information about database migrations performed by Flyway.
[[flyway.retrieving]]
== Retrieving the Migrations
To retrieve the migrations, make a `GET` request to `/actuator/flyway`, as shown in the following curl-based example:
include::{snippets}/flyway/curl-request.adoc[]
include::partial$rest/actuator/flyway/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/flyway/http-response.adoc[]
include::partial$rest/actuator/flyway/http-response.adoc[]
[[flyway.retrieving.response-structure]]
=== Response Structure
The response contains details of the application's Flyway migrations.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/flyway/response-fields.adoc[]
include::partial$rest/actuator/flyway/response-fields.adoc[]

View File

@@ -1,28 +1,31 @@
[[health]]
= Health (`health`)
The `health` endpoint provides detailed information about the health of the application.
[[health.retrieving]]
== Retrieving the Health of the Application
To retrieve the health of the application, make a `GET` request to `/actuator/health`, as shown in the following curl-based example:
include::{snippets}/health/curl-request.adoc[]
include::partial$rest/actuator/health/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/health/http-response.adoc[]
include::partial$rest/actuator/health/http-response.adoc[]
[[health.retrieving.response-structure]]
=== Response Structure
The response contains details of the health of the application.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/health/response-fields.adoc[]
include::partial$rest/actuator/health/response-fields.adoc[]
NOTE: The response fields above are for the V3 API.
If you need to return V2 JSON you should use an accept header or `application/vnd.spring-boot.actuator.v2+json`
@@ -31,35 +34,38 @@ If you need to return V2 JSON you should use an accept header or `application/vn
[[health.retrieving-component]]
== Retrieving the Health of a Component
To retrieve the health of a particular component of the application's health, make a `GET` request to `/actuator/health/\{component}`, as shown in the following curl-based example:
include::{snippets}/health/component/curl-request.adoc[]
include::partial$rest/actuator/health/component/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/health/component/http-response.adoc[]
include::partial$rest/actuator/health/component/http-response.adoc[]
[[health.retrieving-component.response-structure]]
=== Response Structure
The response contains details of the health of a particular component of the application's health.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/health/component/response-fields.adoc[]
include::partial$rest/actuator/health/component/response-fields.adoc[]
[[health.retrieving-component-nested]]
== Retrieving the Health of a Nested Component
If a particular component contains other nested components (as the `broker` indicator in the example above), the health of such a nested component can be retrieved by issuing a `GET` request to `/actuator/health/\{component}/\{subcomponent}`, as shown in the following curl-based example:
include::{snippets}/health/instance/curl-request.adoc[]
include::partial$rest/actuator/health/instance/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/health/instance/http-response.adoc[]
include::partial$rest/actuator/health/instance/http-response.adoc[]
Components of an application's health may be nested arbitrarily deep depending on the application's health indicators and how they have been grouped.
The health endpoint supports any number of `/\{component}` identifiers in the URL to allow the health of a component at any depth to be retrieved.
@@ -68,8 +74,9 @@ The health endpoint supports any number of `/\{component}` identifiers in the UR
[[health.retrieving-component-nested.response-structure]]
=== Response Structure
The response contains details of the health of an instance of a particular component of the application.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/health/instance/response-fields.adoc[]
include::partial$rest/actuator/health/instance/response-fields.adoc[]

View File

@@ -1,11 +1,13 @@
[[heapdump]]
= Heap Dump (`heapdump`)
The `heapdump` endpoint provides a heap dump from the application's JVM.
[[heapdump.retrieving]]
== Retrieving the Heap Dump
To retrieve the heap dump, make a `GET` request to `/actuator/heapdump`.
The response is binary data and can be large.
Its format depends upon the JVM on which the application is running.
@@ -14,6 +16,6 @@ and on OpenJ9 it is https://www.eclipse.org/openj9/docs/dump_heapdump/#portable-
Typically, you should save the response to disk for subsequent analysis.
When using curl, this can be achieved by using the `-O` option, as shown in the following example:
include::{snippets}/heapdump/curl-request.adoc[]
include::partial$rest/actuator/heapdump/curl-request.adoc[]
The preceding example results in a file named `heapdump` being written to the current working directory.

View File

@@ -1,25 +1,28 @@
[[httpexchanges]]
= HTTP Exchanges (`httpexchanges`)
The `httpexchanges` endpoint provides information about HTTP request-response exchanges.
[[httpexchanges.retrieving]]
== Retrieving the HTTP Exchanges
To retrieve the HTTP exchanges, make a `GET` request to `/actuator/httpexchanges`, as shown in the following curl-based example:
include::{snippets}/httpexchanges/curl-request.adoc[]
include::partial$rest/actuator/httpexchanges/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/httpexchanges/http-response.adoc[]
include::partial$rest/actuator/httpexchanges/http-response.adoc[]
[[httpexchanges.retrieving.response-structure]]
=== Response Structure
The response contains details of the traced HTTP request-response exchanges.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/httpexchanges/response-fields.adoc[]
include::partial$rest/actuator/httpexchanges/response-fields.adoc[]

View File

@@ -0,0 +1,41 @@
:navtitle: Actuator
[[overview]]
= Actuator REST API
This API documentation describes Spring Boot Actuators web endpoints.
Before you proceed, you should read the following topics:
* <<overview.endpoint-urls>>
* <<overview.timestamps>>
NOTE: In order to get the correct JSON responses documented below, Jackson must be available.
[[overview.endpoint-urls]]
== URLs
By default, all web endpoints are available beneath the path `/actuator` with URLs of
the form `/actuator/\{id}`. The `/actuator` base path can be configured by using the
`management.endpoints.web.base-path` property, as shown in the following example:
[source,properties]
----
management.endpoints.web.base-path=/manage
----
The preceding `application.properties` example changes the form of the endpoint URLs from
`/actuator/\{id}` to `/manage/\{id}`. For example, the URL `info` endpoint would become
`/manage/info`.
[[overview.timestamps]]
== Timestamps
All timestamps that are consumed by the endpoints, either as query parameters or in the
request body, must be formatted as an offset date and time as specified in
https://en.wikipedia.org/wiki/ISO_8601[ISO 8601].

View File

@@ -1,23 +1,26 @@
[[info]]
= Info (`info`)
The `info` endpoint provides general information about the application.
[[info.retrieving]]
== Retrieving the Info
To retrieve the information about the application, make a `GET` request to `/actuator/info`, as shown in the following curl-based example:
include::{snippets}/info/curl-request.adoc[]
include::partial$rest/actuator/info/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/info/http-response.adoc[]
include::partial$rest/actuator/info/http-response.adoc[]
[[info.retrieving.response-structure]]
=== Response Structure
The response contains general information about the application.
Each section of the response is contributed by an `InfoContributor`.
Spring Boot provides several contributors that are described below.
@@ -26,19 +29,21 @@ Spring Boot provides several contributors that are described below.
[[info.retrieving.response-structure.build]]
==== Build Response Structure
The following table describe the structure of the `build` section of the response:
[cols="2,1,3"]
include::{snippets}/info/response-fields-beneath-build.adoc[]
include::partial$rest/actuator/info/response-fields-beneath-build.adoc[]
[[info.retrieving.response-structure.git]]
==== Git Response Structure
The following table describes the structure of the `git` section of the response:
[cols="2,1,3"]
include::{snippets}/info/response-fields-beneath-git.adoc[]
include::partial$rest/actuator/info/response-fields-beneath-git.adoc[]
NOTE: This is the "simple" output.
The contributor can also be configured to output all available data.

View File

@@ -1,34 +1,38 @@
[[integrationgraph]]
= Spring Integration graph (`integrationgraph`)
The `integrationgraph` endpoint exposes a graph containing all Spring Integration components.
[[integrationgraph.retrieving]]
== Retrieving the Spring Integration Graph
To retrieve the information about the application, make a `GET` request to `/actuator/integrationgraph`, as shown in the following curl-based example:
include::{snippets}/integrationgraph/graph/curl-request.adoc[]
include::partial$rest/actuator/integrationgraph/graph/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/integrationgraph/graph/http-response.adoc[]
include::partial$rest/actuator/integrationgraph/graph/http-response.adoc[]
[[integrationgraph.retrieving.response-structure]]
=== Response Structure
The response contains all Spring Integration components used within the application, as well as the links between them.
More information about the structure can be found in the {spring-integration-docs}/index.html#integration-graph[reference documentation].
More information about the structure can be found in the {url-spring-integration-docs}/graph.html[reference documentation].
[[integrationgraph.rebuilding]]
== Rebuilding the Spring Integration Graph
To rebuild the exposed graph, make a `POST` request to `/actuator/integrationgraph`, as shown in the following curl-based example:
include::{snippets}/integrationgraph/rebuild/curl-request.adoc[]
include::partial$rest/actuator/integrationgraph/rebuild/curl-request.adoc[]
This will result in a `204 - No Content` response:
include::{snippets}/integrationgraph/rebuild/http-response.adoc[]
include::partial$rest/actuator/integrationgraph/rebuild/http-response.adoc[]

View File

@@ -1,25 +1,28 @@
[[liquibase]]
= Liquibase (`liquibase`)
The `liquibase` endpoint provides information about database change sets applied by Liquibase.
[[liquibase.retrieving]]
== Retrieving the Changes
To retrieve the changes, make a `GET` request to `/actuator/liquibase`, as shown in the following curl-based example:
include::{snippets}/liquibase/curl-request.adoc[]
include::partial$rest/actuator/liquibase/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/liquibase/http-response.adoc[]
include::partial$rest/actuator/liquibase/http-response.adoc[]
[[liquibase.retrieving.response-structure]]
=== Response Structure
The response contains details of the application's Liquibase change sets.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/liquibase/response-fields.adoc[]
include::partial$rest/actuator/liquibase/response-fields.adoc[]

View File

@@ -1,30 +1,33 @@
[[logfile]]
= Log File (`logfile`)
The `logfile` endpoint provides access to the contents of the application's log file.
[[logfile.retrieving]]
== Retrieving the Log File
To retrieve the log file, make a `GET` request to `/actuator/logfile`, as shown in the following curl-based example:
include::{snippets}/logfile/entire/curl-request.adoc[]
include::partial$rest/actuator/logfile/entire/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/logfile/entire/http-response.adoc[]
include::partial$rest/actuator/logfile/entire/http-response.adoc[]
[[logfile.retrieving-part]]
== Retrieving Part of the Log File
NOTE: Retrieving part of the log file is not supported when using Jersey.
To retrieve part of the log file, make a `GET` request to `/actuator/logfile` by using the `Range` header, as shown in the following curl-based example:
include::{snippets}/logfile/range/curl-request.adoc[]
include::partial$rest/actuator/logfile/range/curl-request.adoc[]
The preceding example retrieves the first 1024 bytes of the log file.
The resulting response is similar to the following:
include::{snippets}/logfile/range/http-response.adoc[]
include::partial$rest/actuator/logfile/range/http-response.adoc[]

View File

@@ -1,83 +1,91 @@
[[loggers]]
= Loggers (`loggers`)
The `loggers` endpoint provides access to the application's loggers and the configuration of their levels.
[[loggers.all]]
== Retrieving All Loggers
To retrieve the application's loggers, make a `GET` request to `/actuator/loggers`, as shown in the following curl-based example:
include::{snippets}/loggers/all/curl-request.adoc[]
include::partial$rest/actuator/loggers/all/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/loggers/all/http-response.adoc[]
include::partial$rest/actuator/loggers/all/http-response.adoc[]
[[loggers.all.response-structure]]
=== Response Structure
The response contains details of the application's loggers.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/loggers/all/response-fields.adoc[]
include::partial$rest/actuator/loggers/all/response-fields.adoc[]
[[loggers.single]]
== Retrieving a Single Logger
To retrieve a single logger, make a `GET` request to `/actuator/loggers/{logger.name}`, as shown in the following curl-based example:
include::{snippets}/loggers/single/curl-request.adoc[]
include::partial$rest/actuator/loggers/single/curl-request.adoc[]
The preceding example retrieves information about the logger named `com.example`.
The resulting response is similar to the following:
include::{snippets}/loggers/single/http-response.adoc[]
include::partial$rest/actuator/loggers/single/http-response.adoc[]
[[loggers.single.response-structure]]
=== Response Structure
The response contains details of the requested logger.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/loggers/single/response-fields.adoc[]
include::partial$rest/actuator/loggers/single/response-fields.adoc[]
[[loggers.group]]
== Retrieving a Single Group
To retrieve a single group, make a `GET` request to `/actuator/loggers/{group.name}`,
as shown in the following curl-based example:
include::{snippets}/loggers/group/curl-request.adoc[]
include::partial$rest/actuator/loggers/group/curl-request.adoc[]
The preceding example retrieves information about the logger group named `test`.
The resulting response is similar to the following:
include::{snippets}/loggers/group/http-response.adoc[]
include::partial$rest/actuator/loggers/group/http-response.adoc[]
[[loggers.group.response-structure]]
=== Response Structure
The response contains details of the requested group.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/loggers/group/response-fields.adoc[]
include::partial$rest/actuator/loggers/group/response-fields.adoc[]
[[loggers.setting-level]]
== Setting a Log Level
To set the level of a logger, make a `POST` request to `/actuator/loggers/{logger.name}` with a JSON body that specifies the configured level for the logger, as shown in the following curl-based example:
include::{snippets}/loggers/set/curl-request.adoc[]
include::partial$rest/actuator/loggers/set/curl-request.adoc[]
The preceding example sets the `configuredLevel` of the `com.example` logger to `DEBUG`.
@@ -85,19 +93,21 @@ The preceding example sets the `configuredLevel` of the `com.example` logger to
[[loggers.setting-level.request-structure]]
=== Request Structure
The request specifies the desired level of the logger.
The following table describes the structure of the request:
[cols="3,1,3"]
include::{snippets}/loggers/set/request-fields.adoc[]
include::partial$rest/actuator/loggers/set/request-fields.adoc[]
[[loggers.group-setting-level]]
== Setting a Log Level for a Group
To set the level of a logger, make a `POST` request to `/actuator/loggers/{group.name}` with a JSON body that specifies the configured level for the logger group, as shown in the following curl-based example:
include::{snippets}/loggers/setGroup/curl-request.adoc[]
include::partial$rest/actuator/loggers/setGroup/curl-request.adoc[]
The preceding example sets the `configuredLevel` of the `test` logger group to `DEBUG`.
@@ -105,18 +115,20 @@ The preceding example sets the `configuredLevel` of the `test` logger group to `
[[loggers.group-setting-level.request-structure]]
=== Request Structure
The request specifies the desired level of the logger group.
The following table describes the structure of the request:
[cols="3,1,3"]
include::{snippets}/loggers/set/request-fields.adoc[]
include::partial$rest/actuator/loggers/set/request-fields.adoc[]
[[loggers.clearing-level]]
== Clearing a Log Level
To clear the level of a logger, make a `POST` request to `/actuator/loggers/{logger.name}` with a JSON body containing an empty object, as shown in the following curl-based example:
include::{snippets}/loggers/clear/curl-request.adoc[]
include::partial$rest/actuator/loggers/clear/curl-request.adoc[]
The preceding example clears the configured level of the `com.example` logger.

View File

@@ -1,29 +1,32 @@
[[mappings]]
= Mappings (`mappings`)
The `mappings` endpoint provides information about the application's request mappings.
[[mappings.retrieving]]
== Retrieving the Mappings
To retrieve the mappings, make a `GET` request to `/actuator/mappings`, as shown in the following curl-based example:
include::{snippets}/mappings/curl-request.adoc[]
include::partial$rest/actuator/mappings/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/mappings/http-response.adoc[]
include::partial$rest/actuator/mappings/http-response.adoc[]
[[mappings.retrieving.response-structure]]
=== Response Structure
The response contains details of the application's mappings.
The items found in the response depend on the type of web application (reactive or Servlet-based).
The following table describes the structure of the common elements of the response:
[cols="2,1,3"]
include::{snippets}/mappings/response-fields.adoc[]
include::partial$rest/actuator/mappings/response-fields.adoc[]
The entries that may be found in `contexts.*.mappings` are described in the following sections.
@@ -31,38 +34,42 @@ The entries that may be found in `contexts.*.mappings` are described in the foll
[[mappings.retrieving.response-structure-dispatcher-servlets]]
=== Dispatcher Servlets Response Structure
When using Spring MVC, the response contains details of any `DispatcherServlet` request mappings beneath `contexts.*.mappings.dispatcherServlets`.
The following table describes the structure of this section of the response:
[cols="4,1,2"]
include::{snippets}/mappings/response-fields-dispatcher-servlets.adoc[]
include::partial$rest/actuator/mappings/response-fields-dispatcher-servlets.adoc[]
[[mappings.retrieving.response-structure-servlets]]
=== Servlets Response Structure
When using the Servlet stack, the response contains details of any `Servlet` mappings beneath `contexts.*.mappings.servlets`.
The following table describes the structure of this section of the response:
[cols="2,1,3"]
include::{snippets}/mappings/response-fields-servlets.adoc[]
include::partial$rest/actuator/mappings/response-fields-servlets.adoc[]
[[mappings.retrieving.response-structure-servlet-filters]]
=== Servlet Filters Response Structure
When using the Servlet stack, the response contains details of any `Filter` mappings beneath `contexts.*.mappings.servletFilters`.
The following table describes the structure of this section of the response:
[cols="2,1,3"]
include::{snippets}/mappings/response-fields-servlet-filters.adoc[]
include::partial$rest/actuator/mappings/response-fields-servlet-filters.adoc[]
[[mappings.retrieving.response-structure-dispatcher-handlers]]
=== Dispatcher Handlers Response Structure
When using Spring WebFlux, the response contains details of any `DispatcherHandler` request mappings beneath `contexts.*.mappings.dispatcherHandlers`.
The following table describes the structure of this section of the response:
[cols="4,1,2"]
include::{snippets}/mappings/response-fields-dispatcher-handlers.adoc[]
include::partial$rest/actuator/mappings/response-fields-dispatcher-handlers.adoc[]

View File

@@ -1,70 +1,77 @@
[[metrics]]
= Metrics (`metrics`)
The `metrics` endpoint provides access to application metrics.
[[metrics.retrieving-names]]
== Retrieving Metric Names
To retrieve the names of the available metrics, make a `GET` request to `/actuator/metrics`, as shown in the following curl-based example:
include::{snippets}/metrics/names/curl-request.adoc[]
include::partial$rest/actuator/metrics/names/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/metrics/names/http-response.adoc[]
include::partial$rest/actuator/metrics/names/http-response.adoc[]
[[metrics.retrieving-names.response-structure]]
=== Response Structure
The response contains details of the metric names.
The following table describes the structure of the response:
[cols="3,1,2"]
include::{snippets}/metrics/names/response-fields.adoc[]
include::partial$rest/actuator/metrics/names/response-fields.adoc[]
[[metrics.retrieving-metric]]
== Retrieving a Metric
To retrieve a metric, make a `GET` request to `/actuator/metrics/{metric.name}`, as shown in the following curl-based example:
include::{snippets}/metrics/metric/curl-request.adoc[]
include::partial$rest/actuator/metrics/metric/curl-request.adoc[]
The preceding example retrieves information about the metric named `jvm.memory.max`.
The resulting response is similar to the following:
include::{snippets}/metrics/metric/http-response.adoc[]
include::partial$rest/actuator/metrics/metric/http-response.adoc[]
[[metrics.retrieving-metric.query-parameters]]
=== Query Parameters
The endpoint uses query parameters to <<metrics.drilling-down,drill down>> into a metric by using its tags.
The endpoint uses query parameters to xref:rest/actuator/metrics.adoc#metrics.drilling-down[drill down] into a metric by using its tags.
The following table shows the single supported query parameter:
[cols="2,4"]
include::{snippets}/metrics/metric-with-tags/query-parameters.adoc[]
include::partial$rest/actuator/metrics/metric-with-tags/query-parameters.adoc[]
[[metrics.retrieving-metric.response-structure]]
=== Response structure
The response contains details of the metric.
The following table describes the structure of the response:
include::{snippets}/metrics/metric/response-fields.adoc[]
include::partial$rest/actuator/metrics/metric/response-fields.adoc[]
[[metrics.drilling-down]]
== Drilling Down
To drill down into a metric, make a `GET` request to `/actuator/metrics/{metric.name}` using the `tag` query parameter, as shown in the following curl-based example:
include::{snippets}/metrics/metric-with-tags/curl-request.adoc[]
include::partial$rest/actuator/metrics/metric-with-tags/curl-request.adoc[]
The preceding example retrieves the `jvm.memory.max` metric, where the `area` tag has a value of `nonheap` and the `id` attribute has a value of `Compressed Class Space`.
The resulting response is similar to the following:
include::{snippets}/metrics/metric-with-tags/http-response.adoc[]
include::partial$rest/actuator/metrics/metric-with-tags/http-response.adoc[]

View File

@@ -1,47 +1,51 @@
[[prometheus]]
= Prometheus (`prometheus`)
The `prometheus` endpoint provides Spring Boot application's metrics in the format required for scraping by a Prometheus server.
[[prometheus.retrieving]]
== Retrieving All Metrics
To retrieve all metrics, make a `GET` request to `/actuator/prometheus`, as shown in the following curl-based example:
include::{snippets}/prometheus/all/curl-request.adoc[]
include::partial$rest/actuator/prometheus/all/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/prometheus/all/http-response.adoc[]
include::partial$rest/actuator/prometheus/all/http-response.adoc[]
The default response content type is `text/plain;version=0.0.4`.
The endpoint can also produce `application/openmetrics-text;version=1.0.0` when called with an appropriate `Accept` header, as shown in the following curl-based example:
include::{snippets}/prometheus/openmetrics/curl-request.adoc[]
include::partial$rest/actuator/prometheus/openmetrics/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/prometheus/openmetrics/http-response.adoc[]
include::partial$rest/actuator/prometheus/openmetrics/http-response.adoc[]
[[prometheus.retrieving.query-parameters]]
=== Query Parameters
The endpoint uses query parameters to limit the samples that it returns.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/prometheus/names/query-parameters.adoc[]
include::partial$rest/actuator/prometheus/names/query-parameters.adoc[]
[[prometheus.retrieving-names]]
== Retrieving Filtered Metrics
To retrieve metrics matching specific names, make a `GET` request to `/actuator/prometheus` with the `includedNames` query parameter, as shown in the following curl-based example:
include::{snippets}/prometheus/names/curl-request.adoc[]
include::partial$rest/actuator/prometheus/names/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/prometheus/names/http-response.adoc[]
include::partial$rest/actuator/prometheus/names/http-response.adoc[]

View File

@@ -1,96 +1,105 @@
[[quartz]]
= Quartz (`quartz`)
The `quartz` endpoint provides information about jobs and triggers that are managed by the Quartz Scheduler.
[[quartz.report]]
== Retrieving Registered Groups
Jobs and triggers are managed in groups.
To retrieve the list of registered job and trigger groups, make a `GET` request to `/actuator/quartz`, as shown in the following curl-based example:
include::{snippets}/quartz/report/curl-request.adoc[]
include::partial$rest/actuator/quartz/report/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/quartz/report/http-response.adoc[]
include::partial$rest/actuator/quartz/report/http-response.adoc[]
[[quartz.report.response-structure]]
=== Response Structure
The response contains the groups names for registered jobs and triggers.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/quartz/report/response-fields.adoc[]
include::partial$rest/actuator/quartz/report/response-fields.adoc[]
[[quartz.job-groups]]
== Retrieving Registered Job Names
To retrieve the list of registered job names, make a `GET` request to `/actuator/quartz/jobs`, as shown in the following curl-based example:
include::{snippets}/quartz/jobs/curl-request.adoc[]
include::partial$rest/actuator/quartz/jobs/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/quartz/jobs/http-response.adoc[]
include::partial$rest/actuator/quartz/jobs/http-response.adoc[]
[[quartz.job-groups.response-structure]]
=== Response Structure
The response contains the registered job names for each group.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/quartz/jobs/response-fields.adoc[]
include::partial$rest/actuator/quartz/jobs/response-fields.adoc[]
[[quartz.trigger-groups]]
== Retrieving Registered Trigger Names
To retrieve the list of registered trigger names, make a `GET` request to `/actuator/quartz/triggers`, as shown in the following curl-based example:
include::{snippets}/quartz/triggers/curl-request.adoc[]
include::partial$rest/actuator/quartz/triggers/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/quartz/triggers/http-response.adoc[]
include::partial$rest/actuator/quartz/triggers/http-response.adoc[]
[[quartz.trigger-groups.response-structure]]
=== Response Structure
The response contains the registered trigger names for each group.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/quartz/triggers/response-fields.adoc[]
include::partial$rest/actuator/quartz/triggers/response-fields.adoc[]
[[quartz.job-group]]
== Retrieving Overview of a Job Group
To retrieve an overview of the jobs in a particular group, make a `GET` request to `/actuator/quartz/jobs/\{groupName}`, as shown in the following curl-based example:
include::{snippets}/quartz/job-group/curl-request.adoc[]
include::partial$rest/actuator/quartz/job-group/curl-request.adoc[]
The preceding example retrieves the summary for jobs in the `samples` group.
The resulting response is similar to the following:
include::{snippets}/quartz/job-group/http-response.adoc[]
include::partial$rest/actuator/quartz/job-group/http-response.adoc[]
[[quartz.job-group.response-structure]]
=== Response Structure
The response contains an overview of jobs in a particular group.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/quartz/job-group/response-fields.adoc[]
include::partial$rest/actuator/quartz/job-group/response-fields.adoc[]
@@ -99,36 +108,38 @@ include::{snippets}/quartz/job-group/response-fields.adoc[]
To retrieve an overview of the triggers in a particular group, make a `GET` request to `/actuator/quartz/triggers/\{groupName}`, as shown in the following curl-based example:
include::{snippets}/quartz/trigger-group/curl-request.adoc[]
include::partial$rest/actuator/quartz/trigger-group/curl-request.adoc[]
The preceding example retrieves the summary for triggers in the `tests` group.
The resulting response is similar to the following:
include::{snippets}/quartz/trigger-group/http-response.adoc[]
include::partial$rest/actuator/quartz/trigger-group/http-response.adoc[]
[[quartz.trigger-group.response-structure]]
=== Response Structure
The response contains an overview of triggers in a particular group.
Trigger implementation specific details are available.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/quartz/trigger-group/response-fields.adoc[]
include::partial$rest/actuator/quartz/trigger-group/response-fields.adoc[]
[[quartz.job]]
== Retrieving Details of a Job
To retrieve the details about a particular job, make a `GET` request to `/actuator/quartz/jobs/\{groupName}/\{jobName}`, as shown in the following curl-based example:
include::{snippets}/quartz/job-details/curl-request.adoc[]
include::partial$rest/actuator/quartz/job-details/curl-request.adoc[]
The preceding example retrieves the details of the job identified by the `samples` group and `jobOne` name.
The resulting response is similar to the following:
include::{snippets}/quartz/job-details/http-response.adoc[]
include::partial$rest/actuator/quartz/job-details/http-response.adoc[]
If a key in the data map is identified as sensitive, its value is sanitized.
@@ -136,20 +147,22 @@ If a key in the data map is identified as sensitive, its value is sanitized.
[[quartz.job.response-structure]]
=== Response Structure
The response contains the full details of a job including a summary of the triggers associated with it, if any.
The triggers are sorted by next fire time and priority.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/quartz/job-details/response-fields.adoc[]
include::partial$rest/actuator/quartz/job-details/response-fields.adoc[]
[[quartz.trigger]]
== Retrieving Details of a Trigger
To retrieve the details about a particular trigger, make a `GET` request to `/actuator/quartz/triggers/\{groupName}/\{triggerName}`, as shown in the following curl-based example:
include::{snippets}/quartz/trigger-details-cron/curl-request.adoc[]
include::partial$rest/actuator/quartz/trigger-details-cron/curl-request.adoc[]
The preceding example retrieves the details of trigger identified by the `samples` group and `example` name.
@@ -157,6 +170,7 @@ The preceding example retrieves the details of trigger identified by the `sample
[[quartz.trigger.common-response-structure]]
=== Common Response Structure
The response has a common structure and an additional object that is specific to the trigger's type.
There are five supported types:
@@ -169,89 +183,94 @@ There are five supported types:
The following table describes the structure of the common elements of the response:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-common/response-fields.adoc[]
include::partial$rest/actuator/quartz/trigger-details-common/response-fields.adoc[]
[[quartz.trigger.cron-response-structure]]
=== Cron Trigger Response Structure
A cron trigger defines the cron expression that is used to determine when it has to fire.
The resulting response for such a trigger implementation is similar to the following:
include::{snippets}/quartz/trigger-details-cron/http-response.adoc[]
include::partial$rest/actuator/quartz/trigger-details-cron/http-response.adoc[]
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz.trigger.common-response-structure,described previously>>.
The structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].
The following table describes the structure of the parts of the response that are specific to cron triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-cron/response-fields.adoc[]
include::partial$rest/actuator/quartz/trigger-details-cron/response-fields.adoc[]
[[quartz.trigger.simple-response-structure]]
=== Simple Trigger Response Structure
A simple trigger is used to fire a Job at a given moment in time, and optionally repeated at a specified interval.
The resulting response for such a trigger implementation is similar to the following:
include::{snippets}/quartz/trigger-details-simple/http-response.adoc[]
include::partial$rest/actuator/quartz/trigger-details-simple/http-response.adoc[]
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz.trigger.common-response-structure,described previously>>.
The structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].
The following table describes the structure of the parts of the response that are specific to simple triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-simple/response-fields.adoc[]
include::partial$rest/actuator/quartz/trigger-details-simple/response-fields.adoc[]
[[quartz.trigger.daily-time-interval-response-structure]]
=== Daily Time Interval Trigger Response Structure
A daily time interval trigger is used to fire a Job based upon daily repeating time intervals.
The resulting response for such a trigger implementation is similar to the following:
include::{snippets}/quartz/trigger-details-daily-time-interval/http-response.adoc[]
include::partial$rest/actuator/quartz/trigger-details-daily-time-interval/http-response.adoc[]
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz.trigger.common-response-structure,described previously>>.
The structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].
The following table describes the structure of the parts of the response that are specific to daily time interval triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-daily-time-interval/response-fields.adoc[]
include::partial$rest/actuator/quartz/trigger-details-daily-time-interval/response-fields.adoc[]
[[quartz.trigger.calendar-interval-response-structure]]
=== Calendar Interval Trigger Response Structure
A calendar interval trigger is used to fire a Job based upon repeating calendar time intervals.
The resulting response for such a trigger implementation is similar to the following:
include::{snippets}/quartz/trigger-details-calendar-interval/http-response.adoc[]
include::partial$rest/actuator/quartz/trigger-details-calendar-interval/http-response.adoc[]
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz.trigger.common-response-structure,described previously>>.
The structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].
The following table describes the structure of the parts of the response that are specific to calendar interval triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-calendar-interval/response-fields.adoc[]
include::partial$rest/actuator/quartz/trigger-details-calendar-interval/response-fields.adoc[]
[[quartz.trigger.custom-response-structure]]
=== Custom Trigger Response Structure
A custom trigger is any other implementation.
The resulting response for such a trigger implementation is similar to the following:
include::{snippets}/quartz/trigger-details-custom/http-response.adoc[]
include::partial$rest/actuator/quartz/trigger-details-custom/http-response.adoc[]
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz.trigger.common-response-structure,described previously>>.
The structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].
The following table describes the structure of the parts of the response that are specific to custom triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-custom/response-fields.adoc[]
include::partial$rest/actuator/quartz/trigger-details-custom/response-fields.adoc[]

View File

@@ -1,25 +1,28 @@
[[scheduled-tasks]]
= Scheduled Tasks (`scheduledtasks`)
The `scheduledtasks` endpoint provides information about the application's scheduled tasks.
[[scheduled-tasks.retrieving]]
== Retrieving the Scheduled Tasks
To retrieve the scheduled tasks, make a `GET` request to `/actuator/scheduledtasks`, as shown in the following curl-based example:
include::{snippets}/scheduled-tasks/curl-request.adoc[]
include::partial$rest/actuator/scheduled-tasks/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/scheduled-tasks/http-response.adoc[]
include::partial$rest/actuator/scheduled-tasks/http-response.adoc[]
[[scheduled-tasks.retrieving.response-structure]]
=== Response Structure
The response contains details of the application's scheduled tasks.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/scheduled-tasks/response-fields.adoc[]
include::partial$rest/actuator/scheduled-tasks/response-fields.adoc[]

View File

@@ -1,69 +1,76 @@
[[sessions]]
= Sessions (`sessions`)
The `sessions` endpoint provides information about the application's HTTP sessions that are managed by Spring Session.
[[sessions.retrieving]]
== Retrieving Sessions
To retrieve the sessions, make a `GET` request to `/actuator/sessions`, as shown in the following curl-based example:
include::{snippets}/sessions/username/curl-request.adoc[]
include::partial$rest/actuator/sessions/username/curl-request.adoc[]
The preceding examples retrieves all of the sessions for the user whose username is `alice`.
The resulting response is similar to the following:
include::{snippets}/sessions/username/http-response.adoc[]
include::partial$rest/actuator/sessions/username/http-response.adoc[]
[[sessions.retrieving.query-parameters]]
=== Query Parameters
The endpoint uses query parameters to limit the sessions that it returns.
The following table shows the single required query parameter:
[cols="2,4"]
include::{snippets}/sessions/username/query-parameters.adoc[]
include::partial$rest/actuator/sessions/username/query-parameters.adoc[]
[[sessions.retrieving.response-structure]]
=== Response Structure
The response contains details of the matching sessions.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/sessions/username/response-fields.adoc[]
include::partial$rest/actuator/sessions/username/response-fields.adoc[]
[[sessions.retrieving-id]]
== Retrieving a Single Session
To retrieve a single session, make a `GET` request to `/actuator/sessions/\{id}`, as shown in the following curl-based example:
include::{snippets}/sessions/id/curl-request.adoc[]
include::partial$rest/actuator/sessions/id/curl-request.adoc[]
The preceding example retrieves the session with the `id` of `4db5efcc-99cb-4d05-a52c-b49acfbb7ea9`.
The resulting response is similar to the following:
include::{snippets}/sessions/id/http-response.adoc[]
include::partial$rest/actuator/sessions/id/http-response.adoc[]
[[sessions.retrieving-id.response-structure]]
=== Response Structure
The response contains details of the requested session.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/sessions/id/response-fields.adoc[]
include::partial$rest/actuator/sessions/id/response-fields.adoc[]
[[sessions.deleting]]
== Deleting a Session
To delete a session, make a `DELETE` request to `/actuator/sessions/\{id}`, as shown in the following curl-based example:
include::{snippets}/sessions/delete/curl-request.adoc[]
include::partial$rest/actuator/sessions/delete/curl-request.adoc[]
The preceding example deletes the session with the `id` of `4db5efcc-99cb-4d05-a52c-b49acfbb7ea9`.

View File

@@ -1,25 +1,28 @@
[[shutdown]]
= Shutdown (`shutdown`)
The `shutdown` endpoint is used to shut down the application.
[[shutdown.shutting-down]]
== Shutting Down the Application
To shut down the application, make a `POST` request to `/actuator/shutdown`, as shown in the following curl-based example:
include::{snippets}/shutdown/curl-request.adoc[]
include::partial$rest/actuator/shutdown/curl-request.adoc[]
A response similar to the following is produced:
include::{snippets}/shutdown/http-response.adoc[]
include::partial$rest/actuator/shutdown/http-response.adoc[]
[[shutdown.shutting-down.response-structure]]
=== Response Structure
The response contains details of the result of the shutdown request.
The following table describes the structure of the response:
[cols="3,1,3"]
include::{snippets}/shutdown/response-fields.adoc[]
include::partial$rest/actuator/shutdown/response-fields.adoc[]

View File

@@ -1,43 +1,48 @@
[[startup]]
= Application Startup (`startup`)
The `startup` endpoint provides information about the application's startup sequence.
[[startup.retrieving]]
== Retrieving the Application Startup Steps
The application startup steps can either be retrieved as a snapshot (`GET`) or drained from the buffer (`POST`).
[[startup.retrieving.snapshot]]
=== Retrieving a snapshot of the Application Startup Steps
To retrieve the steps recorded so far during the application startup phase, make a `GET` request to `/actuator/startup`, as shown in the following curl-based example:
include::{snippets}/startup-snapshot/curl-request.adoc[]
include::partial$rest/actuator/startup-snapshot/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/startup-snapshot/http-response.adoc[]
include::partial$rest/actuator/startup-snapshot/http-response.adoc[]
[[startup.retrieving.drain]]
=== Draining the Application Startup Steps
To drain and return the steps recorded so far during the application startup phase, make a `POST` request to `/actuator/startup`, as shown in the following curl-based example:
include::{snippets}/startup/curl-request.adoc[]
include::partial$rest/actuator/startup/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/startup/http-response.adoc[]
include::partial$rest/actuator/startup/http-response.adoc[]
[[startup.retrieving.response-structure]]
=== Response Structure
The response contains details of the application startup steps.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/startup/response-fields.adoc[]
include::partial$rest/actuator/startup/response-fields.adoc[]

View File

@@ -1,38 +1,42 @@
[[threaddump]]
= Thread Dump (`threaddump`)
The `threaddump` endpoint provides a thread dump from the application's JVM.
[[threaddump.retrieving-json]]
== Retrieving the Thread Dump as JSON
To retrieve the thread dump as JSON, make a `GET` request to `/actuator/threaddump` with an appropriate `Accept` header, as shown in the following curl-based example:
include::{snippets}/threaddump/json/curl-request.adoc[]
include::partial$rest/actuator/threaddump/json/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/threaddump/json/http-response.adoc[]
include::partial$rest/actuator/threaddump/json/http-response.adoc[]
[[threaddump.retrieving-json.response-structure]]
=== Response Structure
The response contains details of the JVM's threads.
The following table describes the structure of the response:
[cols="3,1,2"]
include::{snippets}/threaddump/json/response-fields.adoc[]
include::partial$rest/actuator/threaddump/json/response-fields.adoc[]
[[threaddump.retrieving-text]]
== Retrieving the Thread Dump as Text
To retrieve the thread dump as text, make a `GET` request to `/actuator/threaddump` that
accepts `text/plain`, as shown in the following curl-based example:
include::{snippets}/threaddump/text/curl-request.adoc[]
include::partial$rest/actuator/threaddump/text/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/threaddump/text/http-response.adoc[]
include::partial$rest/actuator/threaddump/text/http-response.adoc[]

View File

@@ -0,0 +1,25 @@
* xref:api:rest/actuator/index.adoc[]
** xref:api:rest/actuator/auditevents.adoc[]
** xref:api:rest/actuator/beans.adoc[]
** xref:api:rest/actuator/caches.adoc[]
** xref:api:rest/actuator/conditions.adoc[]
** xref:api:rest/actuator/configprops.adoc[]
** xref:api:rest/actuator/env.adoc[]
** xref:api:rest/actuator/flyway.adoc[]
** xref:api:rest/actuator/health.adoc[]
** xref:api:rest/actuator/heapdump.adoc[]
** xref:api:rest/actuator/httpexchanges.adoc[]
** xref:api:rest/actuator/info.adoc[]
** xref:api:rest/actuator/integrationgraph.adoc[]
** xref:api:rest/actuator/liquibase.adoc[]
** xref:api:rest/actuator/logfile.adoc[]
** xref:api:rest/actuator/loggers.adoc[]
** xref:api:rest/actuator/mappings.adoc[]
** xref:api:rest/actuator/metrics.adoc[]
** xref:api:rest/actuator/prometheus.adoc[]
** xref:api:rest/actuator/quartz.adoc[]
** xref:api:rest/actuator/scheduledtasks.adoc[]
** xref:api:rest/actuator/sessions.adoc[]
** xref:api:rest/actuator/shutdown.adoc[]
** xref:api:rest/actuator/startup.adoc[]
** xref:api:rest/actuator/threaddump.adoc[]

View File

@@ -1,103 +0,0 @@
[[spring-boot-actuator-web-api-documentation]]
= Spring Boot Actuator Web API Documentation
Andy Wilkinson; Stephane Nicoll
v{gradle-project-version}
:!version-label:
:doctype: book
:toc: left
:toclevels: 4
:numbered:
:icons: font
:hide-uri-scheme:
:docinfo: shared,private
:attribute-missing: warn
This API documentation describes Spring Boot Actuators web endpoints.
[[overview]]
== Overview
Before you proceed, you should read the following topics:
* <<overview.endpoint-urls>>
* <<overview.timestamps>>
NOTE: In order to get the correct JSON responses documented below, Jackson must be available.
[[overview.endpoint-urls]]
=== URLs
By default, all web endpoints are available beneath the path `/actuator` with URLs of
the form `/actuator/\{id}`. The `/actuator` base path can be configured by using the
`management.endpoints.web.base-path` property, as shown in the following example:
[source,properties,indent=0]
----
management.endpoints.web.base-path=/manage
----
The preceding `application.properties` example changes the form of the endpoint URLs from
`/actuator/\{id}` to `/manage/\{id}`. For example, the URL `info` endpoint would become
`/manage/info`.
[[overview.timestamps]]
=== Timestamps
All timestamps that are consumed by the endpoints, either as query parameters or in the
request body, must be formatted as an offset date and time as specified in
https://en.wikipedia.org/wiki/ISO_8601[ISO 8601].
include::endpoints/auditevents.adoc[leveloffset=+1]
include::endpoints/beans.adoc[leveloffset=+1]
include::endpoints/caches.adoc[leveloffset=+1]
include::endpoints/conditions.adoc[leveloffset=+1]
include::endpoints/configprops.adoc[leveloffset=+1]
include::endpoints/env.adoc[leveloffset=+1]
include::endpoints/flyway.adoc[leveloffset=+1]
include::endpoints/health.adoc[leveloffset=+1]
include::endpoints/heapdump.adoc[leveloffset=+1]
include::endpoints/httpexchanges.adoc[leveloffset=+1]
include::endpoints/info.adoc[leveloffset=+1]
include::endpoints/integrationgraph.adoc[leveloffset=+1]
include::endpoints/liquibase.adoc[leveloffset=+1]
include::endpoints/logfile.adoc[leveloffset=+1]
include::endpoints/loggers.adoc[leveloffset=+1]
include::endpoints/mappings.adoc[leveloffset=+1]
include::endpoints/metrics.adoc[leveloffset=+1]
include::endpoints/prometheus.adoc[leveloffset=+1]
include::endpoints/quartz.adoc[leveloffset=+1]
include::endpoints/scheduledtasks.adoc[leveloffset=+1]
include::endpoints/sessions.adoc[leveloffset=+1]
include::endpoints/shutdown.adoc[leveloffset=+1]
include::endpoints/startup.adoc[leveloffset=+1]
include::endpoints/threaddump.adoc[leveloffset=+1]

View File

@@ -1,6 +1,6 @@
plugins {
id "java"
id "org.asciidoctor.jvm.convert"
id "org.antora"
id "org.springframework.boot.conventions"
id "org.springframework.boot.deployed"
id 'org.jetbrains.kotlin.jvm'
@@ -9,25 +9,12 @@ plugins {
description = "Spring Boot Docs"
configurations {
actuatorApiDocumentation
autoConfiguration
configurationProperties
gradlePluginDocumentation
mavenPluginDocumentation
remoteSpringApplicationExample
springApplicationExample
testSlices
asciidoctorExtensions {
resolutionStrategy {
eachDependency { dependency ->
// Downgrade SnakeYAML as Asciidoctor fails due to an incompatibility
// in the Pysch gem
if (dependency.requested.group.equals("org.yaml")) {
dependency.useVersion("1.33")
}
}
}
}
antoraContent
}
jar {
@@ -53,16 +40,6 @@ plugins.withType(EclipsePlugin) {
}
dependencies {
actuatorApiDocumentation(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure", configuration: "documentation"))
asciidoctorExtensions("io.spring.asciidoctor:spring-asciidoctor-extensions-spring-boot")
asciidoctorExtensions("io.spring.asciidoctor:spring-asciidoctor-extensions-section-ids")
asciidoctorExtensions(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure"))
asciidoctorExtensions(project(path: ":spring-boot-project:spring-boot-autoconfigure"))
asciidoctorExtensions(project(path: ":spring-boot-project:spring-boot-devtools"))
asciidoctorExtensions(project(path: ":spring-boot-project:spring-boot-docker-compose"))
asciidoctorExtensions(project(path: ":spring-boot-project:spring-boot-testcontainers"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-autoconfigure", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-devtools", configuration: "autoConfigurationMetadata"))
@@ -77,8 +54,6 @@ dependencies {
configurationProperties(project(path: ":spring-boot-project:spring-boot-test-autoconfigure", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-testcontainers", configuration: "configurationPropertiesMetadata"))
gradlePluginDocumentation(project(path: ":spring-boot-project:spring-boot-tools:spring-boot-gradle-plugin", configuration: "documentation"))
implementation(project(path: ":spring-boot-project:spring-boot-actuator"))
implementation(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure"))
implementation(project(path: ":spring-boot-project:spring-boot-autoconfigure"))
@@ -184,8 +159,6 @@ dependencies {
implementation("org.junit.jupiter:junit-jupiter")
implementation("org.yaml:snakeyaml")
mavenPluginDocumentation(project(path: ":spring-boot-project:spring-boot-tools:spring-boot-maven-plugin", configuration: "documentation"))
remoteSpringApplicationExample(platform(project(":spring-boot-project:spring-boot-dependencies")))
remoteSpringApplicationExample(project(":spring-boot-project:spring-boot-devtools"))
remoteSpringApplicationExample(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-logging"))
@@ -194,6 +167,10 @@ dependencies {
springApplicationExample(platform(project(":spring-boot-project:spring-boot-dependencies")))
springApplicationExample(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
antoraContent(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure", configuration: "antoraContent"))
antoraContent(project(path: ":spring-boot-project:spring-boot-tools:spring-boot-gradle-plugin", configuration: "antoraContent"))
antoraContent(project(path: ":spring-boot-project:spring-boot-tools:spring-boot-maven-plugin", configuration: "antoraContent"))
testImplementation(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation("org.assertj:assertj-core")
@@ -206,16 +183,14 @@ dependencies {
testSlices(project(path: ":spring-boot-project:spring-boot-test-autoconfigure", configuration: "testSliceMetadata"))
}
task dependencyVersions(type: org.springframework.boot.build.constraints.ExtractVersionConstraints) {
enforcedPlatform(":spring-boot-project:spring-boot-dependencies")
}
task aggregatedJavadoc(type: Javadoc) {
dependsOn dependencyVersions
project.rootProject.gradle.projectsEvaluated {
Set<Project> publishedProjects = rootProject.subprojects.findAll { it != project }
.findAll { it.plugins.hasPlugin(JavaPlugin) && it.plugins.hasPlugin(MavenPublishPlugin) }
.findAll { !it.path.contains(":spring-boot-tools:") }
.findAll { !it.path.contains(":spring-boot-tools:") ||
it.path.contains(":spring-boot-tools:spring-boot-buildpack-platform") ||
it.path.contains(":spring-boot-tools:spring-boot-loader-tools") }
.findAll { !it.name.startsWith('spring-boot-starter') }
dependsOn publishedProjects.javadoc
source publishedProjects.javadoc.source
@@ -247,33 +222,33 @@ task aggregatedJavadoc(type: Javadoc) {
task documentTestSlices(type: org.springframework.boot.build.test.autoconfigure.DocumentTestSlices) {
testSlices = configurations.testSlices
outputFile = file("${buildDir}/docs/generated/test-auto-configuration/documented-slices.adoc")
outputFile = file("${buildDir}/generated/docs/test-auto-configuration/documented-slices.adoc")
}
task documentStarters(type: org.springframework.boot.build.starters.DocumentStarters) {
outputDir = file("${buildDir}/docs/generated/using/starters/")
outputDir = file("${buildDir}/generated/docs/using/starters/")
}
task documentAutoConfigurationClasses(type: org.springframework.boot.build.autoconfigure.DocumentAutoConfigurationClasses) {
autoConfiguration = configurations.autoConfiguration
outputDir = file("${buildDir}/docs/generated/auto-configuration-classes/documented-auto-configuration-classes/")
outputDir = file("${buildDir}/generated/docs/auto-configuration-classes/documented-auto-configuration-classes/")
}
task documentDependencyVersions(type: org.springframework.boot.build.constraints.DocumentConstrainedVersions) {
task documentDependencyVersionCoordinates(type: org.springframework.boot.build.constraints.DocumentConstrainedVersions) {
dependsOn dependencyVersions
constrainedVersions.set(providers.provider { dependencyVersions.constrainedVersions })
outputFile = file("${buildDir}/docs/generated/dependency-versions/documented-coordinates.adoc")
outputFile = file("${buildDir}/generated/docs/dependency-versions/documented-coordinates.adoc")
}
task documentVersionProperties(type: org.springframework.boot.build.constraints.DocumentVersionProperties) {
task documentDependencyVersionProperties(type: org.springframework.boot.build.constraints.DocumentVersionProperties) {
dependsOn dependencyVersions
versionProperties.set(providers.provider { dependencyVersions.versionProperties})
outputFile = file("${buildDir}/docs/generated/dependency-versions/documented-properties.adoc")
outputFile = file("${buildDir}/generated/docs/dependency-versions/documented-properties.adoc")
}
task documentConfigurationProperties(type: org.springframework.boot.build.context.properties.DocumentConfigurationProperties) {
configurationPropertyMetadata = configurations.configurationProperties
outputDir = file("${buildDir}/docs/generated/")
outputDir = file("${buildDir}/generated/docs/application-properties")
}
task documentDevtoolsPropertyDefaults(type: org.springframework.boot.build.devtools.DocumentDevtoolsPropertyDefaults) {}
@@ -306,203 +281,92 @@ task runLoggingFormatExample(type: org.springframework.boot.build.docs.Applicati
normalizeTomcatPort()
}
tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) {
outputs.doNotCacheIf("This task uses log files as inputs which contain changing data (timestamp, pid)") { true }
dependsOn dependencyVersions
inputs.files(runRemoteSpringApplicationExample).withPropertyName("runRemoteSpringApplicationExample").withPathSensitivity(PathSensitivity.RELATIVE)
inputs.files(runSpringApplicationExample).withPropertyName("runSpringApplicationExample").withPathSensitivity(PathSensitivity.RELATIVE)
inputs.files(runLoggingFormatExample).withPropertyName("runLoggingFormatExample").withPathSensitivity(PathSensitivity.RELATIVE)
asciidoctorj {
fatalWarnings = ['^((?!successfully validated).)*$']
def getRelativeExamplesPath(var outputs) {
def fileName = outputs.files.singleFile.name
'example$example-output/' + fileName
}
def antoraRootAggregateContent = tasks.register("antoraRootAggregateContent", Zip) {
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
archiveClassifier = "root-aggregate-content"
from("src/main") {
into "modules/ROOT/examples"
}
doFirst {
def versionConstraints = dependencyVersions.versionConstraints
def toAntoraVersion = version -> {
String formatted = version.split("\\.").take(2).join('.')
return version.endsWith("-SNAPSHOT") ? formatted + "-SNAPSHOT" : formatted
from(project.configurations.configurationProperties) {
eachFile {
it.path = it.file.toString()
.replaceFirst('/build/(?:classes|resources)/java/main/', '/')
.replaceFirst('^.*/([^/]+)/META-INF/(spring-configuration-metadata\\.json)$', 'modules/ROOT/partials/$1/$2')
}
attributes "hibernate-version": versionConstraints["org.hibernate.orm:hibernate-core"].split("\\.").take(2).join('.'),
"jetty-version": versionConstraints["org.eclipse.jetty:jetty-server"],
"jooq-version": versionConstraints["org.jooq:jooq"],
"lettuce-version": versionConstraints["io.lettuce:lettuce-core"],
"native-build-tools-version": nativeBuildToolsVersion,
"spring-amqp-version": versionConstraints["org.springframework.amqp:spring-amqp"],
"spring-batch-version": versionConstraints["org.springframework.batch:spring-batch-core"],
"spring-batch-version-antora": toAntoraVersion(versionConstraints["org.springframework.batch:spring-batch-core"]),
"spring-boot-version": project.version,
"spring-data-commons-version": versionConstraints["org.springframework.data:spring-data-commons"],
"spring-data-couchbase-version": versionConstraints["org.springframework.data:spring-data-couchbase"],
"spring-data-jdbc-version": versionConstraints["org.springframework.data:spring-data-jdbc"],
"spring-data-jpa-version": versionConstraints["org.springframework.data:spring-data-jpa"],
"spring-data-mongodb-version": versionConstraints["org.springframework.data:spring-data-mongodb"],
"spring-data-neo4j-version": versionConstraints["org.springframework.data:spring-data-neo4j"],
"spring-data-r2dbc-version": versionConstraints["org.springframework.data:spring-data-r2dbc"],
"spring-data-rest-version": versionConstraints["org.springframework.data:spring-data-rest-core"],
"spring-framework-version": versionConstraints["org.springframework:spring-core"],
"spring-framework-version-antora": toAntoraVersion(versionConstraints["org.springframework:spring-core"]),
"spring-graphql-version-antora": toAntoraVersion(versionConstraints["org.springframework.graphql:spring-graphql"]),
"spring-integration-version-antora": toAntoraVersion(versionConstraints["org.springframework.integration:spring-integration-core"]),
"spring-kafka-version": versionConstraints["org.springframework.kafka:spring-kafka"],
"spring-pulsar-version": versionConstraints["org.springframework.pulsar:spring-pulsar"],
"spring-security-version-antora": toAntoraVersion(versionConstraints["org.springframework.security:spring-security-core"]),
"spring-authorization-server-version-antora": toAntoraVersion(versionConstraints["org.springframework.security:spring-security-oauth2-authorization-server"]),
"spring-webservices-version": versionConstraints["org.springframework.ws:spring-ws-core"],
"tomcat-version": tomcatVersion.split("\\.").take(2).join('.'),
"remote-spring-application-output": runRemoteSpringApplicationExample.outputs.files.singleFile,
"spring-application-output": runSpringApplicationExample.outputs.files.singleFile,
"logging-format-output": runLoggingFormatExample.outputs.files.singleFile
}
from(runRemoteSpringApplicationExample) {
into "modules/ROOT/examples"
}
from(documentDevtoolsPropertyDefaults) {
into "modules/ROOT/partials/propertydefaults"
}
from(documentStarters) {
into "modules/ROOT/partials/starters"
}
from(documentTestSlices) {
into "modules/appendix/partials/slices"
}
from(runSpringApplicationExample) {
into "modules/ROOT/partials/application"
}
from(runLoggingFormatExample) {
into "modules/ROOT/partials/logging"
}
from(documentDependencyVersionCoordinates) {
into "modules/appendix/partials/dependency-versions"
}
from(documentDependencyVersionProperties) {
into "modules/appendix/partials/dependency-versions"
}
from(documentAutoConfigurationClasses) {
into "modules/appendix/partials/auto-configuration-classes"
}
from(documentConfigurationProperties) {
into "modules/appendix/partials/configuration-properties"
}
from(tasks.getByName("generateAntoraYml")) {
into "modules"
}
}
asciidoctor {
sources {
include "*.singleadoc"
}
}
task asciidoctorPdf(type: org.asciidoctor.gradle.jvm.AsciidoctorTask) {
sources {
include "*.singleadoc"
}
}
task asciidoctorMultipage(type: org.asciidoctor.gradle.jvm.AsciidoctorTask) {
sources {
include "*.adoc"
}
}
syncDocumentationSourceForAsciidoctor {
dependsOn documentTestSlices
dependsOn documentStarters
dependsOn documentAutoConfigurationClasses
dependsOn documentDependencyVersions
dependsOn documentVersionProperties
dependsOn documentConfigurationProperties
dependsOn documentDevtoolsPropertyDefaults
from("${buildDir}/docs/generated") {
into "asciidoc"
}
from("src/main/java") {
into "main/java"
}
from("src/test/java") {
into "test/java"
}
from("src/main/kotlin") {
into "main/kotlin"
}
from("src/main/groovy") {
into "main/groovy"
}
from("src/main/resources") {
into "main/resources"
}
}
syncDocumentationSourceForAsciidoctorMultipage {
dependsOn documentTestSlices
dependsOn documentStarters
dependsOn documentAutoConfigurationClasses
dependsOn documentDependencyVersions
dependsOn documentVersionProperties
dependsOn documentConfigurationProperties
dependsOn documentDevtoolsPropertyDefaults
from("${buildDir}/docs/generated") {
into "asciidoc"
}
from("src/main/java") {
into "main/java"
}
from("src/test/java") {
into "test/java"
}
from("src/main/kotlin") {
into "main/kotlin"
}
from("src/main/groovy") {
into "main/groovy"
}
from("src/main/resources") {
into "main/resources"
}
}
syncDocumentationSourceForAsciidoctorPdf {
dependsOn documentTestSlices
dependsOn documentStarters
dependsOn documentAutoConfigurationClasses
dependsOn documentDependencyVersions
dependsOn documentVersionProperties
dependsOn documentConfigurationProperties
dependsOn documentDevtoolsPropertyDefaults
from("${buildDir}/docs/generated") {
into "asciidoc"
}
from("src/main/java") {
into "main/java"
}
from("src/test/java") {
into "test/java"
}
from("src/main/kotlin") {
into "main/kotlin"
}
from("src/main/groovy") {
into "main/groovy"
}
from("src/main/resources") {
into "main/resources"
}
}
task zip(type: Zip) {
dependsOn asciidoctor,
asciidoctorMultipage,
asciidoctorPdf,
configurations.gradlePluginDocumentation,
configurations.actuatorApiDocumentation,
configurations.mavenPluginDocumentation
duplicatesStrategy "fail"
from(asciidoctor.outputDir) {
into "reference/htmlsingle"
}
from(asciidoctorPdf.outputDir) {
into "reference/pdf"
include "index.pdf"
rename { "spring-boot-reference.pdf" }
}
from(asciidoctorMultipage.outputDir) {
into "reference/html"
}
def antoraApiCatalogContent = tasks.register("antoraApiCatalogContent", Zip) {
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
archiveClassifier = "api-catalog-content"
from(aggregatedJavadoc) {
into "api"
}
into("gradle-plugin") {
from {
zipTree(configurations.gradlePluginDocumentation.singleFile)
}
}
into("actuator-api") {
from {
zipTree(configurations.actuatorApiDocumentation.singleFile)
}
}
into("maven-plugin") {
from {
zipTree(configurations.mavenPluginDocumentation.singleFile)
}
into "java"
}
}
artifacts {
archives zip
def copyAntoraContentDependencies = tasks.register("copyAntoraContentDependencies", Copy) {
into layout.buildDirectory.dir('generated/docs/antora-dependencies-content')
from(configurations.antoraContent)
rename("spring-boot-actuator-autoconfigure", "spring-boot-docs")
rename("spring-boot-maven-plugin", "spring-boot-docs")
rename("spring-boot-gradle-plugin", "spring-boot-docs")
}
tasks.named("antora") {
inputs.files(antoraRootAggregateContent, antoraApiCatalogContent, copyAntoraContentDependencies)
}
gradle.projectsEvaluated {
def mavenPublication = publishing.publications.getByName("maven");
configurations.antoraContent.dependencies.forEach { dependency ->
dependency.dependencyProject.configurations.getByName(dependency.targetConfiguration)
.artifacts.forEach(mavenPublication::artifact)
}
}
publishing {
publications {
maven(MavenPublication) {
artifact zip
getByName("maven") {
artifact antoraRootAggregateContent
artifact antoraApiCatalogContent
}
}
}

View File

@@ -0,0 +1,10 @@
name: spring-boot
ext:
zip_contents_collector:
include:
- name: root
classifier: aggregate-content
- name: api
classifier: catalog-content
module: api
destination: content-catalog

View File

@@ -1,10 +1,9 @@
[[getting-help]]
= Getting Help
include::attributes.adoc[]
:navicon: question
= Community
If you have trouble with Spring Boot, we would like to help.
* Try the <<howto#howto, How-to documents>>.
* Try the xref:how-to:index.adoc[How-to documents].
They provide solutions to the most common questions.
* Learn the Spring basics.
Spring Boot builds on many other Spring projects.
@@ -15,4 +14,4 @@ We monitor https://stackoverflow.com[stackoverflow.com] for questions tagged wit
* Report bugs with Spring Boot at https://github.com/spring-projects/spring-boot/issues.
NOTE: All of Spring Boot is open source, including the documentation.
If you find problems with the docs or if you want to improve them, please {spring-boot-code}[get involved].
If you find problems with the docs or if you want to improve them, please {url-github}[get involved].

View File

@@ -0,0 +1,156 @@
:navtitle: Documentation
:navicon: book
[[documentation]]
= Documentation Overview
This section provides a brief overview of Spring Boot reference documentation.
It serves as a map for the rest of the document.
[[documentation.first-steps]]
== First Steps
If you are getting started with Spring Boot or 'Spring' in general, start with the following topics:
* *From scratch:* xref:index.adoc[Overview] | xref:system-requirements.adoc[Requirements] | xref:installing.adoc[Installation]
* *Tutorial:* xref:tutorial:first-application/index.adoc[Part 1] | xref:tutorial:first-application/index.adoc#getting-started.first-application.code[Part 2]
* *Running your example:* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[Part 1] | xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[Part 2]
[[documentation.upgrading]]
== Upgrading From an Earlier Version
You should always ensure that you are running a {url-github-wiki}/Supported-Versions[supported version] of Spring Boot.
Depending on the version that you are upgrading to, you can find some additional tips here:
* *From 1.x:* xref:upgrading.adoc#upgrading.from-1x[Upgrading from 1.x]
* *To a new feature release:* xref:upgrading.adoc#upgrading.to-feature[Upgrading to New Feature Release]
* *Spring Boot CLI:* xref:upgrading.adoc#upgrading.cli[Upgrading the Spring Boot CLI]
[[documentation.using]]
== Developing With Spring Boot
Ready to actually start using Spring Boot? xref:reference:using/index.adoc[We have you covered]:
* *Build systems:* xref:reference:using/build-systems.adoc#using.build-systems.maven[Maven] | xref:reference:using/build-systems.adoc#using.build-systems.gradle[Gradle] | xref:reference:using/build-systems.adoc#using.build-systems.ant[Ant] | xref:reference:using/build-systems.adoc#using.build-systems.starters[Starters]
* *Best practices:* xref:reference:using/structuring-your-code.adoc[Code Structure] | xref:reference:using/configuration-classes.adoc[@Configuration] | xref:reference:using/auto-configuration.adoc[@EnableAutoConfiguration] | xref:reference:using/spring-beans-and-dependency-injection.adoc[Beans and Dependency Injection]
* *Running your code:* xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[IDE] | xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[Packaged] | xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[Maven] | xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[Gradle]
* *Packaging your app:* xref:reference:using/packaging-for-production.adoc[Production jars]
* *Spring Boot CLI:* xref:cli:index.adoc[Using the CLI]
[[documentation.features]]
== Learning About Spring Boot Features
Need more details about Spring Boot's core features?
xref:reference:features/index.adoc[The following content is for you]:
* *Spring Application:* xref:reference:features/spring-application.adoc[SpringApplication]
* *External Configuration:* xref:reference:features/external-config.adoc[External Configuration]
* *Profiles:* xref:reference:features/profiles.adoc[Profiles]
* *Logging:* xref:reference:features/logging.adoc[Logging]
[[documentation.web]]
== Web
If you develop Spring Boot web applications, take a look at the following content:
* *Servlet Web Applications:* xref:reference:web/servlet.adoc[Spring MVC, Jersey, Embedded Servlet Containers]
* *Reactive Web Applications:* xref:reference:web/reactive.adoc[Spring Webflux, Embedded Servlet Containers]
* *Graceful Shutdown:* xref:reference:web/graceful-shutdown.adoc[Graceful Shutdown]
* *Spring Security:* xref:reference:web/spring-security.adoc[Default Security Configuration, Auto-configuration for OAuth2, SAML]
* *Spring Session:* xref:reference:web/spring-session.adoc[Auto-configuration for Spring Session]
* *Spring HATEOAS:* xref:reference:web/spring-hateoas.adoc[Auto-configuration for Spring HATEOAS]
[[documentation.data]]
== Data
If your application deals with a datastore, you can see how to configure that here:
* *SQL:* xref:reference:data/sql.adoc[Configuring a SQL Datastore, Embedded Database support, Connection pools, and more.]
* *NOSQL:* xref:reference:data/nosql.adoc[Auto-configuration for NOSQL stores such as Redis, MongoDB, Neo4j, and others.]
[[documentation.messaging]]
== Messaging
If your application uses any messaging protocol, see one or more of the following sections:
* *JMS:* xref:reference:messaging/jms.adoc[Auto-configuration for ActiveMQ and Artemis, Sending and Receiving messages through JMS]
* *AMQP:* xref:reference:messaging/amqp.adoc[Auto-configuration for RabbitMQ]
* *Kafka:* xref:reference:messaging/kafka.adoc[Auto-configuration for Spring Kafka]
* *Pulsar:* xref:reference:messaging/pulsar.adoc[Auto-configuration for Spring for Apache Pulsar]
* *RSocket:* xref:reference:messaging/rsocket.adoc[Auto-configuration for Spring Framework's RSocket Support]
* *Spring Integration:* xref:reference:messaging/spring-integration.adoc[Auto-configuration for Spring Integration]
[[documentation.io]]
== IO
If your application needs IO capabilities, see one or more of the following sections:
* *Caching:* xref:reference:io/caching.adoc[Caching support with EhCache, Hazelcast, Infinispan, and more]
* *Quartz:* xref:reference:io/quartz.adoc[Quartz Scheduling]
* *Mail:* xref:reference:io/email.adoc[Sending Email]
* *Validation:* xref:reference:io/validation.adoc[JSR-303 Validation]
* *REST Clients:* xref:reference:io/rest-client.adoc[Calling REST Services with RestTemplate and WebClient]
* *Webservices:* xref:reference:io/webservices.adoc[Auto-configuration for Spring Web Services]
* *JTA:* xref:reference:io/jta.adoc[Distributed Transactions with JTA]
[[documentation.container-images]]
== Container Images
Spring Boot provides first-class support for building efficient container images. You can read more about it here:
* *Efficient Container Images:* xref:reference:container-images/efficient-images.adoc[Tips to optimize container images such as Docker images]
* *Dockerfiles:* xref:reference:container-images/dockerfiles.adoc[Building container images using dockerfiles]
* *Cloud Native Buildpacks:* xref:reference:container-images/cloud-native-buildpacks.adoc[Support for Cloud Native Buildpacks with Maven and Gradle]
[[documentation.actuator]]
== Moving to Production
When you are ready to push your Spring Boot application to production, we have xref:how-to:actuator.adoc[some tricks] that you might like:
* *Management endpoints:* xref:reference:actuator/endpoints.adoc[Overview]
* *Connection options:* xref:reference:actuator/monitoring.adoc[HTTP] | xref:reference:actuator/jmx.adoc[JMX]
* *Monitoring:* xref:reference:actuator/metrics.adoc[Metrics] | xref:reference:actuator/auditing.adoc[Auditing] | xref:reference:actuator/http-exchanges.adoc[HTTP Exchanges] | xref:reference:actuator/process-monitoring.adoc[Process]
[[documentation.native-images]]
== GraalVM Native Images
Spring Boot applications can be converted into native executables using GraalVM.
You can read more about our native image support here:
* *GraalVM Native Images:* xref:reference:native-image/introducing-graalvm-native-images.adoc[Introduction] | xref:reference:native-image/introducing-graalvm-native-images.adoc#native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments[Key Differences with the JVM] | xref:reference:native-image/introducing-graalvm-native-images.adoc#native-image.introducing-graalvm-native-images.understanding-aot-processing[Ahead-of-Time Processing]
* *Getting Started:* xref:reference:native-image/developing-your-first-application.adoc#native-image.developing-your-first-application.buildpacks[Buildpacks] | xref:reference:native-image/developing-your-first-application.adoc#native-image.developing-your-first-application.native-build-tools[Native Build Tools]
* *Testing:* xref:reference:native-image/testing-native-applications.adoc#native-image.testing.with-the-jvm[JVM] | xref:reference:native-image/testing-native-applications.adoc#native-image.testing.with-native-build-tools[Native Build Tools]
* *Advanced Topics:* xref:reference:native-image/advanced-topics.adoc#native-image.advanced.nested-configuration-properties[Nested Configuration Properties] | xref:reference:native-image/advanced-topics.adoc#native-image.advanced.converting-executable-jars[Converting JARs] | xref:reference:native-image/advanced-topics.adoc#native-image.advanced.known-limitations[Known Limitations]
[[documentation.advanced]]
== Advanced Topics
Finally, we have a few topics for more advanced users:
* *Spring Boot Applications Deployment:* xref:reference:deployment/cloud.adoc[Cloud Deployment] | xref:reference:deployment/installing.adoc[OS Service]
* *Build tool plugins:* xref:maven-plugin:index.adoc[Maven] | xref:gradle-plugin:index.adoc[Gradle]
* *Appendix:* xref:appendix:application-properties/index.adoc[Application Properties] | xref:specification:configuration-metadata/index.adoc[Configuration Metadata] | xref:appendix:auto-configuration-classes/index.adoc[Auto-configuration Classes] | xref:appendix:test-auto-configuration/index.adoc[Test Auto-configuration Annotations] | xref:specification:executable-jar/index.adoc[Executable Jars] | xref:appendix:dependency-versions/index.adoc[Dependency Versions]

View File

@@ -1,5 +1,7 @@
[[getting-started.introducing-spring-boot]]
== Introducing Spring Boot
:navtitle: Overview
:navicon: home
= Spring Boot
Spring Boot helps you to create stand-alone, production-grade Spring-based applications that you can run.
We take an opinionated view of the Spring platform and third-party libraries, so that you can get started with minimum fuss.
Most Spring Boot applications need very little Spring configuration.

View File

@@ -1,21 +1,24 @@
:navicon: gift
[[getting-started.installing]]
== Installing Spring Boot
= Installing Spring Boot
Spring Boot can be used with "`classic`" Java development tools or installed as a command line tool.
Either way, you need https://www.java.com[Java SDK v17] or higher.
Before you begin, you should check your current Java installation by using the following command:
[source,shell,indent=0,subs="verbatim"]
[source,shell]
----
$ java -version
$ java -version
----
If you are new to Java development or if you want to experiment with Spring Boot, you might want to try the <<getting-started#getting-started.installing.cli, Spring Boot CLI>> (Command Line Interface) first.
If you are new to Java development or if you want to experiment with Spring Boot, you might want to try the xref:installing.adoc#getting-started.installing.cli[Spring Boot CLI] (Command Line Interface) first.
Otherwise, read on for "`classic`" installation instructions.
[[getting-started.installing.java]]
=== Installation Instructions for the Java Developer
== Installation Instructions for the Java Developer
You can use Spring Boot in the same way as any standard Java library.
To do so, include the appropriate `+spring-boot-*.jar+` files on your classpath.
Spring Boot does not require any special tools integration, so you can use any IDE or text editor.
@@ -26,7 +29,8 @@ Although you _could_ copy Spring Boot jars, we generally recommend that you use
[[getting-started.installing.java.maven]]
==== Maven Installation
=== Maven Installation
Spring Boot is compatible with Apache Maven 3.6.3 or later.
If you do not already have Maven installed, you can follow the instructions at https://maven.apache.org.
@@ -36,35 +40,37 @@ Ubuntu users can run `sudo apt-get install maven`.
Windows users with https://chocolatey.org/[Chocolatey] can run `choco install maven` from an elevated (administrator) prompt.
Spring Boot dependencies use the `org.springframework.boot` group id.
Typically, your Maven POM file inherits from the `spring-boot-starter-parent` project and declares dependencies to one or more <<using#using.build-systems.starters,"`Starters`">>.
Spring Boot also provides an optional <<build-tool-plugins#build-tool-plugins.maven, Maven plugin>> to create executable jars.
Typically, your Maven POM file inherits from the `spring-boot-starter-parent` project and declares dependencies to one or more xref:reference:using/build-systems.adoc#using.build-systems.starters["`Starters`"].
Spring Boot also provides an optional xref:maven-plugin:index.adoc[Maven plugin] to create executable jars.
More details on getting started with Spring Boot and Maven can be found in the {spring-boot-maven-plugin-docs}#getting-started[Getting Started section] of the Maven plugin's reference guide.
More details on getting started with Spring Boot and Maven can be found in the xref:maven-plugin:getting-started.adoc[Getting Started section] of the Maven plugin's reference guide.
[[getting-started.installing.java.gradle]]
==== Gradle Installation
=== Gradle Installation
Spring Boot is compatible with Gradle 7.x (7.5 or later) and 8.x.
If you do not already have Gradle installed, you can follow the instructions at https://gradle.org.
Spring Boot dependencies can be declared by using the `org.springframework.boot` `group`.
Typically, your project declares dependencies to one or more <<using#using.build-systems.starters, "`Starters`">>.
Spring Boot provides a useful <<build-tool-plugins#build-tool-plugins.gradle, Gradle plugin>> that can be used to simplify dependency declarations and to create executable jars.
Typically, your project declares dependencies to one or more xref:reference:using/build-systems.adoc#using.build-systems.starters["`Starters`"].
Spring Boot provides a useful xref:gradle-plugin:index.adoc[Gradle plugin] that can be used to simplify dependency declarations and to create executable jars.
.Gradle Wrapper
****
The Gradle Wrapper provides a nice way of "`obtaining`" Gradle when you need to build a project.
It is a small script and library that you commit alongside your code to bootstrap the build process.
See {gradle-docs}/gradle_wrapper.html for details.
See {url-gradle-docs}/gradle_wrapper.html for details.
****
More details on getting started with Spring Boot and Gradle can be found in the {spring-boot-gradle-plugin-docs}#getting-started[Getting Started section] of the Gradle plugin's reference guide.
More details on getting started with Spring Boot and Gradle can be found in the xref:gradle-plugin:getting-started.adoc[Getting Started section] of the Gradle plugin's reference guide.
[[getting-started.installing.cli]]
=== Installing the Spring Boot CLI
== Installing the Spring Boot CLI
The Spring Boot CLI (Command Line Interface) is a command line tool that you can use to quickly prototype with Spring.
You do not need to use the CLI to work with Spring Boot, but it is a quick way to get a Spring application off the ground without an IDE.
@@ -72,44 +78,46 @@ You do not need to use the CLI to work with Spring Boot, but it is a quick way t
[[getting-started.installing.cli.manual-installation]]
==== Manual Installation
=== Manual Installation
ifeval::["{artifact-release-type}" == "snapshot"]
You can download one of the `spring-boot-cli-\*-bin.zip` or `spring-boot-cli-*-bin.tar.gz` files from the {artifact-download-repo}/org/springframework/boot/spring-boot-cli/{spring-boot-version}/[Spring software repository].
You can download one of the `spring-boot-cli-\*-bin.zip` or `spring-boot-cli-*-bin.tar.gz` files from the {url-artifact-repository}/org/springframework/boot/spring-boot-cli/{version-spring-boot}/[Spring software repository].
endif::[]
ifeval::["{artifact-release-type}" != "snapshot"]
You can download the Spring CLI distribution from one of the following locations:
* {artifact-download-repo}/org/springframework/boot/spring-boot-cli/{spring-boot-version}/spring-boot-cli-{spring-boot-version}-bin.zip[spring-boot-cli-{spring-boot-version}-bin.zip]
* {artifact-download-repo}/org/springframework/boot/spring-boot-cli/{spring-boot-version}/spring-boot-cli-{spring-boot-version}-bin.tar.gz[spring-boot-cli-{spring-boot-version}-bin.tar.gz]
* {url-artifact-repository}/org/springframework/boot/spring-boot-cli/{version-spring-boot}/spring-boot-cli-{version-spring-boot}-bin.zip[spring-boot-cli-{version-spring-boot}-bin.zip]
* {url-artifact-repository}/org/springframework/boot/spring-boot-cli/{version-spring-boot}/spring-boot-cli-{version-spring-boot}-bin.tar.gz[spring-boot-cli-{version-spring-boot}-bin.tar.gz]
endif::[]
Once downloaded, follow the {github-raw}/spring-boot-project/spring-boot-tools/spring-boot-cli/src/main/content/INSTALL.txt[INSTALL.txt] instructions from the unpacked archive.
Once downloaded, follow the {url-github-raw}/spring-boot-project/spring-boot-tools/spring-boot-cli/src/main/content/INSTALL.txt[INSTALL.txt] instructions from the unpacked archive.
In summary, there is a `spring` script (`spring.bat` for Windows) in a `bin/` directory in the `.zip` file.
Alternatively, you can use `java -jar` with the `.jar` file (the script helps you to be sure that the classpath is set correctly).
[[getting-started.installing.cli.sdkman]]
==== Installation with SDKMAN!
=== Installation with SDKMAN!
SDKMAN! (The Software Development Kit Manager) can be used for managing multiple versions of various binary SDKs, including Groovy and the Spring Boot CLI.
Get SDKMAN! from https://sdkman.io and install Spring Boot by using the following commands:
[source,shell,indent=0,subs="verbatim,attributes"]
[source,shell,subs="verbatim,attributes"]
----
$ sdk install springboot
$ spring --version
Spring CLI v{spring-boot-version}
$ sdk install springboot
$ spring --version
Spring CLI v{version-spring-boot}
----
If you develop features for the CLI and want access to the version you built, use the following commands:
[source,shell,indent=0,subs="verbatim,attributes"]
[source,shell,subs="verbatim,attributes"]
----
$ sdk install springboot dev /path/to/spring-boot/spring-boot-cli/target/spring-boot-cli-{spring-boot-version}-bin/spring-{spring-boot-version}/
$ sdk default springboot dev
$ spring --version
Spring CLI v{spring-boot-version}
$ sdk install springboot dev /path/to/spring-boot/spring-boot-cli/target/spring-boot-cli-{version-spring-boot}-bin/spring-{version-spring-boot}/
$ sdk default springboot dev
$ spring --version
Spring CLI v{version-spring-boot}
----
The preceding instructions install a local instance of `spring` called the `dev` instance.
@@ -117,33 +125,34 @@ It points at your target build location, so every time you rebuild Spring Boot,
You can see it by running the following command:
[source,shell,indent=0,subs="verbatim,attributes"]
[source,shell,subs="verbatim,attributes"]
----
$ sdk ls springboot
$ sdk ls springboot
================================================================================
Available Springboot Versions
================================================================================
> + dev
* {spring-boot-version}
================================================================================
Available Springboot Versions
================================================================================
> + dev
* {version-spring-boot}
================================================================================
+ - local version
* - installed
> - currently in use
================================================================================
================================================================================
+ - local version
* - installed
> - currently in use
================================================================================
----
[[getting-started.installing.cli.homebrew]]
==== OSX Homebrew Installation
=== OSX Homebrew Installation
If you are on a Mac and use https://brew.sh/[Homebrew], you can install the Spring Boot CLI by using the following commands:
[source,shell,indent=0,subs="verbatim"]
[source,shell]
----
$ brew tap spring-io/tap
$ brew install spring-boot
$ brew tap spring-io/tap
$ brew install spring-boot
----
Homebrew installs `spring` to `/usr/local/bin`.
@@ -154,28 +163,30 @@ In that case, run `brew update` and try again.
[[getting-started.installing.cli.macports]]
==== MacPorts Installation
=== MacPorts Installation
If you are on a Mac and use https://www.macports.org/[MacPorts], you can install the Spring Boot CLI by using the following command:
[source,shell,indent=0,subs="verbatim"]
[source,shell]
----
$ sudo port install spring-boot-cli
$ sudo port install spring-boot-cli
----
[[getting-started.installing.cli.completion]]
==== Command-line Completion
=== Command-line Completion
The Spring Boot CLI includes scripts that provide command completion for the https://en.wikipedia.org/wiki/Bash_%28Unix_shell%29[BASH] and https://en.wikipedia.org/wiki/Z_shell[zsh] shells.
You can `source` the script (also named `spring`) in any shell or put it in your personal or system-wide bash completion initialization.
On a Debian system, the system-wide scripts are in `<installation location>/shell-completion/bash` and all scripts in that directory are executed when a new shell starts.
For example, to run the script manually if you have installed by using SDKMAN!, use the following commands:
[source,shell,indent=0,subs="verbatim"]
[source,shell]
----
$ . ~/.sdkman/candidates/springboot/current/shell-completion/bash/spring
$ spring <HIT TAB HERE>
grab help jar run test version
$ . ~/.sdkman/candidates/springboot/current/shell-completion/bash/spring
$ spring <HIT TAB HERE>
grab help jar run test version
----
NOTE: If you install the Spring Boot CLI by using Homebrew or MacPorts, the command-line completion scripts are automatically registered with your shell.
@@ -183,13 +194,14 @@ NOTE: If you install the Spring Boot CLI by using Homebrew or MacPorts, the comm
[[getting-started.installing.cli.scoop]]
==== Windows Scoop Installation
=== Windows Scoop Installation
If you are on a Windows and use https://scoop.sh/[Scoop], you can install the Spring Boot CLI by using the following commands:
[indent=0]
[source,shell]
----
> scoop bucket add extras
> scoop install springboot
$ scoop bucket add extras
$ scoop install springboot
----
Scoop installs `spring` to `~/scoop/apps/springboot/current/bin`.

View File

@@ -1,7 +1,9 @@
:navicon: server
[[getting-started.system-requirements]]
== System Requirements
Spring Boot {spring-boot-version} requires https://www.java.com[Java 17] and is compatible up to and including Java 21.
{spring-framework-docs}/[Spring Framework {spring-framework-version}] or above is also required.
= System Requirements
Spring Boot {version-spring-boot} requires https://www.java.com[Java 17] and is compatible up to and including Java 21.
{url-spring-framework-docs}/[Spring Framework {version-spring-framework}] or above is also required.
Explicit build support is provided for the following build tools:
@@ -18,7 +20,8 @@ Explicit build support is provided for the following build tools:
[[getting-started.system-requirements.servlet-containers]]
=== Servlet Containers
== Servlet Containers
Spring Boot supports the following embedded servlet containers:
|===
@@ -39,8 +42,9 @@ You can also deploy Spring Boot applications to any servlet 5.0+ compatible cont
[[getting-started.system-requirements.graal]]
=== GraalVM Native Images
Spring Boot applications can be <<native-image#native-image.introducing-graalvm-native-images,converted into a Native Image>> using GraalVM {graal-version} or above.
== GraalVM Native Images
Spring Boot applications can be xref:reference:native-image/introducing-graalvm-native-images.adoc[converted into a Native Image] using GraalVM {version-graal} or above.
Images can be created using the https://github.com/graalvm/native-build-tools[native build tools] Gradle/Maven plugins or `native-image` tool provided by GraalVM.
You can also create native images using the https://github.com/paketo-buildpacks/native-image[native-image Paketo buildpack].
@@ -51,8 +55,8 @@ The following versions are supported:
| Name | Version
| GraalVM Community
| {graal-version}
| {version-graal}
| Native Build Tools
| {native-build-tools-version}
| {version-native-build-tools}
|===

View File

@@ -0,0 +1,47 @@
:navicon: rocket
[[upgrading]]
= Upgrading Spring Boot
Instructions for how to upgrade from earlier versions of Spring Boot are provided on the project {url-github-wiki}[wiki].
Follow the links in the {url-github-wiki}#release-notes[release notes] section to find the version that you want to upgrade to.
Upgrading instructions are always the first item in the release notes.
If you are more than one release behind, please make sure that you also review the release notes of the versions that you jumped.
[[upgrading.from-1x]]
== Upgrading From 1.x
If you are upgrading from the `1.x` release of Spring Boot, check the {url-github-wiki}/Spring-Boot-2.0-Migration-Guide["`migration guide`" on the project wiki] that provides detailed upgrade instructions.
Check also the {url-github-wiki}["`release notes`"] for a list of "`new and noteworthy`" features for each release.
[[upgrading.to-feature]]
== Upgrading to a New Feature Release
When upgrading to a new feature release, some properties may have been renamed or removed.
Spring Boot provides a way to analyze your application's environment and print diagnostics at startup, but also temporarily migrate properties at runtime for you.
To enable that feature, add the following dependency to your project:
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
----
WARNING: Properties that are added late to the environment, such as when using `@PropertySource`, will not be taken into account.
NOTE: Once you finish the migration, please make sure to remove this module from your project's dependencies.
[[upgrading.cli]]
== Upgrading the Spring Boot CLI
To upgrade an existing CLI installation, use the appropriate package manager command (for example, `brew upgrade`).
If you manually installed the CLI, follow the xref:installing.adoc#getting-started.installing.cli.manual-installation[standard instructions], remembering to update your `PATH` environment variable to remove any older references.

View File

@@ -0,0 +1,6 @@
* xref:index.adoc[]
* xref:documentation.adoc[]
* xref:community.adoc[]
* xref:system-requirements.adoc[]
* xref:installing.adoc[]
* xref:upgrading.adoc[]

View File

@@ -0,0 +1,4 @@
* Java APIs
** xref:api:java/index.html[Spring Boot]
** xref:gradle-plugin:api/java/index.html[Gradle Plugin]
** xref:maven-plugin:api/java/index.html[Maven Plugin]

View File

@@ -0,0 +1,5 @@
* Rest APIs
+
--
include::api:partial$nav-actuator-rest-api.adoc[]
--

View File

@@ -0,0 +1,48 @@
[appendix]
[[appendix.application-properties]]
= Common Application Properties
Various properties can be specified inside your `application.properties` file, inside your `application.yaml` file, or as command line switches.
This appendix provides a list of common Spring Boot properties and references to the underlying classes that consume them.
TIP: Spring Boot provides various conversion mechanism with advanced value formatting, make sure to review xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[the properties conversion section].
NOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list.
Also, you can define your own properties.
include::partial$configuration-properties/core.adoc[]
include::partial$configuration-properties/cache.adoc[]
include::partial$configuration-properties/mail.adoc[]
include::partial$configuration-properties/json.adoc[]
include::partial$configuration-properties/data.adoc[]
include::partial$configuration-properties/transaction.adoc[]
include::partial$configuration-properties/data-migration.adoc[]
include::partial$configuration-properties/integration.adoc[]
include::partial$configuration-properties/web.adoc[]
include::partial$configuration-properties/templating.adoc[]
include::partial$configuration-properties/server.adoc[]
include::partial$configuration-properties/security.adoc[]
include::partial$configuration-properties/rsocket.adoc[]
include::partial$configuration-properties/actuator.adoc[]
include::partial$configuration-properties/devtools.adoc[]
include::partial$configuration-properties/docker-compose.adoc[]
include::partial$configuration-properties/testcontainers.adoc[]
include::partial$configuration-properties/testing.adoc[]

View File

@@ -1,5 +1,6 @@
[[appendix.auto-configuration-classes.actuator]]
== spring-boot-actuator-autoconfigure
= spring-boot-actuator-autoconfigure
The following auto-configuration classes are from the `spring-boot-actuator-autoconfigure` module:
include::documented-auto-configuration-classes/spring-boot-actuator-autoconfigure.adoc[]
include::partial$/auto-configuration-classes/spring-boot-actuator-autoconfigure.adoc[]

View File

@@ -1,5 +1,6 @@
[[appendix.auto-configuration-classes.core]]
== spring-boot-autoconfigure
= spring-boot-autoconfigure
The following auto-configuration classes are from the `spring-boot-autoconfigure` module:
include::documented-auto-configuration-classes/spring-boot-autoconfigure.adoc[]
include::partial$/auto-configuration-classes/spring-boot-autoconfigure.adoc[]

View File

@@ -1,16 +1,7 @@
[appendix]
[[appendix.auto-configuration-classes]]
= Auto-configuration Classes
include::attributes.adoc[]
This appendix contains details of all of the auto-configuration classes provided by Spring Boot, with links to documentation and source code.
Remember to also look at the conditions report in your application for more details of which features are switched on.
(To do so, start the app with `--debug` or `-Ddebug` or, in an Actuator application, use the `conditions` endpoint).
include::auto-configuration-classes/core.adoc[]
include::auto-configuration-classes/actuator.adoc[]

View File

@@ -1,7 +1,7 @@
[[appendix.dependency-versions.coordinates]]
== Managed Dependency Coordinates
= Managed Dependency Coordinates
The following table provides details of all of the dependency versions that are provided by Spring Boot in its CLI (Command Line Interface), Maven dependency management, and Gradle plugin.
When you declare a dependency on one of these artifacts without declaring a version, the version listed in the table is used.
include::documented-coordinates.adoc[]
include::partial$dependency-versions/documented-coordinates.adoc[]

View File

@@ -1,14 +1,5 @@
[appendix]
[[appendix.dependency-versions]]
= Dependency Versions
include::attributes.adoc[]
This appendix provides details of the dependencies that are managed by Spring Boot.
include::dependency-versions/coordinates.adoc[]
include::dependency-versions/properties.adoc[]

View File

@@ -1,8 +1,8 @@
[[appendix.dependency-versions.properties]]
== Version Properties
= Version Properties
The following table provides all properties that can be used to override the versions managed by Spring Boot.
Browse the {spring-boot-code}/spring-boot-project/spring-boot-dependencies/build.gradle[`spring-boot-dependencies` build.gradle] for a complete list of dependencies.
You can learn how to customize these versions in your application in the <<build-tool-plugins#build-tool-plugins,Build Tool Plugins documentation>>.
Browse the {code-spring-boot}/spring-boot-project/spring-boot-dependencies/build.gradle[`spring-boot-dependencies` build.gradle] for a complete list of dependencies.
You can learn how to customize these versions in your application in the xref:build-tool-plugin:index.adoc[Build Tool Plugins documentation].
include::documented-properties.adoc[]
include::partial$dependency-versions/documented-properties.adoc[]

View File

@@ -1,12 +1,5 @@
[appendix]
[[appendix.test-auto-configuration]]
= Test Auto-configuration Annotations
include::attributes.adoc[]
This appendix describes the `@...Test` auto-configuration annotations that Spring Boot provides to test slices of your application.
include::test-auto-configuration/slices.adoc[]

View File

@@ -1,6 +1,6 @@
[[appendix.test-auto-configuration.slices]]
== Test Slices
= Test Slices
The following table lists the various `@...Test` annotations that can be used to test slices of your application and the auto-configuration that they import by default:
include::documented-slices.adoc[]
include::partial$slices/documented-slices.adoc[]

View File

@@ -0,0 +1,13 @@
* Appendix
** xref:appendix:application-properties/index.adoc[]
** xref:appendix:auto-configuration-classes/index.adoc[]
*** xref:appendix:auto-configuration-classes/core.adoc[]
*** xref:appendix:auto-configuration-classes/actuator.adoc[]
** xref:appendix:test-auto-configuration/index.adoc[]
*** xref:appendix:test-auto-configuration/slices.adoc[]
** xref:appendix:dependency-versions/index.adoc[]
*** xref:appendix:dependency-versions/coordinates.adoc[]
*** xref:appendix:dependency-versions/properties.adoc[]

View File

@@ -1,40 +1,43 @@
[[build-tool-plugins.antlib]]
== Spring Boot AntLib Module
= Spring Boot AntLib Module
The Spring Boot AntLib module provides basic Spring Boot support for Apache Ant.
You can use the module to create executable jars.
To use the module, you need to declare an additional `spring-boot` namespace in your `build.xml`, as shown in the following example:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<project xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:spring-boot="antlib:org.springframework.boot.ant"
name="myapp" default="build">
...
</project>
<project xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:spring-boot="antlib:org.springframework.boot.ant"
name="myapp" default="build">
...
</project>
----
You need to remember to start Ant using the `-lib` option, as shown in the following example:
[source,shell,indent=0,subs="verbatim,attributes"]
[source,shell,subs="verbatim,attributes"]
----
$ ant -lib <directory containing spring-boot-antlib-{spring-boot-version}.jar>
$ ant -lib <directory containing spring-boot-antlib-{version-spring-boot}.jar>
----
TIP: The "`Using Spring Boot`" section includes a more complete example of <<using#using.build-systems.ant, using Apache Ant with `spring-boot-antlib`>>.
TIP: The "`Using Spring Boot`" section includes a more complete example of xref:reference:using/build-systems.adoc#using.build-systems.ant[using Apache Ant with `spring-boot-antlib`].
[[build-tool-plugins.antlib.tasks]]
=== Spring Boot Ant Tasks
== Spring Boot Ant Tasks
Once the `spring-boot-antlib` namespace has been declared, the following additional tasks are available:
* <<build-tool-plugins#build-tool-plugins.antlib.tasks.exejar>>
* <<build-tool-plugins#build-tool-plugins.antlib.findmainclass>>
* xref:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[Using the "`exejar`" Task]
* xref:antlib.adoc#build-tool-plugins.antlib.findmainclass[Using the "`findmainclass`" Task]
[[build-tool-plugins.antlib.tasks.exejar]]
==== Using the "`exejar`" Task
=== Using the "`exejar`" Task
You can use the `exejar` task to create a Spring Boot executable jar.
The following attributes are supported by the task:
@@ -62,46 +65,48 @@ The following nested elements can be used with the task:
| Element | Description
| `resources`
| One or more {ant-docs}/Types/resources.html#collection[Resource Collections] describing a set of {ant-docs}/Types/resources.html[Resources] that should be added to the content of the created +jar+ file.
| One or more {url-ant-docs}/Types/resources.html#collection[Resource Collections] describing a set of {url-ant-docs}/Types/resources.html[Resources] that should be added to the content of the created +jar+ file.
| `lib`
| One or more {ant-docs}/Types/resources.html#collection[Resource Collections] that should be added to the set of jar libraries that make up the runtime dependency classpath of the application.
| One or more {url-ant-docs}/Types/resources.html#collection[Resource Collections] that should be added to the set of jar libraries that make up the runtime dependency classpath of the application.
|====
[[build-tool-plugins.antlib.tasks.examples]]
==== Examples
=== Examples
This section shows two examples of Ant tasks.
.Specify +start-class+
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<spring-boot:exejar destfile="target/my-application.jar"
classes="target/classes" start-class="com.example.MyApplication">
<resources>
<fileset dir="src/main/resources" />
</resources>
<lib>
<fileset dir="lib" />
</lib>
</spring-boot:exejar>
<spring-boot:exejar destfile="target/my-application.jar"
classes="target/classes" start-class="com.example.MyApplication">
<resources>
<fileset dir="src/main/resources" />
</resources>
<lib>
<fileset dir="lib" />
</lib>
</spring-boot:exejar>
----
.Detect +start-class+
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<exejar destfile="target/my-application.jar" classes="target/classes">
<lib>
<fileset dir="lib" />
</lib>
</exejar>
<exejar destfile="target/my-application.jar" classes="target/classes">
<lib>
<fileset dir="lib" />
</lib>
</exejar>
----
[[build-tool-plugins.antlib.findmainclass]]
=== Using the "`findmainclass`" Task
== Using the "`findmainclass`" Task
The `findmainclass` task is used internally by `exejar` to locate a class declaring a `main`.
If necessary, you can also use this task directly in your build.
The following attributes are supported:
@@ -126,23 +131,24 @@ The following attributes are supported:
[[build-tool-plugins.antlib.findmainclass.examples]]
==== Examples
=== Examples
This section contains three examples of using `findmainclass`.
.Find and log
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<findmainclass classesroot="target/classes" />
<findmainclass classesroot="target/classes" />
----
.Find and set
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<findmainclass classesroot="target/classes" property="main-class" />
<findmainclass classesroot="target/classes" property="main-class" />
----
.Override and set
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<findmainclass mainclass="com.example.MainClass" property="main-class" />
<findmainclass mainclass="com.example.MainClass" property="main-class" />
----

View File

@@ -0,0 +1,8 @@
[[build-tool-plugins]]
= Build Tool Plugins
Spring Boot provides build tool plugins for Maven and Gradle.
The plugins offer a variety of features, including the packaging of executable jars.
This section provides more details on both plugins as well as some help should you need to extend an unsupported build system.
If you are just getting started, you might want to read "`xref:reference:using/build-systems.adoc[Build Systems]`" from the "`xref:reference:using/index.adoc[Developing with Spring Boot]`" section first.

View File

@@ -1,7 +1,8 @@
[[build-tool-plugins.other-build-systems]]
== Supporting Other Build Systems
= Supporting Other Build Systems
If you want to use a build tool other than Maven, Gradle, or Ant, you likely need to develop your own plugin.
Executable jars need to follow a specific format and certain entries need to be written in an uncompressed form (see the "`<<executable-jar#appendix.executable-jar, executable jar format>>`" section in the appendix for details).
Executable jars need to follow a specific format and certain entries need to be written in an uncompressed form (see the "`xref:specification:/executable-jar/index.adoc[executable jar format]`" section in the appendix for details).
The Spring Boot Maven and Gradle plugins both make use of `spring-boot-loader-tools` to actually generate jars.
If you need to, you may use this library directly.
@@ -9,7 +10,8 @@ If you need to, you may use this library directly.
[[build-tool-plugins.other-build-systems.repackaging-archives]]
=== Repackaging Archives
== Repackaging Archives
To repackage an existing archive so that it becomes a self-contained executable archive, use `org.springframework.boot.loader.tools.Repackager`.
The `Repackager` class takes a single constructor argument that refers to an existing jar or war archive.
Use one of the two available `repackage()` methods to either replace the original file or write to a new destination.
@@ -18,7 +20,8 @@ Various settings can also be configured on the repackager before it is run.
[[build-tool-plugins.other-build-systems.nested-libraries]]
=== Nested Libraries
== Nested Libraries
When repackaging an archive, you can include references to dependency files by using the `org.springframework.boot.loader.tools.Libraries` interface.
We do not provide any concrete implementations of `Libraries` here as they are usually build-system-specific.
@@ -27,14 +30,16 @@ If your archive already includes libraries, you can use `Libraries.NONE`.
[[build-tool-plugins.other-build-systems.finding-main-class]]
=== Finding a Main Class
== Finding a Main Class
If you do not use `Repackager.setMainClass()` to specify a main class, the repackager uses https://asm.ow2.io/[ASM] to read class files and tries to find a suitable class with a `public static void main(String[] args)` method.
An exception is thrown if more than one candidate is found.
[[build-tool-plugins.other-build-systems.example-repackage-implementation]]
=== Example Repackage Implementation
== Example Repackage Implementation
The following example shows a typical repackage implementation:
include::code:MyBuildTool[]
include-code::MyBuildTool[]

View File

@@ -0,0 +1,11 @@
* xref:build-tool-plugin:index.adoc[]
+
--
include::maven-plugin:partial$nav-maven-plugin.adoc[]
--
+
--
include::gradle-plugin:partial$nav-gradle-plugin.adoc[]
--
** xref:build-tool-plugin:antlib.adoc[]
** xref:build-tool-plugin:other-build-systems.adoc[]

View File

@@ -1,12 +1,5 @@
[[cli]]
= Spring Boot CLI
include::attributes.adoc[]
The Spring Boot CLI is a command line tool that you can use to bootstrap a new project from https://start.spring.io or encode a password.
include::cli/installation.adoc[]
include::cli/using-the-cli.adoc[]

View File

@@ -0,0 +1,5 @@
[[cli.installation]]
= Installing the CLI
The Spring Boot CLI (Command-Line Interface) can be installed manually by using SDKMAN! (the SDK Manager) or by using Homebrew or MacPorts if you are an OSX user.
See xref:ROOT:installing.adoc#getting-started.installing.cli[_Installing the Spring Boot CLI_] in the "`Getting started`" section for comprehensive installation instructions.

View File

@@ -0,0 +1,177 @@
[[cli.using-the-cli]]
= Using the CLI
Once you have installed the CLI, you can run it by typing `spring` and pressing Enter at the command line.
If you run `spring` without any arguments, a help screen is displayed, as follows:
[source,shell]
----
$ spring
usage: spring [--help] [--version]
<command> [<args>]
Available commands are:
init [options] [location]
Initialize a new project using Spring Initializr (start.spring.io)
encodepassword [options] <password to encode>
Encode a password for use with Spring Security
shell
Start a nested shell
Common options:
--debug Verbose mode
Print additional status information for the command you are running
See 'spring help <command>' for more information on a specific command.
----
You can type `spring help` to get more details about any of the supported commands, as shown in the following example:
[source,shell]
----
$ spring help init
spring init - Initialize a new project using Spring Initializr (start.spring.io)
usage: spring init [options] [location]
Option Description
------ -----------
-a, --artifact-id <String> Project coordinates; infer archive name (for
example 'test')
-b, --boot-version <String> Spring Boot version (for example '1.2.0.RELEASE')
--build <String> Build system to use (for example 'maven' or
'gradle') (default: maven)
-d, --dependencies <String> Comma-separated list of dependency identifiers to
include in the generated project
--description <String> Project description
-f, --force Force overwrite of existing files
--format <String> Format of the generated content (for example
'build' for a build file, 'project' for a
project archive) (default: project)
-g, --group-id <String> Project coordinates (for example 'org.test')
-j, --java-version <String> Language level (for example '1.8')
-l, --language <String> Programming language (for example 'java')
--list List the capabilities of the service. Use it to
discover the dependencies and the types that are
available
-n, --name <String> Project name; infer application name
-p, --packaging <String> Project packaging (for example 'jar')
--package-name <String> Package name
-t, --type <String> Project type. Not normally needed if you use --
build and/or --format. Check the capabilities of
the service (--list) for more details
--target <String> URL of the service to use (default: https://start.
spring.io)
-v, --version <String> Project version (for example '0.0.1-SNAPSHOT')
-x, --extract Extract the project archive. Inferred if a
location is specified without an extension
examples:
To list all the capabilities of the service:
$ spring init --list
To creates a default project:
$ spring init
To create a web my-app.zip:
$ spring init -d=web my-app.zip
To create a web/data-jpa gradle project unpacked:
$ spring init -d=web,jpa --build=gradle my-dir
----
The `version` command provides a quick way to check which version of Spring Boot you are using, as follows:
[source,shell,subs="verbatim,attributes"]
----
$ spring version
Spring CLI v{version-spring-boot}
----
[[cli.using-the-cli.initialize-new-project]]
== Initialize a New Project
The `init` command lets you create a new project by using https://start.spring.io without leaving the shell, as shown in the following example:
[source,shell]
----
$ spring init --dependencies=web,data-jpa my-project
Using service at https://start.spring.io
Project extracted to '/Users/developer/example/my-project'
----
The preceding example creates a `my-project` directory with a Maven-based project that uses `spring-boot-starter-web` and `spring-boot-starter-data-jpa`.
You can list the capabilities of the service by using the `--list` flag, as shown in the following example:
[source,shell]
----
$ spring init --list
=======================================
Capabilities of https://start.spring.io
=======================================
Available dependencies:
-----------------------
actuator - Actuator: Production ready features to help you monitor and manage your application
...
web - Web: Support for full-stack web development, including Tomcat and spring-webmvc
websocket - Websocket: Support for WebSocket development
ws - WS: Support for Spring Web Services
Available project types:
------------------------
gradle-build - Gradle Config [format:build, build:gradle]
gradle-project - Gradle Project [format:project, build:gradle]
maven-build - Maven POM [format:build, build:maven]
maven-project - Maven Project [format:project, build:maven] (default)
...
----
The `init` command supports many options.
See the `help` output for more details.
For instance, the following command creates a Gradle project that uses Java 17 and `war` packaging:
[source,shell]
----
$ spring init --build=gradle --java-version=17 --dependencies=websocket --packaging=war sample-app.zip
Using service at https://start.spring.io
Content saved to 'sample-app.zip'
----
[[cli.using-the-cli.embedded-shell]]
== Using the Embedded Shell
Spring Boot includes command-line completion scripts for the BASH and zsh shells.
If you do not use either of these shells (perhaps you are a Windows user), you can use the `shell` command to launch an integrated shell, as shown in the following example:
[source,shell,subs="verbatim,quotes,attributes"]
----
$ spring shell
*Spring Boot* (v{version-spring-boot})
Hit TAB to complete. Type \'help' and hit RETURN for help, and \'exit' to quit.
----
From inside the embedded shell, you can run other commands directly:
[source,shell,subs="verbatim,attributes"]
----
$ version
Spring CLI v{version-spring-boot}
----
The embedded shell supports ANSI color output as well as `tab` completion.
If you need to run a native command, you can use the `!` prefix.
To exit the embedded shell, press `ctrl-c`.

View File

@@ -0,0 +1,4 @@
* xref:cli:index.adoc[]
** xref:cli:installation.adoc[]
** xref:cli:using-the-cli.adoc[]

View File

@@ -1,22 +1,25 @@
[[howto.actuator]]
== Actuator
= Actuator
Spring Boot includes the Spring Boot Actuator.
This section answers questions that often arise from its use.
[[howto.actuator.change-http-port-or-address]]
=== Change the HTTP Port or Address of the Actuator Endpoints
== Change the HTTP Port or Address of the Actuator Endpoints
In a standalone application, the Actuator HTTP port defaults to the same as the main HTTP port.
To make the application listen on a different port, set the external property: configprop:management.server.port[].
To listen on a completely different network address (such as when you have an internal network for management and an external one for user applications), you can also set `management.server.address` to a valid IP address to which the server is able to bind.
For more detail, see the {spring-boot-actuator-autoconfigure-module-code}/web/server/ManagementServerProperties.java[`ManagementServerProperties`] source code and "`<<actuator#actuator.monitoring.customizing-management-server-port>>`" in the "`Production-ready features`" section.
For more detail, see the {code-spring-boot-actuator-autoconfigure-src}/web/server/ManagementServerProperties.java[`ManagementServerProperties`] source code and "`xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[Customizing the Management Server Port]`" in the "`Production-ready features`" section.
[[howto.actuator.customize-whitelabel-error-page]]
=== Customize the '`whitelabel`' Error Page
== Customize the '`whitelabel`' Error Page
Spring Boot installs a '`whitelabel`' error page that you see in a browser client if you encounter a server error (machine clients consuming JSON and other media types should see a sensible response with the right error code).
NOTE: Set `server.error.whitelabel.enabled=false` to switch the default error page off.
@@ -28,14 +31,15 @@ For example, if you use Thymeleaf, you can add an `error.html` template.
If you use FreeMarker, you can add an `error.ftlh` template.
In general, you need a `View` that resolves with a name of `error` or a `@Controller` that handles the `/error` path.
Unless you replaced some of the default configuration, you should find a `BeanNameViewResolver` in your `ApplicationContext`, so a `@Bean` named `error` would be one way of doing that.
See {spring-boot-autoconfigure-module-code}/web/servlet/error/ErrorMvcAutoConfiguration.java[`ErrorMvcAutoConfiguration`] for more options.
See {code-spring-boot-autoconfigure-src}/web/servlet/error/ErrorMvcAutoConfiguration.java[`ErrorMvcAutoConfiguration`] for more options.
See also the section on "`<<web#web.servlet.spring-mvc.error-handling, Error Handling>>`" for details of how to register handlers in the servlet container.
See also the section on "`xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[Error Handling]`" for details of how to register handlers in the servlet container.
[[howto.actuator.customizing-sanitization]]
=== Customizing Sanitization
== Customizing Sanitization
To take control over the sanitization, define a `SanitizingFunction` bean.
The `SanitizableData` with which the function is called provides access to the key and value as well as the `PropertySource` from which they came.
This allows you to, for example, sanitize every value that comes from a particular property source.
@@ -44,7 +48,8 @@ Each `SanitizingFunction` is called in order until a function changes the value
[[howto.actuator.map-health-indicators-to-metrics]]
=== Map Health Indicators to Micrometer Metrics
== Map Health Indicators to Micrometer Metrics
Spring Boot health indicators return a `Status` type to indicate the overall system health.
If you want to monitor or alert on levels of health for a particular application, you can export these statuses as metrics with Micrometer.
By default, the status codes "`UP`", "`DOWN`", "`OUT_OF_SERVICE`" and "`UNKNOWN`" are used by Spring Boot.
@@ -52,4 +57,4 @@ To export these, you will need to convert these states to some set of numbers so
The following example shows one way to write such an exporter:
include::code:MyHealthMetricsExportConfiguration[]
include-code::MyHealthMetricsExportConfiguration[]

View File

@@ -0,0 +1,55 @@
[[howto.aot]]
= Ahead-of-time processing
A number of questions often arise when people use the ahead-of-time processing of Spring Boot applications.
This section addresses those questions.
[[howto.aot.conditions]]
== Conditions
Ahead-of-time processing optimizes the application and evaluates {url-spring-framework-javadoc}/org/springframework/context/annotation/Conditional.html[conditions] based on the environment at build time.
xref:reference:features/profiles.adoc[Profiles] are implemented through conditions and are therefore affected, too.
If you want beans that are created based on a condition in an ahead-of-time optimized application, you have to set up the environment when building the application.
The beans which are created while ahead-of-time processing at build time are then always created when running the application and can't be switched off.
To do this, you can set the profiles which should be used when building the application.
For Maven, this works by setting the `profiles` configuration of the `spring-boot-maven-plugin:process-aot` execution:
[source,xml]
----
<profile>
<id>native</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>process-aot</id>
<configuration>
<profiles>profile-a,profile-b</profiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
----
For Gradle, you need to configure the `ProcessAot` task:
[source,gradle]
----
tasks.withType(org.springframework.boot.gradle.tasks.aot.ProcessAot).configureEach {
args('--spring.profiles.active=profile-a,profile-b')
}
----
Profiles which only change configuration properties that don't influence conditions are supported without limitations when running ahead-of-time optimized applications.

View File

@@ -1,12 +1,14 @@
[[howto.application]]
== Spring Boot Application
= Spring Boot Application
This section includes topics relating directly to Spring Boot applications.
[[howto.application.failure-analyzer]]
=== Create Your Own FailureAnalyzer
{spring-boot-module-api}/diagnostics/FailureAnalyzer.html[`FailureAnalyzer`] is a great way to intercept an exception on startup and turn it into a human-readable message, wrapped in a {spring-boot-module-api}/diagnostics/FailureAnalysis.html[`FailureAnalysis`].
== Create Your Own FailureAnalyzer
xref:api:java/org/springframework/boot/diagnostics/FailureAnalyzer.html[`FailureAnalyzer`] is a great way to intercept an exception on startup and turn it into a human-readable message, wrapped in a xref:api:java/org/springframework/boot/diagnostics/FailureAnalysis.html[`FailureAnalysis`].
Spring Boot provides such an analyzer for application-context-related exceptions, JSR-303 validations, and more.
You can also create your own.
@@ -17,10 +19,10 @@ If, for whatever reason, you cannot handle the exception, return `null` to give
`FailureAnalyzer` implementations must be registered in `META-INF/spring.factories`.
The following example registers `ProjectConstraintViolationFailureAnalyzer`:
[source,properties,indent=0,subs="verbatim"]
[source,properties]
----
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
----
NOTE: If you need access to the `BeanFactory` or the `Environment`, declare them as constructor arguments in your `FailureAnalyzer` implementation.
@@ -28,12 +30,13 @@ NOTE: If you need access to the `BeanFactory` or the `Environment`, declare them
[[howto.application.troubleshoot-auto-configuration]]
=== Troubleshoot Auto-configuration
== Troubleshoot Auto-configuration
The Spring Boot auto-configuration tries its best to "`do the right thing`", but sometimes things fail, and it can be hard to tell why.
There is a really useful `ConditionEvaluationReport` available in any Spring Boot `ApplicationContext`.
You can see it if you enable `DEBUG` logging output.
If you use the `spring-boot-actuator` (see <<actuator#actuator,the Actuator chapter>>), there is also a `conditions` endpoint that renders the report in JSON.
If you use the `spring-boot-actuator` (see xref:actuator.adoc[the Actuator chapter]), there is also a `conditions` endpoint that renders the report in JSON.
Use that endpoint to debug the application and see what features have been added (and which have not been added) by Spring Boot at runtime.
Many more questions can be answered by looking at the source code and the Javadoc.
@@ -43,7 +46,7 @@ When reading the code, remember the following rules of thumb:
Pay special attention to the `+@Conditional*+` annotations to find out what features they enable and when.
Add `--debug` to the command line or a System property `-Ddebug` to get a log on the console of all the auto-configuration decisions that were made in your app.
In a running application with actuator enabled, look at the `conditions` endpoint (`/actuator/conditions` or the JMX equivalent) for the same information.
* Look for classes that are `@ConfigurationProperties` (such as {spring-boot-autoconfigure-module-code}/web/ServerProperties.java[`ServerProperties`]) and read from there the available external configuration options.
* Look for classes that are `@ConfigurationProperties` (such as {code-spring-boot-autoconfigure-src}/web/ServerProperties.java[`ServerProperties`]) and read from there the available external configuration options.
The `@ConfigurationProperties` annotation has a `name` attribute that acts as a prefix to external properties.
Thus, `ServerProperties` has `prefix="server"` and its configuration properties are `server.port`, `server.address`, and others.
In a running application with actuator enabled, look at the `configprops` endpoint.
@@ -55,7 +58,8 @@ When reading the code, remember the following rules of thumb:
[[howto.application.customize-the-environment-or-application-context]]
=== Customize the Environment or ApplicationContext Before It Starts
== Customize the Environment or ApplicationContext Before It Starts
A `SpringApplication` has `ApplicationListeners` and `ApplicationContextInitializers` that are used to apply customizations to the context or environment.
Spring Boot loads a number of such customizations for use internally from `META-INF/spring.factories`.
There is more than one way to register additional customizations:
@@ -64,20 +68,20 @@ There is more than one way to register additional customizations:
* Declaratively, for all applications, by adding a `META-INF/spring.factories` and packaging a jar file that the applications all use as a library.
The `SpringApplication` sends some special `ApplicationEvents` to the listeners (some even before the context is created) and then registers the listeners for events published by the `ApplicationContext` as well.
See "`<<features#features.spring-application.application-events-and-listeners,Application Events and Listeners>>`" in the '`Spring Boot features`' section for a complete list.
See "`xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[Application Events and Listeners]`" in the '`Spring Boot features`' section for a complete list.
It is also possible to customize the `Environment` before the application context is refreshed by using `EnvironmentPostProcessor`.
Each implementation should be registered in `META-INF/spring.factories`, as shown in the following example:
[indent=0]
[source]
----
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
----
The implementation can load arbitrary files and add them to the `Environment`.
For instance, the following example loads a YAML configuration file from the classpath:
include::code:MyEnvironmentPostProcessor[]
include-code::MyEnvironmentPostProcessor[]
TIP: The `Environment` has already been prepared with all the usual property sources that Spring Boot loads by default.
It is therefore possible to get the location of the file from the environment.
@@ -91,14 +95,16 @@ This is too late to configure certain properties such as `+logging.*+` and `+spr
[[howto.application.context-hierarchy]]
=== Build an ApplicationContext Hierarchy (Adding a Parent or Root Context)
== Build an ApplicationContext Hierarchy (Adding a Parent or Root Context)
You can use the `ApplicationBuilder` class to create parent/child `ApplicationContext` hierarchies.
See "`<<features#features.spring-application.fluent-builder-api>>`" in the '`Spring Boot features`' section for more information.
See "`xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[Fluent Builder API]`" in the '`Spring Boot features`' section for more information.
[[howto.application.non-web-application]]
=== Create a Non-web Application
== Create a Non-web Application
Not all Spring applications have to be web applications (or web services).
If you want to execute some code in a `main` method but also bootstrap a Spring application to set up the infrastructure to use, you can use the `SpringApplication` features of Spring Boot.
A `SpringApplication` changes its `ApplicationContext` class, depending on whether it thinks it needs a web application or not.

View File

@@ -1,61 +1,66 @@
[[howto.batch]]
== Batch Applications
= Batch Applications
A number of questions often arise when people use Spring Batch from within a Spring Boot application.
This section addresses those questions.
[[howto.batch.specifying-a-data-source]]
=== Specifying a Batch Data Source
== Specifying a Batch Data Source
By default, batch applications require a `DataSource` to store job details.
Spring Batch expects a single `DataSource` by default.
To have it use a `DataSource` other than the applications main `DataSource`, declare a `DataSource` bean, annotating its `@Bean` method with `@BatchDataSource`.
If you do so and want two data sources, remember to mark the other one `@Primary`.
To take greater control, add `@EnableBatchProcessing` to one of your `@Configuration` classes or extend `DefaultBatchConfiguration`.
See the Javadoc of {spring-batch-api}/core/configuration/annotation/EnableBatchProcessing.html[`@EnableBatchProcessing`]
and {spring-batch-api}/core/configuration/support/DefaultBatchConfiguration.html[`DefaultBatchConfiguration`] for more details.
See the Javadoc of {url-spring-batch-javadoc}/core/configuration/annotation/EnableBatchProcessing.html[`@EnableBatchProcessing`]
and {url-spring-batch-javadoc}/core/configuration/support/DefaultBatchConfiguration.html[`DefaultBatchConfiguration`] for more details.
For more info about Spring Batch, see the {spring-batch}[Spring Batch project page].
For more info about Spring Batch, see the {url-spring-batch-site}[Spring Batch project page].
[[howto.batch.specifying-a-transaction-manager]]
=== Specifying a Batch Transaction Manager
Similar to <<howto.batch.specifying-a-data-source>>, you can define a `PlatformTransactionManager` for use in the batch processing by marking it as `@BatchTransactionManager`.
== Specifying a Batch Transaction Manager
Similar to xref:batch.adoc#howto.batch.specifying-a-data-source[Specifying a Batch Data Source], you can define a `PlatformTransactionManager` for use in the batch processing by marking it as `@BatchTransactionManager`.
If you do so and want two transaction managers, remember to mark the other one as `@Primary`.
[[howto.batch.running-jobs-on-startup]]
=== Running Spring Batch Jobs on Startup
== Running Spring Batch Jobs on Startup
Spring Batch auto-configuration is enabled by adding `spring-boot-starter-batch` to your application's classpath.
If a single `Job` bean is found in the application context, it is executed on startup (see {spring-boot-autoconfigure-module-code}/batch/JobLauncherApplicationRunner.java[`JobLauncherApplicationRunner`] for details).
If a single `Job` bean is found in the application context, it is executed on startup (see {code-spring-boot-autoconfigure-src}/batch/JobLauncherApplicationRunner.java[`JobLauncherApplicationRunner`] for details).
If multiple `Job` beans are found, the job that should be executed must be specified using configprop:spring.batch.job.name[].
To disable running a `Job` found in the application context, set the configprop:spring.batch.job.enabled[] to `false`.
See {spring-boot-autoconfigure-module-code}/batch/BatchAutoConfiguration.java[BatchAutoConfiguration] for more details.
See {code-spring-boot-autoconfigure-src}/batch/BatchAutoConfiguration.java[BatchAutoConfiguration] for more details.
[[howto.batch.running-from-the-command-line]]
=== Running From the Command Line
Spring Boot converts any command line argument starting with `--` to a property to add to the `Environment`, see <<features#features.external-config.command-line-args,accessing command line properties>>.
== Running From the Command Line
Spring Boot converts any command line argument starting with `--` to a property to add to the `Environment`, see xref:reference:features/external-config.adoc#features.external-config.command-line-args[accessing command line properties].
This should not be used to pass arguments to batch jobs.
To specify batch arguments on the command line, use the regular format (that is without `--`), as shown in the following example:
[source,shell,indent=0,subs="verbatim"]
[source,shell]
----
$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue
$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue
----
If you specify a property of the `Environment` on the command line, it is ignored by the job.
Consider the following command:
[source,shell,indent=0,subs="verbatim"]
[source,shell]
----
$ java -jar myapp.jar --server.port=7070 someParameter=someValue
$ java -jar myapp.jar --server.port=7070 someParameter=someValue
----
This provides only one argument to the batch job: `someParameter=someValue`.
@@ -63,7 +68,8 @@ This provides only one argument to the batch job: `someParameter=someValue`.
[[howto.batch.restarting-a-failed-job]]
=== Restarting a stopped or failed Job
== Restarting a stopped or failed Job
To restart a failed `Job`, all parameters (identifying and non-identifying) must be re-specified on the command line.
Non-identifying parameters are *not* copied from the previous execution.
This allows them to be modified or removed.
@@ -73,7 +79,8 @@ NOTE: When you're using a custom `JobParametersIncrementer`, you have to gather
[[howto.batch.storing-job-repository]]
=== Storing the Job Repository
== Storing the Job Repository
Spring Batch requires a data store for the `Job` repository.
If you use Spring Boot, you must use an actual database.
Note that it can be an in-memory database, see {spring-batch-docs}/job.html#configuringJobRepository[Configuring a Job Repository].
Note that it can be an in-memory database, see {url-spring-batch-docs}/job.html#configuringJobRepository[Configuring a Job Repository].

View File

@@ -1,79 +1,82 @@
[[howto.build]]
== Build
= Build
Spring Boot includes build plugins for Maven and Gradle.
This section answers common questions about these plugins.
[[howto.build.generate-info]]
=== Generate Build Information
== Generate Build Information
Both the Maven plugin and the Gradle plugin allow generating build information containing the coordinates, name, and version of the project.
The plugins can also be configured to add additional properties through configuration.
When such a file is present, Spring Boot auto-configures a `BuildProperties` bean.
To generate build information with Maven, add an execution for the `build-info` goal, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
[source,xml,subs="verbatim,attributes"]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{spring-boot-version}</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version-spring-boot}</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----
TIP: See the {spring-boot-maven-plugin-docs}#goals-build-info[Spring Boot Maven Plugin documentation] for more details.
TIP: See the xref:maven-plugin:build-info.adoc[Spring Boot Maven Plugin documentation] for more details.
The following example does the same with Gradle:
[source,gradle,indent=0,subs="verbatim"]
[source,gradle]
----
springBoot {
buildInfo()
}
springBoot {
buildInfo()
}
----
TIP: See the {spring-boot-gradle-plugin-docs}#integrating-with-actuator-build-info[Spring Boot Gradle Plugin documentation] for more details.
TIP: See the xref:gradle-plugin:integrating-with-actuator.adoc[Spring Boot Gradle Plugin documentation] for more details.
[[howto.build.generate-git-info]]
=== Generate Git Information
== Generate Git Information
Both Maven and Gradle allow generating a `git.properties` file containing information about the state of your `git` source code repository when the project was built.
For Maven users, the `spring-boot-starter-parent` POM includes a pre-configured plugin to generate a `git.properties` file.
To use it, add the following declaration for the https://github.com/git-commit-id/git-commit-id-maven-plugin[`Git Commit Id Plugin`] to your POM:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
----
Gradle users can achieve the same result by using the https://plugins.gradle.org/plugin/com.gorylenko.gradle-git-properties[`gradle-git-properties`] plugin, as shown in the following example:
[source,gradle,indent=0,subs="verbatim"]
[source,gradle]
----
plugins {
id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
plugins {
id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
----
Both the Maven and Gradle plugins allow the properties that are included in `git.properties` to be configured.
@@ -85,71 +88,74 @@ Using this format lets the time be parsed into a `Date` and its format, when ser
[[howto.build.customize-dependency-versions]]
=== Customize Dependency Versions
== Customize Dependency Versions
The `spring-boot-dependencies` POM manages the versions of common dependencies.
The Spring Boot plugins for Maven and Gradle allow these managed dependency versions to be customized using build properties.
WARNING: Each Spring Boot release is designed and tested against this specific set of third-party dependencies.
Overriding versions may cause compatibility issues.
To override dependency versions with Maven, see {spring-boot-maven-plugin-docs}#using[this section] of the Maven plugin's documentation.
To override dependency versions with Maven, see xref:maven-plugin:using.adoc[this section] of the Maven plugin's documentation.
To override dependency versions in Gradle, see {spring-boot-gradle-plugin-docs}#managing-dependencies-dependency-management-plugin-customizing[this section] of the Gradle plugin's documentation.
To override dependency versions in Gradle, see xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.customizing[this section] of the Gradle plugin's documentation.
[[howto.build.create-an-executable-jar-with-maven]]
=== Create an Executable JAR with Maven
== Create an Executable JAR with Maven
The `spring-boot-maven-plugin` can be used to create an executable "`fat`" JAR.
If you use the `spring-boot-starter-parent` POM, you can declare the plugin and your jars are repackaged as follows:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
----
If you do not use the parent POM, you can still use the plugin.
However, you must additionally add an `<executions>` section, as follows:
[source,xml,indent=0,subs="verbatim,attributes"]
[source,xml,subs="verbatim,attributes"]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{spring-boot-version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version-spring-boot}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----
See the {spring-boot-maven-plugin-docs}#repackage[plugin documentation] for full usage details.
See the xref:maven-plugin:packaging.adoc#packaging.repackage-goal[plugin documentation] for full usage details.
[[howto.build.use-a-spring-boot-application-as-dependency]]
=== Use a Spring Boot Application as a Dependency
== Use a Spring Boot Application as a Dependency
Like a war file, a Spring Boot application is not intended to be used as a dependency.
If your application contains classes that you want to share with other projects, the recommended approach is to move that code into a separate module.
The separate module can then be depended upon by your application and other projects.
If you cannot rearrange your code as recommended above, Spring Boot's Maven and Gradle plugins must be configured to produce a separate artifact that is suitable for use as a dependency.
The executable archive cannot be used as a dependency as the <<executable-jar#appendix.executable-jar.nested-jars.jar-structure,executable jar format>> packages application classes in `BOOT-INF/classes`.
The executable archive cannot be used as a dependency as the xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[executable jar format] packages application classes in `BOOT-INF/classes`.
This means that they cannot be found when the executable jar is used as a dependency.
To produce the two artifacts, one that can be used as a dependency and one that is executable, a classifier must be specified.
@@ -157,25 +163,26 @@ This classifier is applied to the name of the executable archive, leaving the de
To configure a classifier of `exec` in Maven, you can use the following configuration:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
----
[[howto.build.extract-specific-libraries-when-an-executable-jar-runs]]
=== Extract Specific Libraries When an Executable Jar Runs
== Extract Specific Libraries When an Executable Jar Runs
Most nested libraries in an executable jar do not need to be unpacked in order to run.
However, certain libraries can have problems.
For example, JRuby includes its own nested jar support, which assumes that the `jruby-complete.jar` is always directly available as a file in its own right.
@@ -187,77 +194,80 @@ WARNING: Care should be taken to ensure that your operating system is configured
For example, to indicate that JRuby should be flagged for unpacking by using the Maven Plugin, you would add the following configuration:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build>
----
[[howto.build.create-a-nonexecutable-jar]]
=== Create a Non-executable JAR with Exclusions
== Create a Non-executable JAR with Exclusions
Often, if you have an executable and a non-executable jar as two separate build products, the executable version has additional configuration files that are not needed in a library jar.
For example, the `application.yaml` configuration file might be excluded from the non-executable JAR.
In Maven, the executable jar must be the main artifact and you can add a classified jar for the library, as follows:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>lib</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>lib</classifier>
<excludes>
<exclude>application.yaml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>lib</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>lib</classifier>
<excludes>
<exclude>application.yaml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
----
[[howto.build.remote-debug-maven]]
=== Remote Debug a Spring Boot Application Started with Maven
To attach a remote debugger to a Spring Boot application that was started with Maven, you can use the `jvmArguments` property of the {spring-boot-maven-plugin-docs}[maven plugin].
== Remote Debug a Spring Boot Application Started with Maven
See {spring-boot-maven-plugin-docs}#run-example-debug[this example] for more details.
To attach a remote debugger to a Spring Boot application that was started with Maven, you can use the `jvmArguments` property of the xref:maven-plugin:index.adoc[maven plugin].
See xref:maven-plugin:run.adoc#run.examples.debug[this example] for more details.
[[howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib]]
=== Build an Executable Archive From Ant without Using spring-boot-antlib
== Build an Executable Archive From Ant without Using spring-boot-antlib
To build with Ant, you need to grab dependencies, compile, and then create a jar or war archive.
To make it executable, you can either use the `spring-boot-antlib` module or you can follow these instructions:
@@ -272,27 +282,27 @@ To make it executable, you can either use the `spring-boot-antlib` module or you
The following example shows how to build an executable archive with Ant:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<target name="build" depends="compile">
<jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
<mappedresources>
<fileset dir="target/classes" />
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="src/main/resources" erroronmissingdir="false"/>
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="${lib.dir}/runtime" />
<globmapper from="*" to="BOOT-INF/lib/*"/>
</mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.launch.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" />
</manifest>
</jar>
</target>
<target name="build" depends="compile">
<jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
<mappedresources>
<fileset dir="target/classes" />
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="src/main/resources" erroronmissingdir="false"/>
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="${lib.dir}/runtime" />
<globmapper from="*" to="BOOT-INF/lib/*"/>
</mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.launch.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" />
</manifest>
</jar>
</target>
----

View File

@@ -1,29 +1,31 @@
[[howto.data-access]]
== Data Access
= Data Access
Spring Boot includes a number of starters for working with data sources.
This section answers questions related to doing so.
[[howto.data-access.configure-custom-datasource]]
=== Configure a Custom DataSource
== Configure a Custom DataSource
To configure your own `DataSource`, define a `@Bean` of that type in your configuration.
Spring Boot reuses your `DataSource` anywhere one is required, including database initialization.
If you need to externalize some settings, you can bind your `DataSource` to the environment (see "`<<features#features.external-config.typesafe-configuration-properties.third-party-configuration>>`").
If you need to externalize some settings, you can bind your `DataSource` to the environment (see "`xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[Third-party Configuration]`").
The following example shows how to define a data source in a bean:
include::code:custom/MyDataSourceConfiguration[]
include-code::custom/MyDataSourceConfiguration[]
The following example shows how to define a data source by setting properties:
[source,yaml,indent=0,subs="verbatim",configblocks]
[configprops%novalidate,yaml]
----
app:
datasource:
url: "jdbc:h2:mem:mydb"
username: "sa"
pool-size: 30
app:
datasource:
url: "jdbc:h2:mem:mydb"
username: "sa"
pool-size: 30
----
Assuming that `SomeDataSource` has regular JavaBean properties for the URL, the username, and the pool size, these settings are bound automatically before the `DataSource` is made available to other components.
@@ -34,7 +36,7 @@ It also auto-detects the driver based on the JDBC URL.
The following example shows how to create a data source by using a `DataSourceBuilder`:
include::code:builder/MyDataSourceConfiguration[]
include-code::builder/MyDataSourceConfiguration[]
To run an app with that `DataSource`, all you need is the connection information.
Pool-specific settings can also be provided.
@@ -42,14 +44,14 @@ Check the implementation that is going to be used at runtime for more details.
The following example shows how to define a JDBC data source by setting properties:
[source,yaml,indent=0,subs="verbatim",configblocks]
[configprops%novalidate,yaml]
----
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
----
However, there is a catch.
@@ -57,14 +59,14 @@ Because the actual type of the connection pool is not exposed, no keys are gener
Also, if you happen to have Hikari on the classpath, this basic setup does not work, because Hikari has no `url` property (but does have a `jdbcUrl` property).
In that case, you must rewrite your configuration as follows:
[source,yaml,indent=0,subs="verbatim",configblocks]
[configprops%novalidate,yaml]
----
app:
datasource:
jdbc-url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
app:
datasource:
jdbc-url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
----
You can fix that by forcing the connection pool to use and return a dedicated implementation rather than `DataSource`.
@@ -72,27 +74,27 @@ You cannot change the implementation at runtime, but the list of options will be
The following example shows how create a `HikariDataSource` with `DataSourceBuilder`:
include::code:simple/MyDataSourceConfiguration[]
include-code::simple/MyDataSourceConfiguration[]
You can even go further by leveraging what `DataSourceProperties` does for you -- that is, by providing a default embedded database with a sensible username and password if no URL is provided.
You can easily initialize a `DataSourceBuilder` from the state of any `DataSourceProperties` object, so you could also inject the DataSource that Spring Boot creates automatically.
However, that would split your configuration into two namespaces: `url`, `username`, `password`, `type`, and `driver` on `spring.datasource` and the rest on your custom namespace (`app.datasource`).
To avoid that, you can redefine a custom `DataSourceProperties` on your custom namespace, as shown in the following example:
include::code:configurable/MyDataSourceConfiguration[]
include-code::configurable/MyDataSourceConfiguration[]
This setup puts you _in sync_ with what Spring Boot does for you by default, except that a dedicated connection pool is chosen (in code) and its settings are exposed in the `app.datasource.configuration` sub namespace.
Because `DataSourceProperties` is taking care of the `url`/`jdbcUrl` translation for you, you can configure it as follows:
[source,yaml,indent=0,subs="verbatim",configblocks]
[configprops%novalidate,yaml]
----
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
----
TIP: Spring Boot will expose Hikari-specific settings to `spring.datasource.hikari`.
@@ -101,46 +103,47 @@ This example uses a more generic `configuration` sub namespace as the example do
NOTE: Because your custom configuration chooses to go with Hikari, `app.datasource.type` has no effect.
In practice, the builder is initialized with whatever value you might set there and then overridden by the call to `.type()`.
See "`<<data#data.sql.datasource>>`" in the "`Spring Boot features`" section and the {spring-boot-autoconfigure-module-code}/jdbc/DataSourceAutoConfiguration.java[`DataSourceAutoConfiguration`] class for more details.
See "`xref:reference:data/sql.adoc#data.sql.datasource[Configure a DataSource]`" in the "`Spring Boot features`" section and the {code-spring-boot-autoconfigure-src}/jdbc/DataSourceAutoConfiguration.java[`DataSourceAutoConfiguration`] class for more details.
[[howto.data-access.configure-two-datasources]]
=== Configure Two DataSources
== Configure Two DataSources
If you need to configure multiple data sources, you can apply the same tricks that are described in the previous section.
You must, however, mark one of the `DataSource` instances as `@Primary`, because various auto-configurations down the road expect to be able to get one by type.
If you create your own `DataSource`, the auto-configuration backs off.
In the following example, we provide the _exact_ same feature set as the auto-configuration provides on the primary data source:
include::code:MyDataSourcesConfiguration[]
include-code::MyDataSourcesConfiguration[]
TIP: `firstDataSourceProperties` has to be flagged as `@Primary` so that the database initializer feature uses your copy (if you use the initializer).
Both data sources are also bound for advanced customizations.
For instance, you could configure them as follows:
[source,yaml,indent=0,subs="verbatim",configblocks]
[configprops%novalidate,yaml]
----
app:
datasource:
first:
url: "jdbc:mysql://localhost/first"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
app:
datasource:
first:
url: "jdbc:mysql://localhost/first"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
second:
url: "jdbc:mysql://localhost/second"
username: "dbuser"
password: "dbpass"
max-total: 30
second:
url: "jdbc:mysql://localhost/second"
username: "dbuser"
password: "dbpass"
max-total: 30
----
You can apply the same concept to the secondary `DataSource` as well, as shown in the following example:
include::code:MyCompleteDataSourcesConfiguration[]
include-code::MyCompleteDataSourcesConfiguration[]
The preceding example configures two data sources on custom namespaces with the same logic as Spring Boot would use in auto-configuration.
Note that each `configuration` sub namespace provides advanced settings based on the chosen implementation.
@@ -148,32 +151,35 @@ Note that each `configuration` sub namespace provides advanced settings based on
[[howto.data-access.spring-data-repositories]]
=== Use Spring Data Repositories
== Use Spring Data Repositories
Spring Data can create implementations of `@Repository` interfaces of various flavors.
Spring Boot handles all of that for you, as long as those `@Repository` annotations are included in one of the <<using#using.auto-configuration.packages,auto-configuration packages>>, typically the package (or a sub-package) of your main application class that is annotated with `@SpringBootApplication` or `@EnableAutoConfiguration`.
Spring Boot handles all of that for you, as long as those `@Repository` annotations are included in one of the xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages], typically the package (or a sub-package) of your main application class that is annotated with `@SpringBootApplication` or `@EnableAutoConfiguration`.
For many applications, all you need is to put the right Spring Data dependencies on your classpath.
There is a `spring-boot-starter-data-jpa` for JPA, `spring-boot-starter-data-mongodb` for Mongodb, and various other starters for supported technologies.
To get started, create some repository interfaces to handle your `@Entity` objects.
Spring Boot determines the location of your `@Repository` definitions by scanning the <<using#using.auto-configuration.packages,auto-configuration packages>>.
Spring Boot determines the location of your `@Repository` definitions by scanning the xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages].
For more control, use the `@Enable…Repositories` annotations from Spring Data.
For more about Spring Data, see the {spring-data}[Spring Data project page].
For more about Spring Data, see the {url-spring-data-site}[Spring Data project page].
[[howto.data-access.separate-entity-definitions-from-spring-configuration]]
=== Separate @Entity Definitions from Spring Configuration
Spring Boot determines the location of your `@Entity` definitions by scanning the <<using#using.auto-configuration.packages,auto-configuration packages>>.
== Separate @Entity Definitions from Spring Configuration
Spring Boot determines the location of your `@Entity` definitions by scanning the xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages].
For more control, use the `@EntityScan` annotation, as shown in the following example:
include::code:MyApplication[]
include-code::MyApplication[]
[[howto.data-access.jpa-properties]]
=== Configure JPA Properties
== Configure JPA Properties
Spring Data JPA already provides some vendor-independent configuration options (such as those for SQL logging), and Spring Boot exposes those options and a few more for Hibernate as external configuration properties.
Some of them are automatically detected according to the context so you should not have to set them.
@@ -186,14 +192,14 @@ If you prefer to set the dialect yourself, set the configprop:spring.jpa.databas
The most common options to set are shown in the following example:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
spring:
jpa:
hibernate:
naming:
physical-strategy: "com.example.MyPhysicalNamingStrategy"
show-sql: true
spring:
jpa:
hibernate:
naming:
physical-strategy: "com.example.MyPhysicalNamingStrategy"
show-sql: true
----
In addition, all properties in `+spring.jpa.properties.*+` are passed through as normal JPA properties (with the prefix stripped) when the local `EntityManagerFactory` is created.
@@ -213,8 +219,9 @@ This takes precedence to anything that is applied by the auto-configuration.
[[howto.data-access.configure-hibernate-naming-strategy]]
=== Configure Hibernate Naming Strategy
Hibernate uses {hibernate-docs}#naming[two different naming strategies] to map names from the object model to the corresponding database names.
== Configure Hibernate Naming Strategy
Hibernate uses {url-hibernate-userguide}#naming[two different naming strategies] to map names from the object model to the corresponding database names.
The fully qualified class name of the physical and the implicit strategy implementations can be configured by setting the `spring.jpa.hibernate.naming.physical-strategy` and `spring.jpa.hibernate.naming.implicit-strategy` properties, respectively.
Alternatively, if `ImplicitNamingStrategy` or `PhysicalNamingStrategy` beans are available in the application context, Hibernate will be automatically configured to use them.
@@ -224,41 +231,47 @@ Additionally, by default, all table names are generated in lower case.
For example, a `TelephoneNumber` entity is mapped to the `telephone_number` table.
If your schema requires mixed-case identifiers, define a custom `CamelCaseToUnderscoresNamingStrategy` bean, as shown in the following example:
include::code:spring/MyHibernateConfiguration[]
include-code::spring/MyHibernateConfiguration[]
If you prefer to use Hibernate's default instead, set the following property:
[indent=0,properties,subs="verbatim"]
[configprops,yaml]
----
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring:
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
----
Alternatively, you can configure the following bean:
include::code:standard/MyHibernateConfiguration[]
include-code::standard/MyHibernateConfiguration[]
See {spring-boot-autoconfigure-module-code}/orm/jpa/HibernateJpaAutoConfiguration.java[`HibernateJpaAutoConfiguration`] and {spring-boot-autoconfigure-module-code}/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for more details.
See {code-spring-boot-autoconfigure-src}/orm/jpa/HibernateJpaAutoConfiguration.java[`HibernateJpaAutoConfiguration`] and {code-spring-boot-autoconfigure-src}/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for more details.
[[howto.data-access.configure-hibernate-second-level-caching]]
=== Configure Hibernate Second-Level Caching
Hibernate {hibernate-docs}#caching[second-level cache] can be configured for a range of cache providers.
== Configure Hibernate Second-Level Caching
Hibernate {url-hibernate-userguide}#caching[second-level cache] can be configured for a range of cache providers.
Rather than configuring Hibernate to lookup the cache provider again, it is better to provide the one that is available in the context whenever possible.
To do this with JCache, first make sure that `org.hibernate.orm:hibernate-jcache` is available on the classpath.
Then, add a `HibernatePropertiesCustomizer` bean as shown in the following example:
include::code:MyHibernateSecondLevelCacheConfiguration[]
include-code::MyHibernateSecondLevelCacheConfiguration[]
This customizer will configure Hibernate to use the same `CacheManager` as the one that the application uses.
It is also possible to use separate `CacheManager` instances.
For details, see {hibernate-docs}#caching-provider-jcache[the Hibernate user guide].
For details, see {url-hibernate-userguide}#caching-provider-jcache[the Hibernate user guide].
[[howto.data-access.dependency-injection-in-hibernate-components]]
=== Use Dependency Injection in Hibernate Components
== Use Dependency Injection in Hibernate Components
By default, Spring Boot registers a `BeanContainer` implementation that uses the `BeanFactory` so that converters and entity listeners can use regular dependency injection.
You can disable or tune this behavior by registering a `HibernatePropertiesCustomizer` that removes or changes the `hibernate.resource.beans.container` property.
@@ -266,20 +279,21 @@ You can disable or tune this behavior by registering a `HibernatePropertiesCusto
[[howto.data-access.use-custom-entity-manager]]
=== Use a Custom EntityManagerFactory
== Use a Custom EntityManagerFactory
To take full control of the configuration of the `EntityManagerFactory`, you need to add a `@Bean` named '`entityManagerFactory`'.
Spring Boot auto-configuration switches off its entity manager in the presence of a bean of that type.
[[howto.data-access.use-multiple-entity-managers]]
[[howto.data-access.use-multiple-entity-managers]]
=== Using Multiple EntityManagerFactories
== Using Multiple EntityManagerFactories
If you need to use JPA against multiple data sources, you likely need one `EntityManagerFactory` per data source.
The `LocalContainerEntityManagerFactoryBean` from Spring ORM allows you to configure an `EntityManagerFactory` for your needs.
You can also reuse `JpaProperties` to bind settings for each `EntityManagerFactory`, as shown in the following example:
include::code:MyEntityManagerFactoryConfiguration[]
include-code::MyEntityManagerFactoryConfiguration[]
The example above creates an `EntityManagerFactory` using a `DataSource` bean named `firstDataSource`.
It scans entities located in the same package as `Order`.
@@ -295,23 +309,25 @@ Alternatively, you might be able to use a JTA transaction manager that spans bot
If you use Spring Data, you need to configure `@EnableJpaRepositories` accordingly, as shown in the following examples:
include::code:OrderConfiguration[]
include-code::OrderConfiguration[]
include::code:CustomerConfiguration[]
include-code::CustomerConfiguration[]
[[howto.data-access.use-traditional-persistence-xml]]
=== Use a Traditional persistence.xml File
== Use a Traditional persistence.xml File
Spring Boot will not search for or use a `META-INF/persistence.xml` by default.
If you prefer to use a traditional `persistence.xml`, you need to define your own `@Bean` of type `LocalEntityManagerFactoryBean` (with an ID of '`entityManagerFactory`') and set the persistence unit name there.
See {spring-boot-autoconfigure-module-code}/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for the default settings.
See {code-spring-boot-autoconfigure-src}/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for the default settings.
[[howto.data-access.use-spring-data-jpa-and-mongo-repositories]]
=== Use Spring Data JPA and Mongo Repositories
== Use Spring Data JPA and Mongo Repositories
Spring Data JPA and Spring Data Mongo can both automatically create `Repository` implementations for you.
If they are both present on the classpath, you might have to do some extra configuration to tell Spring Boot which repositories to create.
The most explicit way to do that is to use the standard Spring Data `+@EnableJpaRepositories+` and `+@EnableMongoRepositories+` annotations and provide the location of your `Repository` interfaces.
@@ -325,7 +341,8 @@ To work with them, change the names of the annotations and flags accordingly.
[[howto.data-access.customize-spring-data-web-support]]
=== Customize Spring Data's Web Support
== Customize Spring Data's Web Support
Spring Data provides web support that simplifies the use of Spring Data repositories in a web application.
Spring Boot provides properties in the `spring.data.web` namespace for customizing its configuration.
Note that if you are using Spring Data REST, you must use the properties in the `spring.data.rest` namespace instead.
@@ -333,12 +350,13 @@ Note that if you are using Spring Data REST, you must use the properties in the
[[howto.data-access.exposing-spring-data-repositories-as-rest]]
=== Expose Spring Data Repositories as REST Endpoint
== Expose Spring Data Repositories as REST Endpoint
Spring Data REST can expose the `Repository` implementations as REST endpoints for you,
provided Spring MVC has been enabled for the application.
Spring Boot exposes a set of useful properties (from the `spring.data.rest` namespace) that customize the {spring-data-rest-api}/core/config/RepositoryRestConfiguration.html[`RepositoryRestConfiguration`].
If you need to provide additional customization, you should use a {spring-data-rest-api}/webmvc/config/RepositoryRestConfigurer.html[`RepositoryRestConfigurer`] bean.
Spring Boot exposes a set of useful properties (from the `spring.data.rest` namespace) that customize the {url-spring-data-rest-javadoc}/org/springframework/data/rest/core/config/RepositoryRestConfiguration.html[`RepositoryRestConfiguration`].
If you need to provide additional customization, you should use a {url-spring-data-rest-javadoc}/org/springframework/data/rest/webmvc/config/RepositoryRestConfigurer.html[`RepositoryRestConfigurer`] bean.
NOTE: If you do not specify any order on your custom `RepositoryRestConfigurer`, it runs after the one Spring Boot uses internally.
If you need to specify an order, make sure it is higher than 0.
@@ -346,7 +364,8 @@ If you need to specify an order, make sure it is higher than 0.
[[howto.data-access.configure-a-component-that-is-used-by-jpa]]
=== Configure a Component that is Used by JPA
== Configure a Component that is Used by JPA
If you want to configure a component that JPA uses, then you need to ensure that the component is initialized before JPA.
When the component is auto-configured, Spring Boot takes care of this for you.
For example, when Flyway is auto-configured, Hibernate is configured to depend upon Flyway so that Flyway has a chance to initialize the database before Hibernate tries to use it.
@@ -354,13 +373,14 @@ For example, when Flyway is auto-configured, Hibernate is configured to depend u
If you are configuring a component yourself, you can use an `EntityManagerFactoryDependsOnPostProcessor` subclass as a convenient way of setting up the necessary dependencies.
For example, if you use Hibernate Search with Elasticsearch as its index manager, any `EntityManagerFactory` beans must be configured to depend on the `elasticsearchClient` bean, as shown in the following example:
include::code:ElasticsearchEntityManagerFactoryDependsOnPostProcessor[]
include-code::ElasticsearchEntityManagerFactoryDependsOnPostProcessor[]
[[howto.data-access.configure-jooq-with-multiple-datasources]]
=== Configure jOOQ with Two DataSources
== Configure jOOQ with Two DataSources
If you need to use jOOQ with multiple data sources, you should create your own `DSLContext` for each one.
See {spring-boot-autoconfigure-module-code}/jooq/JooqAutoConfiguration.java[JooqAutoConfiguration] for more details.
See {code-spring-boot-autoconfigure-src}/jooq/JooqAutoConfiguration.java[JooqAutoConfiguration] for more details.
TIP: In particular, `JooqExceptionTranslator` and `SpringTransactionProvider` can be reused to provide similar features to what the auto-configuration does with a single `DataSource`.

View File

@@ -1,5 +1,6 @@
[[howto.data-initialization]]
== Database Initialization
= Database Initialization
An SQL database can be initialized in different ways depending on what your stack is.
Of course, you can also do it manually, provided the database is a separate process.
It is recommended to use a single mechanism for schema generation.
@@ -7,7 +8,8 @@ It is recommended to use a single mechanism for schema generation.
[[howto.data-initialization.using-jpa]]
=== Initialize a Database Using JPA
== Initialize a Database Using JPA
JPA has features for DDL generation, and these can be set up to run on startup against the database.
This is controlled through two external properties:
@@ -18,7 +20,8 @@ This is controlled through two external properties:
[[howto.data-initialization.using-hibernate]]
=== Initialize a Database Using Hibernate
== Initialize a Database Using Hibernate
You can set `spring.jpa.hibernate.ddl-auto` explicitly to one of the standard Hibernate property values which are `none`, `validate`, `update`, `create`, and `create-drop`.
Spring Boot chooses a default value for you based on whether it thinks your database is embedded.
It defaults to `create-drop` if no schema manager has been detected or `none` in all other cases.
@@ -28,7 +31,7 @@ Be careful when switching from in-memory to a '`real`' database that you do not
You either have to set `ddl-auto` explicitly or use one of the other mechanisms to initialize the database.
NOTE: You can output the schema creation by enabling the `org.hibernate.SQL` logger.
This is done for you automatically if you enable the <<features#features.logging.console-output,debug mode>>.
This is done for you automatically if you enable the xref:reference:features/logging.adoc#features.logging.console-output[debug mode].
In addition, a file named `import.sql` in the root of the classpath is executed on startup if Hibernate creates the schema from scratch (that is, if the `ddl-auto` property is set to `create` or `create-drop`).
This can be useful for demos and for testing if you are careful but is probably not something you want to be on the classpath in production.
@@ -37,7 +40,8 @@ It is a Hibernate feature (and has nothing to do with Spring).
[[howto.data-initialization.using-basic-sql-scripts]]
=== Initialize a Database Using Basic SQL Scripts
== Initialize a Database Using Basic SQL Scripts
Spring Boot can automatically create the schema (DDL scripts) of your JDBC `DataSource` or R2DBC `ConnectionFactory` and initialize its data (DML scripts).
By default, it loads schema scripts from `optional:classpath*:schema.sql` and data scripts from `optional:classpath*:data.sql`.
@@ -65,26 +69,27 @@ This will defer data source initialization until after any `EntityManagerFactory
NOTE: The initialization scripts support `--` for single line comments and `/++*++ ++*++/` for block comments.
Other comment formats are not supported.
If you are using a <<howto#howto.data-initialization.migration-tool,Higher-level Database Migration Tool>>, like Flyway or Liquibase, you should use them alone to create and initialize the schema.
If you are using a xref:data-initialization.adoc#howto.data-initialization.migration-tool[Higher-level Database Migration Tool], like Flyway or Liquibase, you should use them alone to create and initialize the schema.
Using the basic `schema.sql` and `data.sql` scripts alongside Flyway or Liquibase is not recommended and support will be removed in a future release.
If you need to initialize test data using a higher-level database migration tool, please see the sections about <<howto#howto.data-initialization.migration-tool.flyway-tests, Flyway>> and <<howto#howto.data-initialization.migration-tool.liquibase-tests, Liquibase>>.
If you need to initialize test data using a higher-level database migration tool, please see the sections about xref:data-initialization.adoc#howto.data-initialization.migration-tool.flyway-tests[Flyway] and xref:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase-tests[Liquibase].
[[howto.data-initialization.batch]]
=== Initialize a Spring Batch Database
== Initialize a Spring Batch Database
If you use Spring Batch, it comes pre-packaged with SQL initialization scripts for most popular database platforms.
Spring Boot can detect your database type and execute those scripts on startup.
If you use an embedded database, this happens by default.
You can also enable it for any database type, as shown in the following example:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
spring:
batch:
jdbc:
initialize-schema: "always"
spring:
batch:
jdbc:
initialize-schema: "always"
----
You can also switch off the initialization explicitly by setting `spring.batch.jdbc.initialize-schema` to `never`.
@@ -92,13 +97,15 @@ You can also switch off the initialization explicitly by setting `spring.batch.j
[[howto.data-initialization.migration-tool]]
=== Use a Higher-level Database Migration Tool
== Use a Higher-level Database Migration Tool
Spring Boot supports two higher-level migration tools: https://flywaydb.org/[Flyway] and https://www.liquibase.org/[Liquibase].
[[howto.data-initialization.migration-tool.flyway]]
==== Execute Flyway Database Migrations on Startup
=== Execute Flyway Database Migrations on Startup
To automatically run Flyway database migrations on startup, add the `org.flywaydb:flyway-core` to your classpath.
Typically, migrations are scripts in the form `V<VERSION>__<NAME>.sql` (with `<VERSION>` an underscore-separated version, such as '`1`' or '`2_1`').
@@ -106,34 +113,34 @@ By default, they are in a directory called `classpath:db/migration`, but you can
This is a comma-separated list of one or more `classpath:` or `filesystem:` locations.
For example, the following configuration would search for scripts in both the default classpath location and the `/opt/migration` directory:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
spring:
flyway:
locations: "classpath:db/migration,filesystem:/opt/migration"
spring:
flyway:
locations: "classpath:db/migration,filesystem:/opt/migration"
----
You can also add a special `\{vendor}` placeholder to use vendor-specific scripts.
Assume the following:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
spring:
flyway:
locations: "classpath:db/migration/{vendor}"
spring:
flyway:
locations: "classpath:db/migration/{vendor}"
----
Rather than using `db/migration`, the preceding configuration sets the directory to use according to the type of the database (such as `db/migration/mysql` for MySQL).
The list of supported databases is available in {spring-boot-module-code}/jdbc/DatabaseDriver.java[`DatabaseDriver`].
The list of supported databases is available in {code-spring-boot-src}/jdbc/DatabaseDriver.java[`DatabaseDriver`].
Migrations can also be written in Java.
Flyway will be auto-configured with any beans that implement `JavaMigration`.
{spring-boot-autoconfigure-module-code}/flyway/FlywayProperties.java[`FlywayProperties`] provides most of Flyway's settings and a small set of additional properties that can be used to disable the migrations or switch off the location checking.
{code-spring-boot-autoconfigure-src}/flyway/FlywayProperties.java[`FlywayProperties`] provides most of Flyway's settings and a small set of additional properties that can be used to disable the migrations or switch off the location checking.
If you need more control over the configuration, consider registering a `FlywayConfigurationCustomizer` bean.
Spring Boot calls `Flyway.migrate()` to perform the database migration.
If you would like more control, provide a `@Bean` that implements {spring-boot-autoconfigure-module-code}/flyway/FlywayMigrationStrategy.java[`FlywayMigrationStrategy`].
If you would like more control, provide a `@Bean` that implements {code-spring-boot-autoconfigure-src}/flyway/FlywayMigrationStrategy.java[`FlywayMigrationStrategy`].
Flyway supports SQL and Java https://flywaydb.org/documentation/concepts/callbacks[callbacks].
To use SQL-based callbacks, place the callback scripts in the `classpath:db/migration` directory.
@@ -154,11 +161,11 @@ For example, you can place test-specific migrations in `src/test/resources` and
Also, you can use profile-specific configuration to customize `spring.flyway.locations` so that certain migrations run only when a particular profile is active.
For example, in `application-dev.properties`, you might specify the following setting:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
spring:
flyway:
locations: "classpath:/db/migration,classpath:/dev/db/migration"
spring:
flyway:
locations: "classpath:/db/migration,classpath:/dev/db/migration"
----
With that setup, migrations in `dev/db/migration` run only when the `dev` profile is active.
@@ -166,7 +173,8 @@ With that setup, migrations in `dev/db/migration` run only when the `dev` profil
[[howto.data-initialization.migration-tool.liquibase]]
==== Execute Liquibase Database Migrations on Startup
=== Execute Liquibase Database Migrations on Startup
To automatically run Liquibase database migrations on startup, add the `org.liquibase:liquibase-core` to your classpath.
[NOTE]
@@ -186,12 +194,13 @@ Alternatively, you can use Liquibase's native `DataSource` by setting `spring.li
Setting either `spring.liquibase.url` or `spring.liquibase.user` is sufficient to cause Liquibase to use its own `DataSource`.
If any of the three properties has not been set, the value of its equivalent `spring.datasource` property will be used.
See {spring-boot-autoconfigure-module-code}/liquibase/LiquibaseProperties.java[`LiquibaseProperties`] for details about available settings such as contexts, the default schema, and others.
See {code-spring-boot-autoconfigure-src}/liquibase/LiquibaseProperties.java[`LiquibaseProperties`] for details about available settings such as contexts, the default schema, and others.
[[howto.data-initialization.migration-tool.flyway-tests]]
==== Use Flyway for test-only migrations
=== Use Flyway for test-only migrations
If you want to create Flyway migrations which populate your test database, place them in `src/test/resources/db/migration`.
A file named, for example, `src/test/resources/db/migration/V9999__test-data.sql` will be executed after your production migrations and only if you're running the tests.
You can use this file to create the needed test data.
@@ -200,14 +209,15 @@ This file will not be packaged in your uber jar or your container.
[[howto.data-initialization.migration-tool.liquibase-tests]]
==== Use Liquibase for test-only migrations
=== Use Liquibase for test-only migrations
If you want to create Liquibase migrations which populate your test database, you have to create a test changelog which also includes the production changelog.
First, you need to configure Liquibase to use a different changelog when running the tests.
One way to do this is to create a Spring Boot `test` profile and put the Liquibase properties in there.
For that, create a file named `src/test/resources/application-test.properties` and put the following property in there:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
spring:
liquibase:
@@ -218,7 +228,7 @@ This configures Liquibase to use a different changelog when running in the `test
Now create the changelog file at `src/test/resources/db/changelog/db.changelog-test.yaml`:
[source,yaml,indent=0,subs="verbatim"]
[source,yaml]
----
databaseChangeLog:
- include:
@@ -240,7 +250,8 @@ To do this, you can add the `@ActiveProfiles("test")` annotation to your `@Sprin
[[howto.data-initialization.dependencies]]
=== Depend Upon an Initialized Database
== Depend Upon an Initialized Database
Database initialization is performed while the application is starting up as part of application context refresh.
To allow an initialized database to be accessed during startup, beans that act as database initializers and beans that require that database to have been initialized are detected automatically.
Beans whose initialization depends upon the database having been initialized are configured to depend upon those that initialize it.
@@ -249,7 +260,8 @@ If, during startup, your application tries to access the database and it has not
[[howto.data-initialization.dependencies.initializer-detection]]
==== Detect a Database Initializer
=== Detect a Database Initializer
Spring Boot will automatically detect beans of the following types that initialize an SQL database:
- `DataSourceScriptDatabaseInitializer`
@@ -265,7 +277,8 @@ To have other beans be detected, register an implementation of `DatabaseInitiali
[[howto.data-initialization.dependencies.depends-on-initialization-detection]]
==== Detect a Bean That Depends On Database Initialization
=== Detect a Bean That Depends On Database Initialization
Spring Boot will automatically detect beans of the following types that depends upon database initialization:
- `AbstractEntityManagerFactoryBean` (unless configprop:spring.jpa.defer-datasource-initialization[] is set to `true`)

View File

@@ -1,16 +1,18 @@
[[howto.docker-compose]]
== Docker Compose
= Docker Compose
This section includes topics relating to the Docker Compose support in Spring Boot.
[[howto.docker-compose.jdbc-url]]
=== Customizing the JDBC URL
== Customizing the JDBC URL
When using `JdbcConnectionDetails` with Docker Compose, the parameters of the JDBC URL
can be customized by applying the `org.springframework.boot.jdbc.parameters` label to the
service. For example:
[source,yaml,indent=0]
[source,yaml]
----
services:
postgres:
@@ -30,7 +32,7 @@ With this Docker Compose file in place, the JDBC URL used is `jdbc:postgresql://
[[howto.docker-compose.sharing-services]]
=== Sharing services between multiple applications
== Sharing services between multiple applications
If you want to share services between multiple applications, create the `compose.yaml` file in one of the applications and then use the configuration property configprop:spring.docker.compose.file[] in the other applications to reference the `compose.yaml` file.
You should also set configprop:spring.docker.compose.lifecycle-management[] to `start-only`, as it defaults to `start-and-stop` and stopping one application would shut down the shared services for the other still running applications as well.

View File

@@ -1,67 +1,75 @@
[[howto.hotswapping]]
== Hot Swapping
= Hot Swapping
Spring Boot supports hot swapping.
This section answers questions about how it works.
[[howto.hotswapping.reload-static-content]]
=== Reload Static Content
== Reload Static Content
There are several options for hot reloading.
The recommended approach is to use <<using#using.devtools,`spring-boot-devtools`>>, as it provides additional development-time features, such as support for fast application restarts and LiveReload as well as sensible development-time configuration (such as template caching).
The recommended approach is to use xref:reference:using/devtools.adoc[`spring-boot-devtools`], as it provides additional development-time features, such as support for fast application restarts and LiveReload as well as sensible development-time configuration (such as template caching).
Devtools works by monitoring the classpath for changes.
This means that static resource changes must be "built" for the change to take effect.
By default, this happens automatically in Eclipse when you save your changes.
In IntelliJ IDEA, the Make Project command triggers the necessary build.
Due to the <<using#using.devtools.restart.excluding-resources, default restart exclusions>>, changes to static resources do not trigger a restart of your application.
Due to the xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[default restart exclusions], changes to static resources do not trigger a restart of your application.
They do, however, trigger a live reload.
Alternatively, running in an IDE (especially with debugging on) is a good way to do development (all modern IDEs allow reloading of static resources and usually also allow hot-swapping of Java class changes).
Finally, the <<build-tool-plugins#build-tool-plugins, Maven and Gradle plugins>> can be configured (see the `addResources` property) to support running from the command line with reloading of static files directly from source.
Finally, the xref:build-tool-plugin:index.adoc[Maven and Gradle plugins] can be configured (see the `addResources` property) to support running from the command line with reloading of static files directly from source.
You can use that with an external css/js compiler process if you are writing that code with higher-level tools.
[[howto.hotswapping.reload-templates]]
=== Reload Templates without Restarting the Container
== Reload Templates without Restarting the Container
Most of the templating technologies supported by Spring Boot include a configuration option to disable caching (described later in this document).
If you use the `spring-boot-devtools` module, these properties are <<using#using.devtools.property-defaults,automatically configured>> for you at development time.
If you use the `spring-boot-devtools` module, these properties are xref:reference:using/devtools.adoc#using.devtools.property-defaults[automatically configured] for you at development time.
[[howto.hotswapping.reload-templates.thymeleaf]]
==== Thymeleaf Templates
=== Thymeleaf Templates
If you use Thymeleaf, set `spring.thymeleaf.cache` to `false`.
See {spring-boot-autoconfigure-module-code}/thymeleaf/ThymeleafAutoConfiguration.java[`ThymeleafAutoConfiguration`] for other Thymeleaf customization options.
See {code-spring-boot-autoconfigure-src}/thymeleaf/ThymeleafAutoConfiguration.java[`ThymeleafAutoConfiguration`] for other Thymeleaf customization options.
[[howto.hotswapping.reload-templates.freemarker]]
==== FreeMarker Templates
=== FreeMarker Templates
If you use FreeMarker, set `spring.freemarker.cache` to `false`.
See {spring-boot-autoconfigure-module-code}/freemarker/FreeMarkerAutoConfiguration.java[`FreeMarkerAutoConfiguration`] for other FreeMarker customization options.
See {code-spring-boot-autoconfigure-src}/freemarker/FreeMarkerAutoConfiguration.java[`FreeMarkerAutoConfiguration`] for other FreeMarker customization options.
[[howto.hotswapping.reload-templates.groovy]]
==== Groovy Templates
=== Groovy Templates
If you use Groovy templates, set `spring.groovy.template.cache` to `false`.
See {spring-boot-autoconfigure-module-code}/groovy/template/GroovyTemplateAutoConfiguration.java[`GroovyTemplateAutoConfiguration`] for other Groovy customization options.
See {code-spring-boot-autoconfigure-src}/groovy/template/GroovyTemplateAutoConfiguration.java[`GroovyTemplateAutoConfiguration`] for other Groovy customization options.
[[howto.hotswapping.fast-application-restarts]]
=== Fast Application Restarts
== Fast Application Restarts
The `spring-boot-devtools` module includes support for automatic application restarts.
While not as fast as technologies such as https://www.jrebel.com/products/jrebel[JRebel] it is usually significantly faster than a "`cold start`".
You should probably give it a try before investigating some of the more complex reload options discussed later in this document.
For more details, see the <<using#using.devtools>> section.
For more details, see the xref:reference:using/devtools.adoc[Developer Tools] section.
[[howto.hotswapping.reload-java-classes-without-restarting]]
=== Reload Java Classes without Restarting the Container
== Reload Java Classes without Restarting the Container
Many modern IDEs (Eclipse, IDEA, and others) support hot swapping of bytecode.
Consequently, if you make a change that does not affect class or method signatures, it should reload cleanly with no side effects.

View File

@@ -1,13 +1,15 @@
[[howto.http-clients]]
== HTTP Clients
= HTTP Clients
Spring Boot offers a number of starters that work with HTTP clients.
This section answers questions related to using them.
[[howto.http-clients.rest-template-proxy-configuration]]
=== Configure RestTemplate to Use a Proxy
As described in <<io#io.rest-client.resttemplate.customization>>, you can use a `RestTemplateCustomizer` with `RestTemplateBuilder` to build a customized `RestTemplate`.
== Configure RestTemplate to Use a Proxy
As described in xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[RestTemplate Customization], you can use a `RestTemplateCustomizer` with `RestTemplateBuilder` to build a customized `RestTemplate`.
This is the recommended approach for creating a `RestTemplate` configured to use a proxy.
The exact details of the proxy configuration depend on the underlying client request factory that is being used.
@@ -15,12 +17,13 @@ The exact details of the proxy configuration depend on the underlying client req
[[howto.http-clients.webclient-reactor-netty-customization]]
=== Configure the TcpClient used by a Reactor Netty-based WebClient
== Configure the TcpClient used by a Reactor Netty-based WebClient
When Reactor Netty is on the classpath a Reactor Netty-based `WebClient` is auto-configured.
To customize the client's handling of network connections, provide a `ClientHttpConnector` bean.
The following example configures a 60 second connect timeout and adds a `ReadTimeoutHandler`:
include::code:MyReactorNettyClientConfiguration[]
include-code::MyReactorNettyClientConfiguration[]
TIP: Note the use of `ReactorResourceFactory` for the connection provider and event loop resources.
This ensures efficient sharing of resources for the server receiving requests and the client making requests.

View File

@@ -0,0 +1,12 @@
[[howto]]
= How-to Guides
This section provides answers to some common '`how do I do that...`' questions that often arise when using Spring Boot.
Its coverage is not exhaustive, but it does cover quite a lot.
If you have a specific problem that we do not cover here, you might want to check https://stackoverflow.com/tags/spring-boot[stackoverflow.com] to see if someone has already provided an answer.
This is also a great place to ask new questions (please use the `spring-boot` tag).
We are also more than happy to extend this section.
If you want to add a '`how-to`', send us a {url-github}[pull request].

View File

@@ -1,30 +1,26 @@
[[howto.jersey]]
== Jersey
= Jersey
[[howto.jersey.spring-security]]
=== Secure Jersey endpoints with Spring Security
== Secure Jersey endpoints with Spring Security
Spring Security can be used to secure a Jersey-based web application in much the same way as it can be used to secure a Spring MVC-based web application.
However, if you want to use Spring Security's method-level security with Jersey, you must configure Jersey to use `setStatus(int)` rather `sendError(int)`.
This prevents Jersey from committing the response before Spring Security has had an opportunity to report an authentication or authorization failure to the client.
The `jersey.config.server.response.setStatusOverSendError` property must be set to `true` on the application's `ResourceConfig` bean, as shown in the following example:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/howto/jersey/springsecurity/JerseySetStatusOverSendErrorConfig.java[]
----
include-code::JerseySetStatusOverSendErrorConfig[]
[[howto.jersey.alongside-another-web-framework]]
=== Use Jersey Alongside Another Web Framework
== Use Jersey Alongside Another Web Framework
To use Jersey alongside another web framework, such as Spring MVC, it should be configured so that it will allow the other framework to handle requests that it cannot handle.
First, configure Jersey to use a filter rather than a servlet by configuring the configprop:spring.jersey.type[] application property with a value of `filter`.
Second, configure your `ResourceConfig` to forward requests that would have resulted in a 404, as shown in the following example.
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/howto/jersey/alongsideanotherwebframework/JerseyConfig.java[]
----
includ-code::alongsideanotherwebframework/JerseyConfig[]

View File

@@ -1,17 +1,18 @@
[[howto.logging]]
== Logging
= Logging
Spring Boot has no mandatory logging dependency, except for the Commons Logging API, which is typically provided by Spring Framework's `spring-jcl` module.
To use https://logback.qos.ch[Logback], you need to include it and `spring-jcl` on the classpath.
The recommended way to do that is through the starters, which all depend on `spring-boot-starter-logging`.
For a web application, you only need `spring-boot-starter-web`, since it depends transitively on the logging starter.
If you use Maven, the following dependency adds logging for you:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
----
Spring Boot has a `LoggingSystem` abstraction that attempts to configure logging based on the content of the classpath.
@@ -19,12 +20,12 @@ If Logback is available, it is the first choice.
If the only change you need to make to logging is to set the levels of various loggers, you can do so in `application.properties` by using the "logging.level" prefix, as shown in the following example:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
logging:
level:
org.springframework.web: "debug"
org.hibernate: "error"
logging:
level:
org.springframework.web: "debug"
org.hibernate: "error"
----
You can also set the location of a file to which the log will be written (in addition to the console) by using `logging.file.name`.
@@ -35,10 +36,11 @@ By default, Spring Boot picks up the native configuration from its default locat
[[howto.logging.logback]]
=== Configure Logback for Logging
== Configure Logback for Logging
If you need to apply customizations to logback beyond those that can be achieved with `application.properties`, you will need to add a standard logback configuration file.
You can add a `logback.xml` file to the root of your classpath for logback to find.
You can also use `logback-spring.xml` if you want to use the <<features#features.logging.logback-extensions,Spring Boot Logback extensions>>.
You can also use `logback-spring.xml` if you want to use the xref:reference:features/logging.adoc#features.logging.logback-extensions[Spring Boot Logback extensions].
TIP: The Logback documentation has a https://logback.qos.ch/manual/configuration.html[dedicated section that covers configuration] in some detail.
@@ -55,17 +57,17 @@ In addition, a legacy `base.xml` file is provided for compatibility with earlier
A typical custom `logback.xml` file would look something like this:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
----
Your logback configuration file can also make use of System properties that the `LoggingSystem` takes care of creating for you:
@@ -88,35 +90,37 @@ Any `logback-spring.groovy` files will not be detected.
[[howto.logging.logback.file-only-output]]
==== Configure Logback for File-only Output
=== Configure Logback for File-only Output
If you want to disable console logging and write output only to a file, you need a custom `logback-spring.xml` that imports `file-appender.xml` but not `console-appender.xml`, as shown in the following example:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
----
You also need to add `logging.file.name` to your `application.properties` or `application.yaml`, as shown in the following example:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
[configprops,yaml]
----
logging:
file:
name: "myapplication.log"
logging:
file:
name: "myapplication.log"
----
[[howto.logging.log4j]]
=== Configure Log4j for Logging
== Configure Log4j for Logging
Spring Boot supports https://logging.apache.org/log4j/2.x/[Log4j 2] for logging configuration if it is on the classpath.
If you use the starters for assembling dependencies, you have to exclude Logback and then include Log4j 2 instead.
If you do not use the starters, you need to provide (at least) `spring-jcl` in addition to Log4j 2.
@@ -124,42 +128,42 @@ If you do not use the starters, you need to provide (at least) `spring-jcl` in a
The recommended path is through the starters, even though it requires some jiggling.
The following example shows how to set up the starters in Maven:
[source,xml,indent=0,subs="verbatim"]
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
----
Gradle provides a few different ways to set up the starters.
One way is to use a {gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement].
One way is to use a {url-gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement].
To do so, declare a dependency on the Log4j 2 starter and tell Gradle that any occurrences of the default logging starter should be replaced by the Log4j 2 starter, as shown in the following example:
[source,gradle,indent=0,subs="verbatim"]
[source,gradle]
----
dependencies {
implementation "org.springframework.boot:spring-boot-starter-log4j2"
modules {
module("org.springframework.boot:spring-boot-starter-logging") {
replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
}
dependencies {
implementation "org.springframework.boot:spring-boot-starter-log4j2"
modules {
module("org.springframework.boot:spring-boot-starter-logging") {
replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
}
}
}
----
NOTE: The Log4j starters gather together the dependencies for common logging requirements (such as having Tomcat use `java.util.logging` but configuring the output using Log4j 2).
@@ -169,7 +173,8 @@ NOTE: To ensure that debug logging performed using `java.util.logging` is routed
[[howto.logging.log4j.yaml-or-json-config]]
==== Use YAML or JSON to Configure Log4j 2
=== Use YAML or JSON to Configure Log4j 2
In addition to its default XML configuration format, Log4j 2 also supports YAML and JSON configuration files.
To configure Log4j 2 to use an alternative configuration file format, add the appropriate dependencies to the classpath and name your configuration files to match your chosen file format, as shown in the following example:
@@ -189,7 +194,8 @@ To configure Log4j 2 to use an alternative configuration file format, add the ap
[[howto.logging.log4j.composite-configuration]]
==== Use Composite Configuration to Configure Log4j 2
=== Use Composite Configuration to Configure Log4j 2
Log4j 2 has support for combining multiple configuration files into a single composite configuration.
To use this support in Spring Boot, configure configprop:logging.log4j2.config.override[] with the locations of one or more secondary configuration files.
The secondary configuration files will be merged with the primary configuration, whether the primary's source is Spring Boot's defaults, a standard location such as `log4j.xml`, or the location configured by the configprop:logging.config[] property.

View File

@@ -1,16 +1,18 @@
[[howto.messaging]]
== Messaging
= Messaging
Spring Boot offers a number of starters to support messaging.
This section answers questions that arise from using messaging with Spring Boot.
[[howto.messaging.disable-transacted-jms-session]]
=== Disable Transacted JMS Session
== Disable Transacted JMS Session
If your JMS broker does not support transacted sessions, you have to disable the support of transactions altogether.
If you create your own `JmsListenerContainerFactory`, there is nothing to do, since, by default it cannot be transacted.
If you want to use the `DefaultJmsListenerContainerFactoryConfigurer` to reuse Spring Boot's default, you can disable transacted sessions, as follows:
include::code:MyJmsConfiguration[]
include-code::MyJmsConfiguration[]
The preceding example overrides the default factory, and it should be applied to any other factory that your application defines, if any.

Some files were not shown because too many files have changed in this diff Show More