I have an Initializer class that implements the ServletContextListener interface. In its contextInitialized() method, I initialize some global classes that have to be destroyed, otherwise the servlet cannot be unloaded.
However, when the servlet's init() method throws a ServletException, the contextDestroyed() method never gets called --> resources are not release --> servlet does not get unloaded by Tomcat (it remains in "running" state even though its init method never finished).
My question is this - how do I cleanup the resources in this case?
Bonus: why does the servlet even get to "running" state? I understand from the documentation that it's not supposed to be running unless the init() method finishes successfully.
Edit - I think this is because each status line displayed in Tomcat Manager represents an entire war, and not a servlet. A war may contain several servlets, with some succeeding to start and others not. The Initializer is called when the container starts, and its destroy is called only when the entire container is dropped. This leads to a related question - is there a similar built-in way to monitor the state of individual servlets?
(I'm aware I can write custom code to monitor the servlet, either via JMX, or not, but that's out of the scope of
this question).
As far as I can tell there's absolutely no way to do so without an external request. ServletContextListener gives you the correct signal (when all servlets have been initialized - successfully or not), but you can't enumerate all servlets in the context to test their status because the relevant ServletContext methods were deprecated and now return an empty enumerator.
In short, the only way to do this is via a nonstandard API; in particular, it's almost trivial to do this with Tomcat's JMX API, which is the course I'd recommend.
In real world the init() should never fail. If it fails, then it is a programming error which the developer is supposed to fix. The appserver webcontainer has nothing to do with it. The servlet will simply be kept unavailable.
What container are you running?
Tomcat for example does support JMX. You can always write your own JMX-beans.
Related
I have a ServletContextListener which performs some database management functions when my Java EE application starts. This runs in my application before JPA and other pieces of the application are started/loaded. If the database maintenance fails I am logging the errors. If the database maintenance fails the application will not function properly and I would like to halt the application.
How can I gracefully and correctly stop the application from ServletContextListener.contextInitialized?
Solution given by Viven below is close but not quite. When I throw a RuntimeException Glassfish is left in an inconsistent state where its admin console is not accessible but some process is still running and keeping port 3700 (IIOP?) open which then prevents a restart.
In your listener, catch any exceptions and use servlet context attributes to store flags or other useful information about the error. You should probably also log something to indicate that the app is non-functional.
At this point, your options may be dictated by the architecture of your app. If all requests are handled by a single controller/dispatcher servlet, it might make sense to have its init method check the context attributes and throw an UnavailableException. Just be aware that the exception only applies to the specific servlet throwing it. This makes the approach less manageable if your app contains many servlets or allows direct access to other resources.
Another option would be to create a filter that intercepts every request, checks the context attributes and then throws an exception. Other variations are certainly possible.
If your ServletContextListener throws an exception, the webapp won't load correctly and the application server may block all subsequent request (and respond with a 500 error).
It isn't exactly preventing the application to start, nor stopping the application, but it prevents any further usage of the app and could be useful in your case.
After proper verification in the spec, this behaviour isn't mandatory in the specification. The server may (not must) return 500 errors. This solution has to be used carefully, therefore.
See this Answer for a quote from the Servlet spec.
This link says that earlier versions of Tomcat (before 7.0.54) "renews its threads" thru ThreadPoolExecutor.run().
Why doesn't the init() method of contained Servlets seem to get called again?
A Servlet is initialized only once, either at web application startup or upon first use.
The same instance will then be used to serve all incoming requests, if necessary even multiple requests at the same time (unless you use the deprecated option to synchronize access, but even then there will be just a single instance, and a queue of requests for it).
I'm checking a Java Servlet tutorial, but I miss the information of when exactly the servlet is destroyed by the server?
and what if I want to destroy manually an unused Servlet to conserve a memory for other tasks!
Because as I know every server has its limit in memory and hosting unused servlets is wasting of resources and application quality,
Thank you to clarify this point because the application performance is one of the most important issue to care about during the development process!
There is only one instance of the Servlet on each node in multi-clustered environment or you can say there is only one instance of each Servlet on each JVM machine.
Servlet is initialized on application startup or at the first time when the servlet is invoked.
when exactly the servlet is destroyed by the server?
All the Servlet instances are destroyed when server is shutting down or on application disposal.
I want to destroy manually an unused Servlet to conserve a memory for other tasks!
You can't destroy the Servlet manually and Servlet is just like worker not for data container. In most of the cases Servlet doesn't contain any instance members to avoid multi-threading issues.
The Servlet specification does not say when a servlet must be shut down and destroyed, other than that it must be done before the container completes a normal shutdown. A container is otherwise permitted to remove an idle instance from service at its own discretion, as long as it is prepared to fire up a new instance later if one is needed.
The specification does not define a mechanism for forcing a servlet instance to be unloaded. It having been unloaded, reclaiming its resources (mostly memory) is the job of the garbage collector, and when that happens is difficult to influence.
Overall, these are exactly the kind of details that you choose Java technology to avoid worrying about. If you insist on worrying about them anyway then look to the documentation of your chosen servlet container -- if there is a supported way to do what you are after then you will find it documented there. Such a thing would be container-specific.
The container decides when to unload the servlet , this sequence releases any resources it is holding so that it can reacquire it if the servlet is loaded again.
the unloading sequence calls a servlet's destroy() method when the servlet is set to be unloaded. The destroy() method houses the clean up actions written by the servlet developer. In practice it should free any resources it has acquired that will not be garbage collected at this step. The destroy() method should also give the servlet a chance to write out its unsaved cached information or any persistent information that should be read during the next call to init().
if we call destroy() on servlet then it doesn't mean that our servlet will be unloaded. You can simply call the destroy method alone without unloading the servlet. However when the container decides to unload the servlet instance from memory then container runs destruction mechanism and destroy method is one of steps of the destruction mechanism.
The web container calls the destroy method when it needs to remove the servlet such as at time of stopping server or undeploying the project.
Servlet is also java program but there is no main method in servlet.Who will take role of main method on servet.
Servlets are designed to run inside a servlet container (eg. Apache Tomcat). Execution of a servlet happens in the following manner: The servlet container calls the GenericServlet.service() method on a servlet which typically calls the appropriate doXxx() method, eg. doGet(), doPost(), etc. The doXxx() method is responsible for interpreting the HTTP request and serving an appropriate response. GenericServlet.service() is roughly analagous to main() in a plain old java class.
Servlet runs inside a container(eg:tomcat). This container perform its work under jvm.
Here container takes "the absence of main method". In simlple java program main method tells
the starting control flow of the execution. But in case of servlet base web application jvm dose not need to search the main method. Servlet container tells jvm about the starting
control flow.
Servlet are deployed on Java application server (servlet container). They are kind of 'passive'. When you write servlet, your servlet code is called by the container whenever there's request or need. So you don't see 'main' in your servlet (the whole thing is not started from servlet), which is inside application server (you could imagine the startup of application server starts from some kind of main).
If you're looking for an area in a servlet to place code that's run on startup (similar to main()), take a look at implementing the ServletContextListener interface.
Its two methods are called on application startup and shutdown.
There is no main method in a Java servlet any more than than an ActionListener on a Swing JButton has a main method. What they both do have are methods that you can hook into when a certain event happens (a click on the JButton for example, or an HTTP PUT request on a HttpServlet). And in both cases, you are provided information about the event that triggered the call - the ActionEvent for the JButton and the ServletRequest for a servlet.
Thinking of servlets in terms of event handlers is probably more useful than trying to think of them like a standalone Java application where you are responsible for the entire control flow.
I want to use the Model-View-Controller template while writing my Web App. The problem is, the Model part of the code has already been written in Swing. The Model code also must require the container to call its main method before any interaction with its servlets. So is there a way for me to specify the location of the main method in the Deployment Descriptor so that the container calls the main method and compiles the code, and then, keeps it running for the entire duration the server is running without in any way restarting or recompiling the model class in between.
Try looking into load-on-startup parameter of servlet in Deployment Descriptor (DD). Precisely, it will load that particular servlet on server start-up.
Moreover, you should read about request lifecycle, request/session/application context. And you must look into JSP (or any other popular technology) for creating V of MVC. How URL mapping works.
Main method is basically work as an entry point in our application. Whereas in web application there is no particular entry point. Or if there is you can think of a welcome page. You might also want to look into welcome-file-list parameter of DD.
Cheers.
To run initialization when a web app is loaded, you can either use the servlet's init method or a ServletContextListener. You can call the main method from either of those yourself.