ThreadLocal in Tomcat servlets

I had a problem when exceptions appear in my production system, but I really do not have good information about who causes them. The username is stored as a variable in their tomcat session, access to which I have, for example, in my doPost or doGet , but if I do not pass this information as a parameter for each of my business objects, t have access to the session . For obvious reasons, I would like to bind the username to the registration message so that I have an idea about what is going on.

So my solution is to do something like this

 public class ExceptionUtil { private ExceptionUtil() { } // no instantiation private static final ThreadLocal<String> local = new ThreadLocal<String>(); public static void set(String user) { local.set(user); } public static String get() { return local.get(); } } 

Then in my posts / receives, I can do it

 String username = request.getSession().getAttribute("username"); ExceptionUtil.set(username); 

Then, with my exceptions, I could do it (a far-fetched, bad practice example)

 catch(SQLException e) { logger.error(ExceptionUtil.get() + " did something dumb in sql", e); throw e; } 

The only problem I'm worried about is how Tomcat will manage my threads. What if they save threads? Will they persist? Will ThreadLocal values โ€‹โ€‹be saved? If I saved the entire session in ThreadLocal instead of just String, this would be a serious potential memory leak. It also means that if someone forgot to reinstall (or forget to clear when this is done) the username / session in the stream, which is stored for several requests, there may be outdated data.

Call me cynical, but I do not want to rely on programmers (even, especially on myself!), Not forgetting to do something for the correctness of the program. If I can idiotize my code, I would like to. And that means a better understanding of how Tomcat will use threads.

So the question is in the form of a single sentence:

If I use ThreadLocal in a webapp running on Tomcat (7.0.27), do I run the risk of using Thread for several requests and with it the data from the previous request is saved?

I should note that even if they do not answer the exact question "Tomcat / ThreadLocal shenanigans", I am open to alternative solutions that allow me to elegantly access session variables for logging purposes. I am also open to comments about potential errors of my decision. I have a business problem to solve, and I am not married to any one solution. I just want to know who continues to throw exceptions from my prod system :)

+4
source share
2 answers

Yes, tomcat uses the concept of ThreadPool, which means that threads are reused and therefore, since you suggested "Your Thread Local stores values",

alternatives that I would suggest could be

  • clear threads after you finish somewhere in the view controller

  • Write a query filter and start the filter Clear all and click new values, and assign this to each url pattern on the ur server .

for your approach, instead of storing certain values โ€‹โ€‹in classes, Save the request to the "Local stream", and then use the query to pull values โ€‹โ€‹out of the session, using the homemade util class that accepts the request and then returns the desired value, so you save session in Thread and get the value, but please make sure every time you add a fresh one and clear the request after you finish (use the 2nd option for this).

+2
source

You do not need to reinvent the wheel, the magazine system does it for you.

If logback / log4j is your logical implementation, then context diagnostic context ( MDC ) is definitely your answer. MDC is logically similar to ThreadLocal, but better:

  • MDC processes streams and synchronizes transparency

  • A child thread automatically inherits a copy of its parentโ€™s associated diagnostic context. Thus, even if you use a multi-threaded process to process the request, it is still in order.

Therefore, install MDC in a servlet filter like this to achieve your goal:

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { boolean successfulRegistration = false; HttpServletRequest req = (HttpServletRequest) request; Principal principal = req.getUserPrincipal(); // Please note that we could have also used a cookie to // retrieve the user name if (principal != null) { String username = principal.getName(); successfulRegistration = registerUsername(username); } try { chain.doFilter(request, response); } finally { if (successfulRegistration) { MDC.remove(USER_KEY); } } } private boolean registerUsername(String username) { if (username != null && username.trim().length() > 0) { MDC.put(USER_KEY, username); return true; } return false; } 

Then, in your log configuration, add% X {USER_KEY} to the template layout to use the value set in MDC.

Logback has a built-in filter . MDCInsertingServletFilter can record additional information, such as remoteHost / requestUrl, etc., very useful information for logging.

Check the journal document at MDC http://logback.qos.ch/manual/mdc.html

0
source

All Articles