728x90

RequestContextHolder 는 ThreadLocal 을 사용하여 attributes 들을 저장하고 있다.

MVC spring 에서 비동기적으로 작업을 처리해야 할때가 있는데 이때 RequestContextHolder 에 접근하게 되면 Thread 가 달라 attributes 가 원하는 값이 나오지 않게 된다.

 

문제해결

@Configuration
class WebConfig : ServletContextInitializer {

    override fun onStartup(servletContext: ServletContext) {
        val applicationContext = AnnotationConfigWebApplicationContext()
        val dispatcherServlet = DispatcherServlet(applicationContext)
        dispatcherServlet.setThreadContextInheritable(true)

        val dispatcher: ServletRegistration.Dynamic = servletContext.addServlet("dispatcherServlet", dispatcherServlet)
        dispatcher.setLoadOnStartup(1)
        dispatcher.addMapping("/")
    }
}

 

ServletContextInitializer 의 onStartup 을 override 하여 Request 의 Main Thread 에서 Thread 가 변경될 경우 attributes 들을 copy 하여 넘기는 방식이다.

 

https://gompangs.tistory.com/entry/Spring-RequestContextHolder

 

Spring RequestContextHolder

RequestContextHolder 개요 RequestContextHolder 는 Spring에서 전역으로 Request에 대한 정보를 가져오고자 할 때 사용하는 유틸성 클래스이다. 주로, Controller가 아닌 Business Layer 등에서 Request 객체를..

gompangs.tistory.com

 

Thread Pool 을 override 하기

class ContextAwarePoolExecutor : ThreadPoolTaskExecutor() {
    override fun <T> submit(task: Callable<T>): Future<T> {
        return super.submit(ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()))
    }

    override fun <T> submitListenable(task: Callable<T>): ListenableFuture<T> {
        return super.submitListenable(ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()))
    }
}

class ContextAwareCallable<T>(
    private val task: Callable<T>,
    private val context: RequestAttributes?
) : Callable<T> {
    override fun call(): T {
        if (context != null) {
            RequestContextHolder.setRequestAttributes(context)
        }
        return try {
            task.call()
        } finally {
            RequestContextHolder.resetRequestAttributes()
        }
    }
}

 

728x90