ThreadLocal - using as context information for REST API with spring-boot

给你一囗甜甜゛ 提交于 2019-12-31 05:41:07

问题


I have some spring-boot application (it exposes rest api). The mentioned REST API is secured by spring-security. Everything is fine, however now I need to set context for servicing request. Setting context is about choosing datasource in depends on user context. The key is that RoutingDataSource need to use this context. (This context must be set directly after authenticating request due to other causes, I have also other thread which use RoutingDataSource, but no invoked by request (no user context)).

These things I can do, however my doubts are concerned on thread-safety of context and clearing it. I tried to find answer in docs, but I didn't managed to.

public class CustomContextHolder {

   private static final ThreadLocal<DatabaseType> contextHolder = 
            new ThreadLocal<DatabaseType>();

   public static void setContext(DatabaseType databaseType) {
      contextHolder.set(databaseType);
   }

   public static CustomerType getContext() {
      return (CustomerType) contextHolder.get();
   }

   public static void clearContext() {
      contextHolder.remove();
   }
}

And setting context:

@Component
class AuthorizedRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response, 
                                    FilterChain filterChain) throws ServletException, IOException {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            // here we set context
        }

        filterChain.doFilter(request, response);
    }
}

I can do it. However, because spring-boot is multi-thread and I am using ThreadLocal for hold context I am afraid of thread-safety of this configuration.

When I set this context ? In filter, only after successful authorization of request. So the questions are:

  1. Is it thread-safe? It means: Can I assume that the same thread that executes filter (hence also this thread set context in its own local context) also executes entire request (e.g. calling methods from dao, sending response, executing body of controller) ?

  2. If in case 1. I can assume that one thread works with request from begin to end (begin includes filter after secured request) then when I should call clearContext() ?


回答1:


On your second question: clear thread local in the same filter in which you set it.

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    boolean contextSetViaThreadLocal = false;
    if (authentication != null && authentication.isAuthenticated()) {
        contextSetViaThreadLocal = true;
        // here we set context
    }
    // immediately after the conditional context store
    try {
        filterChain.doFilter(request, response);
    } finally {
        if (contextSetViaThreadLocal) {
            // clear the context
        }
    }



回答2:


  1. If you use only one thread in your program, the answer is yes. There are no reasons run this operations in different threads, because switching threads is overhead. But in your program you or somebody can define async operations (@Async, Thread.start(), events, etc.) in that case there are more then one thread, and your ThreadLocal will handle value only for the first thread.

  2. Yes, but see first paragraph.

I recommend for this task use thread safe cache (for example ConcurrentHashMap) associate with users. It will be simpler for understanding and thread safe. If you want use ThreadLocal you need to clarify and minimize his lifecycle in your application.




回答3:


you should clear context once after request is completed.

try {
    filterChain.doFilter(request, response);
}
finally {
    // remove context here
}



回答4:


it's single threaded unless you purposely initiate child threads. in such case use InheritableThreadLocal to store information.



来源:https://stackoverflow.com/questions/43181576/threadlocal-using-as-context-information-for-rest-api-with-spring-boot

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!