How to debug Spring Boot autoconfiguration

148 views Asked by At

A common problem pattern when working with Spring Boot is that a bean is missing, although that one expects it to be created by Spring Boot.

How does one debug such a scenario? How does one find out why that bean wasn't created as expected!

Note: I created this question and it's answer from a question asking this for a special case. I hope this is helpful in a wide array of scenarios.

1

There are 1 answers

0
Jens Schauder On
  1. Enable Spring Boot's debugging by adding debug=true to your application.properties file.

    This creates log output during startup. For each auto-configuration available it contains the information if it "matched" or not, i.e. if it's preconditions are fulfilled, and what these conditions are.

  2. Look especially in the section Negative matches of the output for auto-configurations that should happen but don't. Searching for relevant technologies in the log is a good idea.

  3. auto-configurations you found in the previous step might hint at other auto-configurations that didn't get activated. For these repeat step 2.

The following is an example of that search for https://github.com/iosenberg/todo/commit/c4cfbf63132e251ce98cfe02178bd48cc447aac7 Which was referenced in Spring boot can't find Repository bean

The missing bean is a Spring Data JDBC repository. Therefore datasource or jdbc come to mind as first search terms. Searching for JDBC yields the following results that seem relevant:

   DataSourceAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' (OnClassCondition)
      - @ConditionalOnMissingBean (types: io.r2dbc.spi.ConnectionFactory; SearchStrategy: all) did not find any beans (OnBeanCondition)

   DataSourceTransactionManagerAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'org.springframework.jdbc.core.JdbcTemplate', 'org.springframework.transaction.TransactionManager' (OnClassCondition)

This looks like there is a DataSource, which just demonstrates that you shouldn't stop at the first match.

The next match is:

   DataSourceInitializationConfiguration:
      Did not match:
         - @ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) did not find any beans (OnBeanCondition)
      Matched:
         - @ConditionalOnClass found required class 'org.springframework.jdbc.datasource.init.DatabasePopulator' (OnClassCondition)

So, DataSourceAutoConfiguration did run, but we still don't seem to have a DataSource bean. From this we learn that there is an important difference between a class being available and a bean of that type being available. Kind of obvious when you say it out loud, yet easy to miss when you look at some log file.

The rest of the search turns up just more stuff that doesn't work, which is either irrelevant, or not surprising if there is no DataSource bean. Therefore I switched to searching for datasource in the log.

That returns tons of hits. But the first one in the Negative matches was really helpful.

   DataSourceAutoConfiguration.EmbeddedDatabaseConfiguration:
      Did not match:
         - EmbeddedDataSource did not find embedded database (DataSourceAutoConfiguration.EmbeddedDatabaseCondition)

So no embedded database found! What database is it trying to use? Checking the application.properties for a JDBC url shows there is none. Checking the dependencies shows there is an embedded database, but only with scope test, therefore for the main program there is no JDBC driver available. Fixing that by making the in memory database dependency available for the main application solved the proble.