Extract some code samples from docs

See gh-6313
This commit is contained in:
Phillip Webb
2021-02-03 17:53:29 -08:00
parent e0392c4558
commit 0e326d6b0f
12 changed files with 571 additions and 226 deletions

View File

@@ -13,11 +13,9 @@ If you have not already done so, you might want to read the "<<getting-started.a
The `SpringApplication` class provides a convenient way to bootstrap a Spring application that is started from a `main()` method.
In many situations, you can delegate to the static `SpringApplication.run` method, as shown in the following example:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
include::{include-springbootfeatures}/springapplication/main/run/MyApplication.java[tag=*]
----
When your application starts, you should see something similar to the following output:
@@ -176,13 +174,9 @@ This will initialize the `application.*` banner variables before building the cl
If the `SpringApplication` defaults are not to your taste, you can instead create a local instance and customize it.
For example, to turn off the banner, you could write:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
include::{include-springbootfeatures}/springapplication/main/custom/MyApplication.java[tag=*]
----
NOTE: The constructor arguments passed to `SpringApplication` are configuration sources for Spring beans.
@@ -255,49 +249,16 @@ More often, applications will want to listen to state updates or update the stat
For example, we can export the "Readiness" state of the application to a file so that a Kubernetes "exec Probe" can look at this file:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
@Component
public class ReadinessStateExporter {
@EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC:
// create file /tmp/healthy
break;
case REFUSING_TRAFFIC:
// remove file /tmp/healthy
break;
}
}
}
include::{include-springbootfeatures}/springapplication/availability/ReadinessStateExporter.java[tag=*]
----
We can also update the state of the application, when the application breaks and cannot recover:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
@Component
public class LocalCacheVerifier {
private final ApplicationEventPublisher eventPublisher;
public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void checkLocalCache() {
try {
//...
}
catch (CacheCompletelyBrokenException ex) {
AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
}
}
}
include::{include-springbootfeatures}/springapplication/availability/LocalCacheVerifier.java[tag=*]
----
Spring Boot provides <<production-ready-features.adoc#production-ready-kubernetes-probes,Kubernetes HTTP probes for "Liveness" and "Readiness" with Actuator Health Endpoints>>.
@@ -380,23 +341,9 @@ TIP: It is often desirable to call `setWebApplicationType(WebApplicationType.NON
If you need to access the application arguments that were passed to `SpringApplication.run(...)`, you can inject a `org.springframework.boot.ApplicationArguments` bean.
The `ApplicationArguments` interface provides access to both the raw `String[]` arguments as well as parsed `option` and `non-option` arguments, as shown in the following example:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
@Component
public class MyBean {
@Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
// if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
}
}
include::{include-springbootfeatures}/springapplication/ApplicationArgumentsExample.java[tag=*]
----
TIP: Spring Boot also registers a `CommandLinePropertySource` with the Spring `Environment`.
@@ -415,19 +362,9 @@ NOTE: This contract is well suited for tasks that should run after application s
The `CommandLineRunner` interfaces provides access to application arguments as a string array, whereas the `ApplicationRunner` uses the `ApplicationArguments` interface discussed earlier.
The following example shows a `CommandLineRunner` with a `run` method:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
import org.springframework.boot.*;
import org.springframework.stereotype.*;
@Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
}
}
include::{include-springbootfeatures}/springapplication/CommandLineRunnerExample.java[tag=*]
----
If several `CommandLineRunner` or `ApplicationRunner` beans are defined that must be called in a specific order, you can additionally implement the `org.springframework.core.Ordered` interface or use the `org.springframework.core.annotation.Order` annotation.
@@ -473,13 +410,9 @@ This data can be collected for profiling purposes, or just to have a better unde
You can choose an `ApplicationStartup` implementation when setting up the `SpringApplication` instance.
For example, to use the `BufferingApplicationStartup`, you could write:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setApplicationStartup(new BufferingApplicationStartup(2048));
app.run(args);
}
include::{include-springbootfeatures}/springapplication/startup/MyApplication.java[tag=*]
----
The first available implementation, `FlightRecorderApplicationStartup` is provided by Spring Framework.
@@ -532,20 +465,9 @@ Config data files are considered in the following order:
To provide a concrete example, suppose you develop a `@Component` that uses a `name` property, as shown in the following example:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
include::{include-springbootfeatures}/externalizedconfiguration/valueinjection/MyBean.java[tag=*]
----
On your application classpath (for example, inside your jar) you can have an `application.properties` file that provides a sensible default property value for `name`.
@@ -1115,58 +1037,9 @@ TIP: See also the <<boot-features-external-config-vs-value,differences between `
==== JavaBean properties binding
It is possible to bind a bean declaring standard JavaBean properties as shown in the following example:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
package com.example;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() { ... }
public void setEnabled(boolean enabled) { ... }
public InetAddress getRemoteAddress() { ... }
public void setRemoteAddress(InetAddress remoteAddress) { ... }
public Security getSecurity() { ... }
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() { ... }
public void setUsername(String username) { ... }
public String getPassword() { ... }
public void setPassword(String password) { ... }
public List<String> getRoles() { ... }
public void setRoles(List<String> roles) { ... }
}
}
include::{include-springbootfeatures}/externalizedconfiguration/javabeanbinding/AcmeProperties.java[tag=*]
----
The preceding POJO defines the following properties:
@@ -1205,63 +1078,9 @@ Finally, only standard Java Bean properties are considered and binding on static
==== Constructor binding
The example in the previous section can be rewritten in an immutable fashion as shown in the following example:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}
include::{include-springbootfeatures}/externalizedconfiguration/constructorbinding/AcmeProperties.java[tag=*]
----
In this setup, the `@ConstructorBinding` annotation is used to indicate that constructor binding should be used.
@@ -1273,32 +1092,9 @@ Default values can be specified using `@DefaultValue` and the same conversion se
By default, if no properties are bound to `Security`, the `AcmeProperties` instance will contain a `null` value for `security`.
If you wish you return a non-null instance of `Security` even when no properties are bound to it, you can use an empty `@DefaultValue` annotation to do so:
[source,java,pending-extract=true,indent=0]
[source,java,indent=0]
----
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
}
include::{include-springbootfeatures}/externalizedconfiguration/constructorbinding/nonnull/AcmeProperties.java[tag=*]
----

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.externalizedconfiguration.constructorbinding;
//tag::code[]
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() {
return this.enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() {
return this.username;
}
public String getPassword() {
return this.password;
}
public List<String> getRoles() {
return this.roles;
}
}
}
// end::code[]

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.externalizedconfiguration.constructorbinding.nonnull;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
// tag::code[]
public AcmeProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
// end::code[]
public boolean isEnabled() {
return this.enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() {
return this.username;
}
public String getPassword() {
return this.password;
}
public List<String> getRoles() {
return this.roles;
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.externalizedconfiguration.javabeanbinding;
//tag::code[]
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public void setRemoteAddress(InetAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public List<String> getRoles() {
return this.roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
}
}
// end::code[]

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.externalizedconfiguration.valueinjection;
// tag::code[]
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
// end::code[]

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.springapplication;
//tag::code[]
import java.util.List;
import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;
@Component
public class ApplicationArgumentsExample {
public ApplicationArgumentsExample(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
if (debug) {
System.out.println(files);
}
// if run with "--debug logfile.txt" prints ["logfile.txt"]
}
}
// end::code[]

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.springapplication;
//tag::code[]
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class CommandLineRunnerExample implements CommandLineRunner {
@Override
public void run(String... args) {
// Do something...
}
}
// end::code[]

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.springapplication.availability;
//tag::code[]
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class LocalCacheVerifier {
private final ApplicationEventPublisher eventPublisher;
public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void checkLocalCache() {
try {
// ...
}
catch (CacheCompletelyBrokenException ex) {
AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
}
}
}
// end::code[]
class CacheCompletelyBrokenException extends RuntimeException {
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.springapplication.availability;
// tag::code[]
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class ReadinessStateExporter {
@EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC:
// create file /tmp/healthy
break;
case REFUSING_TRAFFIC:
// remove file /tmp/healthy
break;
}
}
}
// end::code[]

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.springapplication.main.custom;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
// tag::code[]
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
// end::code[]
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.springapplication.main.run;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
// tag::code[]
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
// end::code[]
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2012-2021 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.docs.springbootfeatures.springapplication.startup;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
@SpringBootApplication
public class MyApplication {
// tag::code[]
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
}
// end::code[]
}