Disable reuse of ServletRequest instance - java

Is it possible to disable the reuse of the ServletRequest instance for each request? It looks like the instance is reused multiple times (maybe bound per TCP session?)

What you can see in the spec :
3.13 Lifetime of the Request Object
Each request object is valid only within the scope of a servlet’s service method, or
within the scope of a filter’s doFilter method, unless the asynchronous processing
is enabled for the component and the startAsync method is invoked on the request
object. In the case where asynchronous processing occurs, the request object remains
valid until complete is invoked on the AsyncContext. Containers commonly recycle
request objects in order to avoid the performance overhead of request object
creation. The developer must be aware that maintaining references to request objects
for which startAsync has not been called outside the scope described above is not
recommended as it may have indeterminate results.
In case of upgrade, the above is still true
Containers commonly recycle
request objects in order to avoid the performance overhead of request object
creation
It is container-specific.
In this case it is specific to Jetty.

Jetty recycles the org.eclipse.jetty.server.Request object between requests.
This is normal, is within the definition of the Servlet Spec, and many containers do this.
Be careful of your usage of the HttpServletRequest / ServletRequest / Request object outside of the dispatch from the container.
If you are using it from an AsyncContext you should only use it when you are called by the container, not any other point or from any other thread (unless you are 100% certain you are handling the threading properly, and are ready to handle one of the thousands of corner cases with AsyncContext from a non-container thread)

Related

Is HttpSessionListener.sessionCreated() guaranteed to complete before any other thread accesses the new session?

I'm trying to cache values in a ConcurrentHashMap in the Session. In order to avoid race conditions and ensure that my map is created before any threads attempt to use it, I use HttpSessionListener.sessionCreated() to add the map to the Session:
#Override
public void sessionCreated(HttpSessionEvent event) {
event.getSession()
.setAttribute(MY_CACHE_KEY, new ConcurrentHashMap());
}
Is this code guaranteed to complete before any other threads access the session (via request.getSession() for example)?
I looked at the HttpSessionListener JavaDoc and the Servlet 4.0 Spec. and there don't seem to be any guarantees about thread safety.
The Serlvet Spec. references session thread-safety a few times, but none of these references related to session listeners and session creation as I understand them:
7.7.1 Threading Issues
Multiple servlets executing request threads may have active access to the same session object at the same time. The container must ensure that manipulation of internal data structures representing the session attributes
is performed in a thread safe manner. The Developer has the responsibility for thread safe access to the attribute objects themselves. This will protect the attribute collection inside the HttpSession object from concurrent access,
eliminating the opportunity for an application to cause that collection to become corrupted. Unless explicitly stated elsewhere in the specification (for example Section 7.7.1, “Threading Issues” on page 7-67 for session objects), objects vended from the request or response must be assumed to be non thread safe. This includes, but is not limited to the PrintWriter returned from
ServletResponse.getWriter() and the OutputStream returned from ServletResponse.getOutputStream().
11.5 Listener Instances and Threading
The container is required to complete instantiation of the listener classes in a Web application prior to the start of execution of the first request into the application. The container must maintain a reference to each listener instance until the last request is serviced for the Web application.
Attribute changes to ServletContext and HttpSession objects may occur concurrently. The container is not required to synchronize the resulting notifications to attribute listener classes. Listener classes that maintain state are responsible for the integrity of the data and should handle this case explicitly.
It seems obvious that sessionCreated() must complete before threads have access to the session, but "obviously correct code" has been unsafe for multithreading before.
This ambiguity doesn't exist for ServletContextLister.contextInitialized() since it is guaranteed to complete before Servlet initialization and Servlet.init() is guaranteed to be single-threaded and occur before any requests.
I've tested Tomcat at least and it does ensure that sessionCreated() completes before request.getSession() returns. I tested by putting a breakpoint in sessionCreated() and sending a request which called request.getSession(). This request didn't complete until I continued from the breakpoint. However, one Servlet container implementation's behavior isn't really conclusive proof that all containers/servers behave this way.

HttpServletRequest reuse

It seems that some servlet containers reuse HttpServletRequest (or more generally, ServletRequest) instances between requests.
Question:
Can someone point to the servlet spec where this behavior (or the validity rules for references to such instances) is defined?
It is not defined in the Servlet API. It is an implementation detail.
In 3.11 for request objects (and 5.6 for response objects)
Each request object is valid only within the scope of a servlet’s
service method, or within the scope of a filter’s doFilter method,
unless the asynchronous processing is enabled for the component and
the startAsync method is invoked on the request object. In the case
where asynchronous processing occurs, the request object remains valid
until complete is invoked on the AsyncContext. Containers commonly
recycle request objects in order to avoid the performance overhead of
request object creation. The developer must be aware that maintaining
references to request objects for which startAsync has not been called
outside the scope described above is not recommended as it may have
indeterminate results
It is not required, but commonly used.
What is in the spec (see chapter 2.3.3) is the single threaded model. One request, one thread. This allows the request to be cleaned up and reused.

