jim stafford
Configuration focus thus far has been
under fairly static conditions
applied directly to a single application
dynamically determined
modularized and not repeated
dynamic based on runtime environment at startup
libraries present
properties defined
resources found
etc.
Examples:
what database will be used when in development, integration, or production?
what security should be enabled in development versus production areas?
applications will ideally be broken into separate components
making components reusable for multiple applications is good practice
requires physically breaking them into separate modules
leaves us with repeated responsibility to configure reused components
there could be dozens of choices to make within a component configuration
application can be significantly simplified by an opinionated configuration supplied based on runtime environment
If you find yourself
needing configurations determined dynamically at runtime
solving a repeated problem and bundling that into a library shared by multiple applications
Master the concepts behind Spring Boot’s Auto-configuration capability
The student will learn to:
Enable/disable bean creation based on condition(s) at startup
Create Auto-configuration/Starter module(s) that establish necessary dependencies and conditionally supplies beans
Resolve conflicts between alternate configurations
Locate environment and condition details to debug Auto-configuration issues
At the conclusion of this lecture and related exercises, the student will be able to:
Enable a @Component
, @Configuration
class, or @Bean
factory method based
on the result of a condition at startup
Create Spring Boot Auto-configuration/Starter module(s)
Bootstrap Auto-configuration classes into applications using a Spring Boot 3 org.springframework.boot.autoconfigure.AutoConfiguration.imports
metadata file
Create a conditional component based on the presence of a property value
Create a conditional component based on a missing component
Create a conditional component based on the presence of a class
Define a processing dependency order for Auto-configuration classes
Access textual debug information relative to conditions using the debug
property
Access web-based debug information relative to conditionals and properties using the Spring Boot Actuator
@Configuration
classes used to bootstrap application using Java classes
modern alternative to legacy XML definitions that basically do the same thing — define and configure beans
can be the @SpringBootApplication
class itself
appropriate for a small application
@SpringBootApplication
//==> wraps @EnableAutoConfiguration
//==> wraps @SpringBootConfiguration
// ==> wraps @Configuration
public class SelfConfiguredApp {
public static void main(String...args) {
SpringApplication.run(SelfConfiguredApp.class, args);
}
@Bean
public Hello hello() {
return new StdOutHello("Application @Bean says Hey");
}
}
can be broken out into separate classes
appropriate for larger applications with distinct areas to be configured
@Configuration(proxyBeanMethods = false) (2)
public class AConfigurationClass {
@Bean (1)
public Hello hello() {
return new StdOutHello("...");
}
}
1 | bean scope defaults to "singleton" |
2 | nothing directly calling the @Bean factory method; establishing a CGLIB proxy is unnecessary |
@Configuration classes are commonly annotated with the proxyMethods=false attribute that tells Spring not to create extra proxy code to enforce normal, singleton return of the created instance to be shared by all callers since @Configuration class instances are only called by Spring.
The javadoc for the annotation attribute describes the extra and unnecessary work saved. |
can make configurations dependent on conditions found at startup
individual @Bean
factory methods (or the @Component
annotated class)
entire @Configuration
classes
...
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class StarterConfiguredApp {
public static void main(String...args) {
SpringApplication.run(StarterConfiguredApp.class, args);
}
@Bean
@ConditionalOnProperty(prefix="hello", name="quiet", havingValue="true") (1)
public Hello quietHello() {
return new StdOutHello("(hello.quiet property condition set, Application @Bean says hi)");
}
}
1 |
@ConditionalOnProperty annotation used to define a Hello bean based on the presence of the hello.quiet property having the value true |
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar --hello.quiet=true (1)
...
(hello.quiet property condition set, Application @Bean says hi) World (2)
1 | matching property supplied using command line |
2 | satisfies property condition in @SpringBootApplication |
The (parentheses) is trying to indicate a whisper.
hello.quiet=true property turns on this behavior. |
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar (1)
...
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in info.ejava.examples.app.config.auto.AppCommand required a bean of type 'info.ejava.examples.app.hello.Hello' that could not be found. (2)
Action:
Consider defining a bean of type 'info.ejava.examples.app.hello.Hello' in your configuration.
1 | property either not specified or not specified with targeted value |
2 | property condition within @SpringBootApplication not satisfied |
Configuration processing within Spring Boot is separated into two primary phases:
User-defined configuration classes
processed first
part of the application module
located through the use of a @ComponentScan
(wrapped by @SpringBootApplication
)
establish the base configuration for the application
fill in any fine-tuning details.
Auto-configuration classes
parsed second
outside the scope of the @ComponentScan
placed in separate modules, identified by metadata within those modules
enabled by application using @EnableAutoConfiguration
(also wrapped by @SpringBootApplication
)
provide defaults to fill in the reusable parts of the application
use User-defined configuration for details
technically no different from any other @Configuration
class except
inspected after User-defined @Configuration
class(es) processing complete
based on being named in a descriptor file within META-INF/
alternate identification and second pass processing allows the core application to
make key directional and detailed decisions
control conditions for the Auto-configuration class(es)
package info.ejava.examples.app.hello; (2)
...
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean (1)
public Hello hello(HelloProperties helloProperties) {
return new StdOutHello(helloProperties.getGreeting());
}
}
1 | Example Auto-configuration class provides unconditional @Bean factory for Hello |
2 | this @Configuration package is outside the default scanning scope of @SpringBootApplication |
Auto-Configuration Packages are Separate from Application Auto-Configuration classes are designed to be outside the scope of the
|
Spring Boot 2.7 added the @AutoConfiguration
annotation, which
extends @Configuration
permanently sets proxyBeanMethods to false
contains aliases for before/after configuration processing order
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
//@Configuration(proxyBeanMethods = false)
@AutoConfiguration
public class HelloAutoConfiguration {
It helps document the purpose of the @Configuration
class and provides some ease of use features, but the @Configuration
annotation can still be used.
this particular @Bean
factory defines the @ConfigurationProperties
class to
encapsulate the details of configuring Hello
supplies a default greeting
making it optional for the User-defined configuration to do anything
@ConfigurationProperties("hello")
@Data
@Validated
public class HelloProperties {
@NotBlank
private String greeting = "HelloProperties default greeting says Hola!"; (1)
}
1 | Value used if user-configuration does not specify a property value |
registered within META-INF/spring/ org.springframework.boot.autoconfigure.AutoConfiguration
file of Auto-configuration class’s JAR
$ jar tf target/hello-starter-*-SNAPSHOT.jar | egrep -v '/$|maven|MANIFEST.MF'
META-INF/spring-configuration-metadata.json (2)
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (1)
info/ejava/examples/app/hello/HelloProperties.class
info/ejava/examples/app/hello/HelloAutoConfiguration.class
1 | "auto-configuration" dependency JAR supplies … AutoConfiguration.imports |
2 | @ConfigurationProperties class metadata generated by maven plugin for use by IDEs |
It is common best-practice to host Auto-configuration classes in a separate
module than the beans it configures. The Hello interface and Hello implementation(s)
comply with this convention and are housed in separate modules. |
List each fully qualified class name in … AutoConfiguration.imports
file, one per line
# src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
info.ejava.examples.app.hello.HelloAutoConfiguration (1)
info.ejava.examples.app.hello.HelloResourceAutoConfiguration (2)
1 | Auto-configuration class registration |
2 | this class is part of a later example; multiple classes are listed one-per-line |
Prior to Spring Boot 2.7, the general purpose META-INF/spring.factories
file was used to bootstrap auto-configuration classes.
This approach was deprecated in 2.7 and eliminated in Spring Boot 3.
If you are ever working with a legacy version of Spring Boot, you will have to use this approach.
list each class' fully qualified name, separated by commas, in spring.factories
file
used property name equaling fully qualified classname of @EnableAutoConfiguration
annotation
# src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
info.ejava.examples.app.hello.HelloAutoConfiguration, \ (1)
info.ejava.examples.app.hello.HelloResourceAutoConfiguration
1 | Auto-configuration class registration |
The last line of the property cannot end with a comma or Spring Boot 2 will interpret entry as an empty class name |
pom.xml
src
`-- main
|-- java
| `-- info
| `-- ejava
| `-- examples
| `-- app
| `-- hello
| |-- HelloAutoConfiguration.java
| `-- HelloProperties.java
`-- resources
`-- META-INF
`-- spring
`-- org.springframework.boot.autoconfigure.AutoConfiguration.imports
Modules designed as starters can have varying designs with the following roles carried out:
Auto-configuration classes that conditionally wire the application.
An opinionated starter with dependencies that trigger the Auto-configuration rules
The module commonly termed a starter
and will have dependencies on
spring-boot-starter, which has dependency on spring-boot-autoconfigure with auto-configuration class references waiting for conditions
the service interface
one or more service implementation(s) and their implementation dependencies
<groupId>info.ejava.examples.app</groupId>
<artifactId>hello-starter</artifactId>
<dependencies>
<dependency> (1)
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- commonly declares dependency on interface module -->
<dependency> (2)
<groupId>${project.groupId}</groupId>
<artifactId>hello-service-api</artifactId>
<version>${project.version}</version>
</dependency> (2)
<!-- hello implementation dependency -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>hello-service-stdout</artifactId>
<version>${project.version}</version>
</dependency>
1 | dependency on spring-boot-starter define classes pertinent to Auto-configuration |
2 | starter modules commonly define dependencies on interface and implementation modules |
remaining dependencies support the specific example module implementation
The application module declares dependency on the starter module containing or having a dependency on the Auto-configuration artifacts.
<!-- takes care of initializing Hello Service for us to inject -->
<dependency>
<groupId>${project.groupId}</groupId> (1)
<artifactId>hello-starter</artifactId>
<version>${project.version}</version> (1)
</dependency>
1 | For this example, the application and starter modules share the same groupId and version
and leverage a ${project} variable to simplify the expression.
That will likely not be the case with most starter module dependencies and will need to be spelled out. |
starter dependency brings in
Hello Service interface
targeted implementation(s)
some implementation dependencies
$ mvn dependency:tree
...
[INFO] +- info.ejava.examples.app:hello-starter:jar:6.1.0-SNAPSHOT:compile
[INFO] | +- info.ejava.examples.app:hello-service-api:jar:6.1.0-SNAPSHOT:compile
[INFO] | +- info.ejava.examples.app:hello-service-stdout:jar:6.1.0-SNAPSHOT:compile
[INFO] | +- org.projectlombok:lombok:jar:1.18.10:provided
[INFO] | \- org.springframework.boot:spring-boot-starter-validation:jar:3.3.2:compile
...
example application contains component that requests the greeter implementation of type Hello
to say hello to "World"
import lombok.RequiredArgsConstructor;
...
@Component
@RequiredArgsConstructor (1)
public class AppCommand implements CommandLineRunner {
private final Hello greeter; //<== component in App requires Hello injected
public void run(String... args) throws Exception {
greeter.sayHello("World");
}
}
1 | lombok is being used to provide the constructor injection |
This starter dependency is bringing in a @Bean
factory to construct an implementation of Hello
, that can satisfy the injection dependency.
package info.ejava.examples.app.hello;
...
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
public Hello hello(HelloProperties helloProperties) { (1)
return new StdOutHello(helloProperties.getGreeting());
}
}
1 | Example Auto-configuration configured by HelloProperties |
This bean will be unconditionally instantiated the way it is currently defined.
starter dependency brings in an Auto-configuration class that instantiates a StdOutHello
implementation configured by a HelloProperties
class
@ConfigurationProperties("hello")
@Data
@Validated
public class HelloProperties {
@NotBlank
private String greeting = "HelloProperties default greeting says Hola!"; (1)
}
1 | hello.greeting default defined in @ConfigurationProperties class of starter/autoconfigure module |
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar
...
HelloProperties default greeting says Hola! World
HelloAutoConfiguration.hello
@Bean
instantiated with HelloProperties
greeting of "HelloProperties default greeting says Hola!"
This Hello
instance was injected into AppCommand
, which added "World" to result
Example of Reasonable Default This is an example of a component being Auto-configured with a reasonable default.
It did not simply crash, demanding a greeting be supplied. |
application can supply properties to express details of greeting
#appconfig-autoconfig-example application.properties
#uncomment to use this greeting
hello.greeting: application.properties Says - Hey
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar
...
application.properties Says - Hey World (1)
1 | auto-configured implementation using user-defined property |
same scenario as before is occurring
except instantiation of the HelloProperties
finds hello.greeting
property to override Java default
Example of Configuring Details This is an example of customizing the behavior of an Auto-configured component. |
We saw how we could make a @Bean
factory in the User-defined application module conditional (on the value of a property).
@SpringBootApplication
public class StarterConfiguredApp {
...
@Bean
@ConditionalOnProperty(prefix = "hello", name = "quiet", havingValue = "true")
public Hello quietHello() {
return new StdOutHello("(hello.quiet property condition set, Application @Bean says hi)");
}
}
have condition where our two @Bean
factory methods cause ambiguity error
@Bean
factory in User-defined application module conditional (on property value)
@Bean
factory in Auto-configuration class brought in by starter module
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar --hello.quiet=true (1)
...
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in info.ejava.examples.app.config.auto.AppCommand
required a single bean, but 2 were found:
- quietHello: defined by method 'quietHello' in info.ejava.examples.app.config.auto.StarterConfiguredApp
- hello: defined by method 'hello' in class path resource [info/ejava/examples/app/hello/HelloAutoConfiguration.class]
This may be due to missing parameter name information
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
1 | Supplying the hello.quiet=true property value causes two @Bean factories to choose from |
Conditional
If User-definition did not supply a bean
can solve ambiguity by using @ConditionalOnMissingBean annotation
...
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnMissingBean (1)
public Hello hello(HelloProperties helloProperties) {
return new StdOutHello(helloProperties.getGreeting());
}
}
1 | @ConditionOnMissingBean causes Auto-configured @Bean method to be inactive when Hello bean already exists |
@ConditionalOnMissingBean
and sibling @ConditionalOnBean are special
meant to be used with Auto-configuration classes in the autoconfigure modules
Auto-configuration classes are processed after the User-defined classes
clear point to determine whether User-defined @Bean
factory does or does not exist
any other use of these two annotations requires careful ordering and is not recommended
with @ConditionalOnMissingBean
defined on Auto-configuration class and the property condition satisfied
we get bean injected from User-defined @Bean
factory
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar --hello.quiet=true
...
(hello.quiet property condition set, Application @Bean says hi) World
with property condition not satisfied, we get bean injected from
Auto-configuration @Bean
factory
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar
...
application.properties Says - Hey World
can define condition based on presence of resource on filesystem or classpath using @ConditionOnResource
can also order our Auto-configured classes using
...
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
@Configuration(proxyBeanMethods = false)
@ConditionalOnResource(resources = "file:./hello.properties") (1)
@AutoConfigureBefore(HelloAutoConfiguration.class) (2)
public class HelloResourceAutoConfiguration {
@Bean
public Hello resourceHello() {
return new StdOutHello("hello.properties exists says hello");
}
}
1 | Auto-configured class satisfied only when file hello.properties present |
2 | This Auto-configuration class is processed prior to HelloAutoConfiguration |
We can use the @AutoConfiguration
annotation
wraps some of our desired settings
import org.springframework.boot.autoconfigure.AutoConfiguration;
@AutoConfiguration(before = HelloAutoConfiguration.class)
//==> wraps @Configuration(proxyBeanMethods = false)
//==> wraps @AutoConfigureBefore(HelloAutoConfiguration.class)
@ConditionalOnClass(StdOutHello.class)
@ConditionalOnResource(resources = "file:./hello.properties")
public class HelloResourceAutoConfiguration {
# src/main/resources/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
info.ejava.examples.app.hello.HelloAutoConfiguration
info.ejava.examples.app.hello.HelloResourceAutoConfiguration
with hello.properties
present
@Bean
factory from HelloAutoConfiguration
skipped — bean already exists
bean created using HelloResourceAutoConfiguration
@Bean
factory — evaluated before HelloAutoConfiguration
$ touch hello.properties
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar
...
hello.properties exists says hello World
when property file is not present:
@Bean
factory from HelloAutoConfiguration
used since neither property nor resource-based conditions satisfied
$ rm hello.properties
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar
...
application.properties Says - Hey World
familiar situation — ambiguous match
if we supply a hello.properties
file and hello.quiet=true
property value
$ touch hello.properties
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar --hello.quiet=true
...
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in info.ejava.examples.app.config.auto.AppCommand required a single bean,
but 2 were found:
- quietHello: defined by method 'quietHello' in info.ejava.examples.app.config.auto.StarterConfiguredApp
- resourceHello: defined by method 'resourceHello' in class path resource
[info/ejava/examples/app/hello/HelloResourceAutoConfiguration.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans,
or using @Qualifier to identify the bean that should be consumed
this time — to correct — we add the @Primary annotation to our highest priority @Bean
factory
if there is a conflict — this one will be used
...
import org.springframework.context.annotation.Primary;
@AutoConfiguration(before = HelloAutoConfiguration.class)
@ConditionalOnResource(resources = "file:./hello.properties")
public class HelloResourceAutoConfiguration {
@Bean
@Primary //chosen when there is a conflict
public Hello resourceHello() {
return new StdOutHello("hello.properties exists says hello");
}
}
avoided conflict error with one of the @Bean
factories listed as @Primary
$ touch hello.properties
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar --hello.quiet=true (1)
...
hello.properties exists says hello World
1 | @Primary condition satisfied overrides application @Bean condition |
important difference between conditions applied to @Configuration
class or methods
class conditional annotations prevent entire class from loading when not satisfied
@Bean
factory conditional annotations allow class to load but prevent method from
being called when not satisfied
this works for missing classes too!
Spring Boot parses conditional class using ASM to detect and evaluate conditions before allowing class to be loaded into JVM
otherwise we would get ClassNotFoundException
for the import of class we are trying
to base condition on
adding
@ConditionalOnClass
annotation to prevent @Configuration
class from being loaded if implementation
class does not exist on classpath
...
import info.ejava.examples.app.hello.stdout.StdOutHello; (2)
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(StdOutHello.class) (2)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public Hello hello(HelloProperties helloProperties) {
return new StdOutHello(helloProperties.getGreeting()); (1)
}
}
1 | StdOutHello is the implementation instantiated by the @Bean factory method |
2 | HelloAutoConfiguration.class will not get loaded if StdOutHello.class does not exist |
@ConditionOnClass
accepts either class or string expression of fully qualified classname
@ConditionalOnMissingClass accepts only string form of classname
Spring Boot Autoconfigure module contains many examples of real Auto-configuration classes |
We can turn off certain Auto-configured classes using the
exclude
attribute of the @EnableAutoConfiguration
annotation
exclude
attribute of the @SpringBootApplication
annotation which wraps the @EnableAutoConfiguration
annotation
@SpringBootApplication(exclude = {})
// ==> wraps @EnableAutoConfiguration(exclude={})
public class StarterConfiguredApp {
...
}
many conditional User-defined and Auto-configurations going on
easy to get lost or make a mistake
two primary tools can expose details of conditional configuration decisions
Conditions Evaluation Report
Spring Boot Actuator
simplistic textual report of positive and negative condition evaluation matches
add a debug
property to the configuration
--debug
or -Ddebug to the command line
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar --debug | less
...
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches: (1)
-----------------
HelloAutoConfiguration matched:
- @ConditionalOnClass found required class 'info.ejava.examples.app.hello.stdout.StdOutHello' (OnClassCondition)
HelloAutoConfiguration#hello matched:
- @ConditionalOnMissingBean (types: info.ejava.examples.app.hello.Hello; SearchStrategy: all) did not find any beans (OnBeanCondition)
Negative matches: (2)
-----------------
HelloResourceAutoConfiguration:
Did not match:
- @ConditionalOnResource did not find resource 'file:./hello.properties' (OnResourceCondition)
Matched:
- @ConditionalOnClass found required class 'info.ejava.examples.app.hello.stdout.StdOutHello' (OnClassCondition)
StarterConfiguredApp#quietHello:
Did not match:
- @ConditionalOnProperty (hello.quiet=true) did not find property 'quiet' (OnPropertyCondition)
1 | Positive matches show which conditionals are activated and why |
2 | Negative matches show which conditionals are not activated and why |
The report shows us that
HelloAutoConfiguration
class was enabled because StdOutHello
class was present
hello
@Bean
factory method of HelloAutoConfiguration
class was enabled because no other
beans were located
entire HelloResourceAutoConfiguration
class was not loaded because file hello.properties
was not present
quietHello
@Bean
factory method of application class was not activated because
hello.quiet
property was not found
can also look at conditionals while Web applications are running using the Spring Boot Actuator
requires example transitioned from a command to a Web application
can be done technically by simply changing our starter in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- <artifactId>spring-boot-starter</artifactId>-->
</dependency>
also need to add a dependency on the spring-boot-starter-actuator module
<!-- added to inspect env -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Actuator, by default, will not expose any information without being configured to do so
can show a JSON version of the Conditions Evaluation Report by adding
management.endpoints.web.exposure.include
equal to value “conditions”
performed here using command line
could be in a profile-specific properties file appropriate for exposing this information
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar \
--management.endpoints.web.exposure.include=conditions
report available at: http://localhost:8080/actuator/conditions
{
"contexts": {
"application": {
"positiveMatches": {
"HelloAutoConfiguration": [{
"condition": "OnClassCondition",
"message": "@ConditionalOnClass found required class 'info.ejava.examples.app.hello.stdout.StdOutHello'"
}],
"HelloAutoConfiguration#hello": [{
"condition": "OnBeanCondition",
"message": "@ConditionalOnBean (types: info.ejava.examples.app.hello.Hello; SearchStrategy: all) did not find any beans"
}],
...
,
"negativeMatches": {
"StarterConfiguredApp#quietHello": {
"notMatched": [{
"condition": "OnPropertyCondition",
"message": "@ConditionalOnProperty (hello.quiet=true) did not find property 'quiet'"
}],
"matched": []
},
"HelloResourceAutoConfiguration": {
"notMatched": [{
"condition": "OnResourceCondition",
"message": "@ConditionalOnResource did not find resource 'file:./hello.properties'"
}],
"matched": []
},
...
also helpful to inspect the environment
determine value of properties
determine which source of properties is being used
add env
to the exposure.include
property to see information
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar \
--management.endpoints.web.exposure.include=conditions,env
adds new endpoints to see property information
full /env
endpoint
specific /env/{property}
endpoint for a specific property name
links available at http://localhost:8080/actuator
{
_links: {
self: {
href: "http://localhost:8080/actuator",
templated: false
},
conditions: {
href: "http://localhost:8080/actuator/conditions",
templated: false
},
env: {
href: "http://localhost:8080/actuator/env",
templated: false
},
env-toMatch: {
href: "http://localhost:8080/actuator/env/{toMatch}",
templated: true
}
}
}
available at http://localhost:8080/actuator/env
{
activeProfiles: [ ],
propertySources: [{
name: "server.ports",
properties: {
local.server.port: {
value: 8080
}
}
},
{
name: "commandLineArgs",
properties: {
management.endpoints.web.exposure.include: {
value: "conditions,env"
}
}
},
...
source of specific property and its defined value
available below the /actuator/env
URI
{
property: {
source: "applicationConfig: [classpath:/application.properties]",
value: "application.properties Says - Hey"
},
...
can explore some of the other Actuator endpoints by
changing the include property to *
revisiting the main actuator endpoint
Actuator Documentation is available on the web
$ java -jar target/appconfig-autoconfig-*-SNAPSHOT-bootexec.jar \
--management.endpoints.web.exposure.include="*" (1)
1 | double quotes ("") being used to escape * special character on command line |
In this module we:
Defined conditions for @Configuration
classes and @Bean
factory methods that
are evaluated at runtime startup
Placed User-defined conditions, which are evaluated first, in with application module
Placed Auto-configuration classes in separate starter
module to automatically
bootstrap applications with specific capabilities
Added conflict resolution and ordering to conditions to avoid ambiguous matches
Discovered how class conditions can help prevent entire @Configuration
classes from
being loaded and disrupt the application because an optional class is missing
Learned how to debug conditions and visualize the runtime environment through use of
the debug
property or by using the Actuator for web applications