Bug report: After updating spring boot from 2.5.7 to 2.6.7 (Or any version higher than 2.5.7) Our app faces an issue and is unable to start. (Only When Sleuth is used in our code)

The error :

Caused by: java.lang.ClassCastException: class org.springframework.cloud.sleuth.instrument.async.LazyTraceAsyncCustomizer cannot be cast to class org.springframework.web.servlet.config.annotation.WebMvcConfigurer (org.springframework.cloud.sleuth.instrument.async.LazyTraceAsyncCustomizer and org.springframework.web.servlet.config.annotation.WebMvcConfigurer are in unnamed module of loader 'app')
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite.configurePathMatch(WebMvcConfigurerComposite.java:52)

The error explained after debugging :

In file WebMvcConfigurerComposite method configurePathMatch is trying to cast all delegates to WebMvcConfigurer The issue is here because spring boot instead of having our AsyncConfig file which implements WebMvcConfigurer it mistakenly get another class instead and that class is LazyTraceAsyncCustomizer , which doesn't implement the WebMvcConfigurer then it fails because it can't cast it

To Reproduce Steps to reproduce the behavior: 1. Use below versions together (Or any spring boot later than 2.5.7):

  <dependencyManagement>
    <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>2021.0.2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    </dependencies>
  </dependencyManagement> 

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
  1. Try to create AsyncConfig class which use Sleuth e.g. LazyTraceAsyncTaskExecutor & LazyTraceExecutor (Below is our current Kotlin class)
package nl.rabobank.online.dao.config

import org.springframework.beans.factory.BeanFactory
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.cloud.sleuth.instrument.async.LazyTraceAsyncTaskExecutor
import org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Role
import org.springframework.scheduling.annotation.AsyncConfigurer
import org.springframework.scheduling.annotation.EnableAsync
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.RejectedExecutionHandler
import java.util.concurrent.ThreadPoolExecutor

private const val TEN_SECOND_DELAY = 10000L

private const val TP_EXECUTOR_SIZE = 20

private const val TP_TASK_SIZE = 5

private const val TP_QUEUE_SIZE = 30

@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EnableAsync // add the infrastructure role to ensure that the bean gets auto-proxied
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
class AsyncConfig(private val beanFactory: BeanFactory) : AsyncConfigurer,WebMvcConfigurer{

    private val executor = threadPoolTaskExecutor(TP_EXECUTOR_SIZE, 0, "task-", true)

    override fun getAsyncExecutor() = LazyTraceExecutor(beanFactory, executor)

    override fun configureAsyncSupport(configurer: AsyncSupportConfigurer) {
        configurer.setTaskExecutor(LazyTraceAsyncTaskExecutor(beanFactory, executor))
    }

    private fun threadPoolTaskExecutor(
        poolSize: Int,
        queueCapacity: Int,
        threadNamePrefix: String,
        shouldBlock: Boolean
    ): ThreadPoolTaskExecutor {
        val executor = ThreadPoolTaskExecutor()
        // CUSTOMIZE HERE
        executor.corePoolSize = poolSize
        executor.maxPoolSize = poolSize
        executor.setQueueCapacity(queueCapacity)
        executor.setThreadNamePrefix(threadNamePrefix)
        executor.setWaitForTasksToCompleteOnShutdown(true)
        executor.setAwaitTerminationMillis(TEN_SECOND_DELAY)
        if (shouldBlock) {
            executor.setRejectedExecutionHandler(BlockingExecutionHandler())
        }
        // DON'T FORGET TO INITIALIZE
        executor.initialize()
        return executor
    }

    @Bean("documentCreationPoolTaskExecutor")
    fun getDocumentCreationPoolTaskExecutor(): LazyTraceExecutor {
        val threadPoolExecutorConfig = threadPoolTaskExecutor(TP_TASK_SIZE, TP_QUEUE_SIZE, "doc-create-", false)
        return LazyTraceExecutor(beanFactory, threadPoolExecutorConfig)
    }
}

internal class BlockingExecutionHandler : RejectedExecutionHandler {
    override fun rejectedExecution(runnable: Runnable, executor: ThreadPoolExecutor) {
        try {
            // based on the BlockingQueue documentation below should block until able to place on the queue...
            executor.queue.put(runnable)
        } catch (e: InterruptedException) {
            throw RejectedExecutionException(
                "There was an unexpected InterruptedException whilst waiting to add a Runnable in the executor's blocking queue",
                e
            )
        }
    }
}

  1. Try to start your spring boot app,Then it won't start and it will give the above error.

Version of the framework Spring cloud dependencies : 2021.0.2 Spring boot parent: 2.6.7

Expected behavior Expected behaviour when it works (For versions earlier than 2.5.8) in file WebMvcConfigurerComposite METHOD configurePathMatch The delegates object Should contain our correct AsyncConfig class below (Which impl. the WebMvcConfigurer) :

{AsyncConfig@10458} nl.rabobank.online.dao.config.AsyncConfig@40cd02fc BUT Instead (In versions later than 2.5.7) it contains this: {LazyTraceAsyncCustomizer@10473}

Screenshots Screen shots of Debugging Spring code: Screenshot 2022-05-08 at 13 13 34

Screenshot 2022-05-08 at 13 08 53 Screenshot 2022-05-08 at 13 09 31

See invalid class LazyTraceAsyncCustomizer not impl. the WebMvcConfigurer at all

Screenshot 2022-05-08 at 13 10 18

Additional context It is a critical bug for our team and preventing us from upgrading Spring boot version to solve other security issues.

Comment From: wilkinsona

This is a duplicate of https://github.com/spring-cloud/spring-cloud-sleuth/issues/2100 which should be fixed in Spring Cloud 2021.0.3.