du.study기록공간

Spring Cloud Sleuth를 적용할때 AsyncConfigurer를 구현하는 @Configuration이 있다면 본문

스프링

Spring Cloud Sleuth를 적용할때 AsyncConfigurer를 구현하는 @Configuration이 있다면

du.study 2024. 10. 16. 19:41
728x90

 

Spring Cloud Sleuth를 적용하는 과정에 확인한 간단한 에러를 기록해보고자 합니다. (나중에 또 기억 못할까봐)

 

기존 코드에는 비동기관련 Configuration이 있었고, AsyncConfigurer를 implements한 AsyncConfigurer 를 상속해놓은 Configuration이 있었습니다. 해당 코드에서는 기본 구현체 외에도 별도로 쓰레드풀을 선언한 상태였습니다.

@Configuration
@EnableAsync
public class AsyncConfiguration extends AsyncConfigurerSupport {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        ....
        return executor;
    }

    @Bean(name = "workThreadPoolTaskExecutor")
    public ThreadPoolTaskExecutor workThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
       	....
        return taskExecutor;
    }
}

 

이 과정에서 로그 추적을 위해 Spring Cloud Sleuth를 추가하는순간 아래 추가해둔 workThreadPoolTaskExecutor는 Bean생성이 되지않는 문제가 발생했습니다. (해당 bean을 쓰고있으나, bean생성이 안되어 구동시점에 알게됐네요)

 

그 원인이 뭐일까 stack을 따라가던 도중 TraceAsyncCustomAutoConfiguration 를 발견했고 postProcessAfterInitialization코드를 보고 느낌이와 디버깅 포인트를 잡아보니 원인을 확인할 수 있었습니다. (버전따라 AsyncCustomAutoConfiguration 이름도 있네요)

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(AsyncConfigurer.class)
@ConditionalOnBean(AsyncConfigurer.class)
@AutoConfigureBefore(TraceAsyncDefaultAutoConfiguration.class)
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
@AutoConfigureAfter(name = "org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAutoConfiguration",
		value = BraveAutoConfiguration.class)
public class TraceAsyncCustomAutoConfiguration implements BeanPostProcessor {

	@Autowired
	private BeanFactory beanFactory;

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean instanceof AsyncConfigurer && !(bean instanceof LazyTraceAsyncCustomizer)) {
			AsyncConfigurer configurer = (AsyncConfigurer) bean;
			return new LazyTraceAsyncCustomizer(this.beanFactory, configurer);
		}
		return bean;
	}

}

 

class명이되는 AsyncConfiguration 를 먼저 Bean으로 인식하고, sleuth의 해당 메서드에 의하여 AsyncConfiguration는 LazyTraceAsyncCustomizer로 래핑되었습니다.

이후 LazyTraceAsyncCustomizer class로 래핑되어있는 AsyncConfiguration class에다가  workThreadPoolTaskExecutor를 가져오기위해 Method.invoke하는 코드가 동작합니다.

하지만 LazyTraceAsyncCustomizer로 매핑된 class에는 workThreadPoolTaskExecutor가 없으니 에러가 발생하는 수순이였습니다.

 

이걸 해결하는 방법은 여러가지가 있을것 같습니다.

1. AsyncConfigurer를 지우고, @Async 로직에 threadPool을 직접 명시한다.

2. 별도의 Configuration에서  ThreadPoolTaskExecutor를  @Bean 선언한다

3. 래핑을 exclude시키는 방법  https://github.com/spring-cloud/spring-cloud-sleuth/issues/2100


문제해결이야 쉽지만 혹시나 원인이 궁금하거나 미래에 또까먹을 나를 위해 작성해봅니다.

 

 

728x90
Comments