Accessing HttpSession outside of the originally receiving thread

I'm using Spring 3. When controller gets requests it passes control to method someMethod() annotated with #Async in Service bean and then returns. When I access in someMethod() HttpSession object I receive this exception
java.lang.IllegalStateException: No thread-bound request found: Are you
referring to request attributes outside of an actual web request, or
processing a request outside of the originally receiving thread? If you are
actually operating within a web request and still receive this message, your
code is probably running outside of DispatcherServlet/DispatcherPortlet: In
this case, use RequestContextListener or
RequestContextFilter to expose the current request.
How can I resolve this?
The HttpSession object itself can be used in multiple threads (but is not thread-safe and therefore must be synchronized). However Spring is doing some extra magic e.g. when you have session-scoped beans. Namely it uses ThreadLocal underneath to bind current session with thread.
I don't know what is your exact scenario, but apparently Spring tries to retrieve HttpSession from this ThreadLocal while you are in another thread - which obviously fails.
The solution is simple - extract session attributes you need in #Async method and pass them directly. This is by the way much better design - avoid passing HttpSession object around because it makes testing harder and your code is much less likely to be reused in the future.

What is the lifecycle of a HttpServlet?

Basically, how long is an instance of a servlet around for? I am kind of guessing it is session scope. However, I suppose it could have some sort of timeout or garbage collection to remove old instances.
a servlet is created when the application starts (it is deployed on the servlet container) or when it is first accessed (depending on the load-on-startup setting)
when the servlet is instantiated, the init() method of the servlet is called
then the servlet (its one and only instance) handles all requests (its service() method being called by multiple threads). That's why it is not advisable to have any synchronization in it, and you should avoid instance variables of the servlet
when the application is undeployed (the servlet container stops), the destroy() method is called.
The lifecycle is well defined, and exposed through lifecycle methods exposed in init, service, and destroy methods of the Servlet.
And, despite what else is being said here, this is all you can count on from the specification. Basically, you get those three methods and a guarantee that Servlets are not thread safe. That a single servlet MAY be simultaneously accessed by one or more requests.
There is nothing in the specification that limits a servlet to one instance the container, if a container decides to, it can get a request, create a servlet, call it's init, then service, then destroy methods, and set it free for garbage collection.
Individual containers have potentially different implementations.
Most containers do create a single instance. But the specification does not guarantee that, so you shouldn't rely on it.
Also, consider something like Google App Engine. GAE is VERY aggressive is continually expiring and shutting down entire web apps that receive no traffic. If you have a lightly traveled site, you can very well expect the entire app to start up, init all of its services, init any load-on-startup servlets, execute the request, and then shut everything down. So, on GAE it's imperative that you have a very fast application startup in order to maintain any semblance of performance.
So, simply, what you can count on is what the specification says. Individual containers may offer different run time experiences.
A Servlet lives as long as the application does.
A servlet is not bound to a session, it is a service object that is instantiated by the container when needed, and typically is kept alive for the full life of the webapp. It typically responds to requests from several clients (and sessions), even concurrent requests.
That's precisely why your servlet code must be thread safe, and you never store in a servlet field some data associated to a request or a session.
A servlet life cycle can be defined as the entire process from its creation till the destruction. The following are the paths followed by a servlet
The servlet is initialized by calling the init () method.
The servlet calls service() method to process a client's request.
The servlet is terminated by calling the destroy() method.
Finally, servlet is garbage collected by the garbage collector of the
JVM.
More here ..
http://www.dzone.com/links/r/java_ee_servlets_life_cycle.html
when i remember correctly servlets live as Singletons in the Servlet Container (e.g. Tomcat). Im not sure if the first instantiation is lazy, meaning that the Servlet gets constructed only if needed, but im guessing one could check this in the corresponding Servlet Container's Classloader sources.
The Servlet's lifecycle ends and it's destroy() method gets called when the Servlet Container is shut down.
You can check this easily by setting up breakpoints or logging in the appropriate init() and destroy() methods and Constructor then just check when the code gets executed in your debugger/logfile.
hope that helped.
References:
Tomcat's Classloader howto
The servlet (its one and only instance) will handle n number of request in the fashion of separate single thread for every client ie where CGI limitation is overcomed
A servlet object lives in heap of serverside machine as long as application is undeployed or servletConatiner is shutdown the servlet object will not die.
Technically : servletcontainer holds servletobject and servletobject holds servletConfig object
Servletcontainer can only call the 3 methods of its life cycle 1)init() 2)service() 3)destroy()
Actually the Servlet may be destroyed and recreated at any time ! So the other answers kinda describe the whole lifecycle but miss this important detail. From the servlet specification:
The servlet container is not required to keep a servlet loaded for any particular
period of time. A servlet instance may be kept active in a servlet container for a
period of milliseconds, for the lifetime of the servlet container (which could be a
number of days, months, or years), or any amount of time in between.
[...]
Once the destroy method is called on a servlet instance, the container may not route
other requests to that instance of the servlet. If the container needs to enable the
servlet again, it must do so with a new instance of the servlet’s class.
The lifecycle of a typical servlet running on Tomcat might look something like this:
1.Tomcat receives a request from a client through one of its connectors.
2.Tomcat maps this request to the appropriate Engine for processing. These Engines are contained within other elements, such as Hosts and Servers, which limit the scope of Tomcat's search for the correct Engine.
3.Once the request has been mapped to the appropriate servlet, Tomcat checks to see if that servlet class has been loaded. If it has not, Tomcat compiles the servlet into Java bytecode, which is executable by the JVM, and creates an instance of the servlet.
4.Tomcat initializes the servlet by calling its init method. The servlet includes code that is able to read Tomcat configuration files and act accordingly, as well as declare any resources it might need, so that Tomcat can create them in an orderly, managed fashion.
5.Once the servlet has been initialized, Tomcat can call the servlet's service method to process the request, which will be returned as a response.
6.During the servlet's lifecycle, Tomcat and the servlet can communicate through the use of listener classes, which monitor the servlet for a variety of state changes. Tomcat can retrieve and store these state changes in a variety of ways, and allow other servlets access to them, allowing state to be maintained and accessed by various components of a given context across the span of a single or multiple user sessions. An example of this functionality in action is an e-commerce application that remembers what the user has added to their cart and is able to pass this data to a checkout process.
7.Tomcat calls the servlet's destroy method to smoothly remove the servlet. This action is triggered either by a state change that is being listened for, or by an external command delivered to Tomcat to undeploy the servlet's Context or shut down the server.
Reference:
https://www.mulesoft.com/tcat/tomcat-servlet
life cycle of servlet >
1) load the class.
2) instantiate the servlet.
3) servlet container construct the servlet config interface.
4) container call the init() and pass the servlet config object.
5) httpRequest and httpResponse object created.
6) container call the service() and pass the httpRequest and httpResponse object as argument.
7) process the service method.and if have any other request then follow the step 4 again.
8) other wise container call the distroy().
The servlet's container is attached to a web server that listens for HTTP or HTTPS requests on a certain port number (port 8080 is usually used during development and port 80 in production). When a client (user with a web browser) sends an HTTP request, the servlet container creates new HttpServletRequest and HttpServletResponse objects (for every new request) and passes them through any defined Filter chain and, eventually, the Servlet instance.
In the case of filters, the doFilter() method is invoked. When its code calls chain.doFilter(request, response), the request and response continue on to the next filter, or hit the servlet if there are no remaining filters.
In the case of servlets, the service() method is invoked(by multiple threads for different request). By default, this method determines which one of the doXxx() methods to invoke based off of request.getMethod(). If the determined method is absent from the servlet, then an HTTP 405 error is returned in the response.
The request object provides access to all of the information about the HTTP request, such as its headers and body. The response object provides the ability to control and send the HTTP response the way you want by, for instance, allowing you to set the headers and the body (usually with generated HTML content from a JSP file). When the HTTP response is committed and finished, both the request and response objects are recycled and made for reuse.

