1

I have a web application where multiple servlets use a certain amount of identical logic for pre-initialization (setting up logging, session tracking, etc.). What I did was to introduce an intermediary level between javax.servlet.http.HttpServlet and my concrete servlet class:

public abstract class AbstractHttpServlet extends HttpServlet {
    // ... some common things ...
}

and then:

public class MyServlet extends AbstractHttpServlet {
    // ... specialized logic ...
}

One of the things I do in AbstractHttpServlet's default (and only) constructor is to set a few private member variables. In this case it is a UUID, which serves as a session identifier:

public abstract class AbstractHttpServlet extends HttpServlet {
    private UUID sessionUuid;

    public AbstractHttpServlet() {
        super();
        this.sessionUuid = UUID.randomUUID();
        // ... there's more, but snipped for brevity ...
    }

    protected UUID getSessionUuid() {
        return this.sessionUuid;
    }
}

I then use getSessionUuid() in MyServlet to provide for session tracking within the request. This is very useful e.g. in logging, to be able to sift through a large log file and get all entries relating to a single HTTP request. In principle the session identifier could be anything; I just picked using a UUID because it is easy to generate a random one and there's no need to worry about collisions between different servers, seed issues, searching through the log file turning up a match as a portion of a longer string, etc etc.

I don't see any reason why multiple executions should get the same value in the sessionUuid member variable, but in practice, it appears that they do. It's as if the instance of the class is being reused for multiple requests even over a long period of time (seemingly until the server process is restarted).

In my case, class instantiation overhead is minor compared to the useful work done by the class, so ideally I'd like Tomcat to always create new class instances for each request and thus force it to execute the constructor separately each time. Is it possible to perhaps annotate the class to ensure that it is instantiated per request? Answers that don't require server configuration changes are much preferred.

Failing that, is there a way (other than doing so separately in each do*() method such as doGet(), doPost(), etc.) to ensure that some sort of initialization is done per HTTP request which results in execution of a particular servlet?

4

3 回答 3

1

This code is not threadsafe. The servlet container will generally create one instance of the servlet and all requests will use it.This means that the sessionUUID will be shared by all requests and will be continually overwritten.

If you need to keep this value on a per request basis, consider using a ThreadLocal object and putting the UUID in there.

于 2013-07-03T09:38:29.067 回答
1

It's as if the instance of the class is being reused for multiple requests even over a long period of time (seemingly until the server process is restarted).

Yes, that's exactly what will be happening, and what you should expect.

A servlet isn't meant to be a session - it's just meant to be the handler.

If you want to do "something" on each request, no matter what the method, you can override the service method, take whatever action, and then call super.service(). However, you shouldn't change the state of the servlet itself - bear in mind that multiple requests may execute in the same servlet at the same time.

Basically, what you're asking for goes against the design of servlets - you should work with the design rather than against it. You could modify the request itself (using setAttribute) to store some information related to just this request - but I'd probably do that at a higher level than HTTP anyway. (I'd try to make the servlet itself very small, just delegating to non-servlet-aware classes as far as possible, which makes them easier to test.)

于 2013-07-03T09:38:43.787 回答
0

It's as if the instance of the class is being reused for multiple requests even over a long period of time.

There is always one instance of a Servlet class at any given point in time per JVM. Hence instance variables are not thread safe in Servlet. Each request for the Servlet will be processed by a thread. Local variables declared inside the service(),doPost() and doGet() will be thread safe .

  1. Hence you can move your logic to some other class , instantiate it inside the service methods and use it in thread safe fashion.You can even use ThreadLocal objects.

  2. There is a provision to implement the SingleThreadModel ,it is deprecated, it is not only bad but ridiculous to do so.

    Ensures that servlets handle only one request at a time. This interface has no methods.

    If a servlet implements this interface, you are guaranteed that no two threads will execute concurrently in the servlet's service method. The servlet container can make this guarantee by synchronizing access to a single instance of the servlet, or by maintaining a pool of servlet instances and dispatching each new request to a free servlet.

  3. Better to implement a ServletRequestListener and put the logic there.

于 2013-07-03T09:36:06.390 回答