Using Spring Boot's autoconfiguration report

As we've seen in this book so far, Spring Boot autoconfigures beans to help us avoid configuring infrastructure and instead focus on coding business requirements. However, sometimes, we may want to know what Spring Boot did (or didn't) do for us.

That's why it has an autoconfiguration report. Essentially, every time a bean is selected based on some conditional check, Spring Boot logs the decision (yea or nay) and offers it to us in many different ways.

The simplest approach is to add --debug to the run configuration. In the following screenshot, we can see how to set it in IntelliJ:

If we launch our app with --debug as a program argument, an autoconfiguration report is printed out to the console:

That's nice, and during certain failure scenarios, the report will print out automatically to help with postmortem analysis. However, scraping the console for a report isn't very effective.

If we use Spring Boot Actuator, we can consume this report in a nicer JSON structure. If you'll recall, we included Actuator in our list of dependencies back in Chapter 1, Quick Start with Java:

    compile('org.springframework.boot:spring-boot-starter-actuator')  
If you're building a new application and didn't pick it on http://start.spring.io, this dependency is quite valuable.

In addition to adding Spring Boot's Actuator module, we have to opt in or rather enable its features. In Spring Boot 2.0, Actuator supports many technologies including Spring MVC, Spring WebFlux, and JMX. We have to signal what platforms we wish to enable instead of expecting Spring Boot to guess. To do so, we need to add the following line of code to our application.properties file:

    endpoints.default.web.enabled=true  

This will make Actuator's endpoints active from an HTTP perspective; (to enable Actuator for JMX, we would want to set endpoints.default.jmx.enabled to true).

When we launch our application, several Spring WebFlux endpoints are added, providing additional information. To get a quick glance at all the available endpoints, we can visit http://localhost:8080/application, as shown in the following screenshot:

his screenshot doesn't capture them all, but there is a long list of endpoints serving up detailed information about our application. (By the way, earlier in the book, we enabled just one actuator endpoint, /application/health. This flag lets us switch on all the default endpoints.)

From there, we can easily find the autoconfiguration report at http://localhost:8080/application/autoconfig, click on it, and thanks to JSON Viewer (https://github.com/tulios/json-viewer), see this nicely formatted report:

Okay, so we've seen a couple ways to generate this report. But what does it say?

If we zoom into one fragment, we can figure something out:

    "ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration": [ 
    { 
      "condition": "OnClassCondition", 
      "message": "@ConditionalOnClass found required class 
'reactor.ipc.netty.http.server.HttpServer';
@ConditionalOnMissingClass did not find unwanted class" }, { "condition": "OnBeanCondition", "message": "@ConditionalOnMissingBean (types:
org.springframework.boot.web.reactive
.server.ReactiveWebServerFactory; SearchStrategy: all) did
not find any beans" } ]

This fragment of JSON in the autoconfiguration report can be described as follows:

  • ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration is a Spring Boot autoconfiguration policy that was evaluated, specifically on the subject of Netty.
  • @ConditionalOnClass matched on spotting Reactor's HttpServer class, glue code used by Reactor to embed the Netty container. This shows that Netty was on the classpath.
  • @ConditionalOnMissingBean is the second condition, and was negative, indicating there is no overriding, user-defined ReactiveWebServerFactory defined. Therefore, Spring Boot is activating its default policy for Reactor Netty.

To divine exactly what this autoconfiguration policy was, we can open the code and inspect it ourselves. Using our IDE, we merely need to look for the parent class, ReactiveWebServerConfiguration:

    abstract class ReactiveWebServerConfiguration { 
 
      @ConditionalOnMissingBean(ReactiveWebServerFactory.class) 
      @ConditionalOnClass({ HttpServer.class }) 
      static class ReactorNettyAutoConfiguration { 
 
        @Bean 
        public NettyReactiveWebServerFactory 
NettyReactiveWebServerFactory() { return new NettyReactiveWebServerFactory(); } } ... }

This fragment from Spring Boot's Reactive web server configuration code can be explained as follows:

  • ReactiveWebServerConfiguration is an abstract class that is merely used as a container for other policies
  • @ConditionalOnMissingBean(ReactiveWebServerFactory.class) tells Spring Boot to back off and not use this if the user has declared such a bean elsewhere
  • @ConditionalOnClass({HttpServer.class}) tells Spring Boot to only consider this if Reactor Netty is on the classpath
  • static class ReactorNettyAutoConfiguration names this rule used to autoconfigure Reactor Netty
  • @Bean flags the code as a Spring bean
  • return new NettyReactiveWebServerFactory() actually creates the Spring bean for Reactor Netty

All this comes together to allow Reactor Netty to be configured automatically when put on the classpath. And we spotted it in the autoconfiguration report.

There are other bean definitions in ReactiveWebServerConfiguration, including support for Jetty, Apache Tomcat, and Undertow, but aren't shown due to space constraints.

What is this good for?

If we are attempting to use some feature of Spring Boot and it's not going as desired, one thing to debug is whether or not the expected beans are being created. Another usage is if we are working on our own autoconfiguration module for a given project and need to see if the right beans are being created.

You see, the autoconfiguration report isn't confined to what is released by the Spring team. It looks at everything.

Speaking of making a change, notice how we have Netty running under the hood. We can tell both from the console output as well as the autoconfiguration report we just looked at.

What if we wanted to change containers? It's quite easy with Spring Boot. We simply have to tweak the build file.

By default, Spring Boot uses Netty for Reactive apps, but it's not hard to switch:

    compile('org.springframework.boot:spring-boot-starter-webflux') { 
      exclude module: 'spring-boot-starter-reactor-netty' 
    } 
    compile('org.springframework.boot:spring-boot-starter-undertow') 

The changes to build.gradle are as follows:

  • Excludes spring-boot-starter-reactor-netty from the reactive web dependency
  • Introduces spring-boot-starter-undertow as an alternative container

If we relaunch our application and look at the autoconfiguration report again and look for the ReactorNettyAutoConfiguration entry, we will find this:

    "ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration": { 
      "notMatched": [ 
      { 
        "condition": "OnClassCondition", 
        "message": "@ConditionalOnClass did not find required class 
'reactor.ipc.netty.http.server.HttpServer'" } ], "matched": [ ] }

The new fragment of JSON from the autoconfiguration report shows that the same policy we just looked at has now switched to notMatched. In the details, it failed because @ConditionalOnClass didn't spot HttpServer on the classpath.

In light of switching from Reactor Netty to Undertow, searching for Undertow in the autoconfiguration report will lead us to this:

    "ReactiveWebServerConfiguration.UndertowAutoConfiguration": [ 
    { 
      "condition": "OnClassCondition", 
      "message": "@ConditionalOnClass found required class 
'io.undertow.Undertow'; @ConditionalOnMissingClass did not
find unwanted class" }, { "condition": "OnBeanCondition", "message": "@ConditionalOnMissingBean (types:
org.springframework.boot.web.reactive.server
.ReactiveWebServerFactory; SearchStrategy: all) did not
find any beans" } ]

This fragment of JSON reveals that UndertowAutoConfiguration is now in effect as follows:

  • @ConditionalOnClass has found Undertow on the classpath
  • @ConditionalOnMissingBean has not found a user-defined ReactiveWebServerFactory bean; hence, Spring Boot did not back off with its autoconfiguration of Undertow.

On further digging into UndertowReactiveWebServerFactory, we will find all the details needed to run Undertow for a Reactor-based application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.144.229