Servlets, filters and threads in Tomcat

In the Tomcat container, do all the filters associated to a servlet and the servlet itself use the same thread? i.e, will doFilter() be run in the same thread as a servlet's service() method? Thanks in advance.
I suspect the question is more: Can I use ThreadLocal objects to pass data between filters and to servlets? In which case the answer is, absolutely. App servers do this themselves to track security, transaction, connection and other request information.
Just make sure you clean out your ThreadLocal in a finally block in the same code that sets the ThreadLocal.
As already noted by other, the servlets themselves may or may not be synchronized, but that is orthogonal to the concept of thread state; i.e. how many threads execute against object foo vs. can I put state in the thread and have it seen by object foo. The answer to the second question is always yes.
The only time the answer would be 'no' is if you made use of any asynchronous communication:
Dispatched the call via AsyncContext
mixed in EJBs and started making use of #Asynchronous or the TimerService
These involve the app server starting new threads not associated with the original request thread so any ThreadLocal state will not travel with the new thread. It is also why those APIs do not allow security and transaction context of the caller to be propagated to the method invoked as the caller and method are in different threads.
Advanced note, InheritableThreadLocal typically does not work as async calls are typically done by the server against a thread pool rather than creating child threads of the caller thread.
Yes, each request is performed in a single thread, including all filters and the target servlet.
Yeah, each request is performed within a single servlet instance.Servlet container receives each request and start a new thread which contains the HttpServletRequest and HttpServletResponse. This thread process the request in the service method of the servlet instance and will be destroyed as soon as the service method completes.

Categories