This question already has an answer here:
Using special auto start servlet to initialize on startup and share application data
(1 answer)
Closed 7 years ago.
We have a few war files deployed inside an ear file. Some of the war files have a class that caches static data from our PLM system in singletons. Since some of the classes take several minutes to load we use the load-on-startup in the web.xml to load them ahead of time. This all works fine until we attempt to re-deploy the application on our production servers. (WebLogic 10.3) We get an exception from our PLM API about a dll already being loaded. Our PLM vendor has confirmed that this is a problem and stated that they don't support using the load-on-startup. This is also a huge problem on our development boxes where we have redeploy the app all the time. Most of us, when we're not working on one of the apps that uses a cache, have them commented out. Obviously we can't do that for the production servers. Right now we transfer the ear to the production server, deploy it in the console, wait for it to crash, shut the app server instance down and then start it up again.
We need to find a way around this...
One suggestion was to create a servlet that we can call after the server boots that will load the various caches. While this will work I'm looking for something a bit cleaner. Is there anyway to detect once the server started and then fire off the methods?
Thanks.
We had a similar problem with a third party JDBC driver that loaded a native DLL. When redeploying the app the driver would crash saying the DLL was already loaded. The solution (if one can call it that) was to move the driver from deploy into lib. This way the driver was global to the app server and didn't need to be reloaded when the app was redeployed.
What about using a servlet container lifecycle listener, such as ServletContextListener?
Example on how to use.
EDIT: Sorry, after re-reading your question I don't think this will work. You want something that will load only once per server life, not application life. The ServletContextListener's methods will be called each time the app is deployed, just like a load-on-startup servlet (which it seems you are using). My suggestion will do the exact same thing in a different way.
I would try Chris Nava's suggestion.
EDIT2: It looks like tomcat has some lifecycle listener(s) available to it also. It looks like documentation is sparse, but this potentially would allow you to do something on server startup specifically only once.
EDIT3: Yes, a tomcat lifecycle listener is the way to go. This link explains pretty well how to set one up. Should be fairly straight forward. If you ignore the part about adding the Transaction to tomcat, it goes over pretty thoroughly how to add a lifecycle listener.
Related
Even if we enable "deploy on save" with our IDE, we still need to wait some time to propagate changes. This can be annoying espacially when we deploy small changes.
So, is it possible to run some servlet container in-memory with IDE-compatible deployment to speed up deployment and development time? Or even run whole container in-memory with server dependencies (JSP compilator etc.).
(I know that I can install Tomcat on RAMDisk, but looking for "more native" solution)
According from their site
JRebel is a JVM-plugin that makes it possible for Java developers to instantly see any code change made to an app without redeploying. JRebel lets you see code changes instantly, versioning classes and resources individually and updating one at a time instead of as a lump application redeploy. When developers make a change to any class or resource in their IDE, the change is immediately reflected in the deployed application, skipping the build and redeploy phases and preventing an average of 5.25 work weeks per year in redeploys!
http://zeroturnaround.com/software/jrebel/
The first thing you can do is to set the deployment path to your webapps directory. This way you deploy the application "exploded" without copying the whole app to another deployment directory. Make sure to let the classes be compiled into the WEB-INF/classes directory.
A second, more problematic thing is, the class loader. When the JVM runs in debug mode, some code changes made within methods will be recognized by the class loader and you would see the changes immediately. But some changes, like method signature and structural class changes will not be detected, so a restart of the JVM will be necessary. You can provide a self brewed class loader which will be able to reload anything when the underlying class files changes.
The tomcat container is loaded in memory when you start it. And tomcat loads all the applications available in webapps directory. Later as and when application classes are required are loaded. And application may load some other resources as required.
If you open the task manager on windows or similar thing on other OS, you can see that tomcat java process is always runnning once started. You may also check its current memory footprint . So it is not unloaded and re-loaded on demand.
We have been using tomcat 7.0.19 successfully in embedded mode. However recently due to some fixes in our area of concern we decided to move to tomcat 7.0.32. Most things work as expected with same code and newer version, however the war deployment for some reason has'nt worked well. I have a couple of servlets registered with my tomcat. Facing below 2 issues,
Has something changed from 7.0.19 to 7.0.32 from embedded tomcat behavior. To detail this out let me explain the behavior difference, with 7.0.19, i could deploy my application and when i hit the "host:port/contextpath" it loaded the applications start page (i.e. welcome page, this page is UI centric and does not need a server intervention, so none of my servlets get called). However with 7.0.32 the same url results in my servlet being called.
So to debug the problem, i commented most of my code so that i have a vanilla tomcat implementation, just the very basic stuff, i.e. setting the engine name, default host, setting host properties, adding a connector (nio, with default properties) and deploying a war. No servlets and other things, just to check if the very basic stuff works. To my surprise when i ran this code it still failed with the same problem within my servlet, how did that happen, now that my code is commented it does not register any servlets, still where does it find it from? Does embedded tomcat store some old references, which are not getting cleaned on subsequent runs? I tried changing the port, but that too didn't help.
I am hitting the wall here, not able to understand this wierd behavior, if i figure out #2, only then can i make some progress on #1.
Thanks in advance,
Vikram
Figured out what the problems were.
In reverse order,
2 - This actually was a weird behavior with the vanilla embedded tomcat code too invoking the servlets which never were registered in the first place. The problem here was with eclipse, for some reason it picked up the old reference of my class. The moment i ran the same code from outside of eclipse i.e. via command prompt, things were back to normal.
1 - This problem was related to web deployment, in my code i was additionally setting my classloader into WebappLoader and eventually adding my application jars into it. This for whatever reasons worked fine with 7.0.19, however did not with 7.0.32, the moment i externalized all my jars to be loaded during application startup via classpath this problem too was resolved.
Thanks,
Vicky
I am currently using tomcat 6 as my Web Server. I have a very small application which should not take long to deploy on server, but my tomcat is taking too long start.
It is taking most of its time in following step.
INFO: Starting Servlet Engine: Apache Tomcat/6.0.16
I don't know why it is taking much time. Same is the case with stopping the server. I tried almost everything I know. I also tried to delete server from the workspace and started from scratch. I don't know what is the problem.
You can find out which library consumes the time. When the server is being started in a debug mode, pause its thread several times and examine stacktraces. There may be possibly some library that populates its Spring application context, weaves advised objects, initializes file storage, whatever. If so, you will see it from stacktraces.
Have you removed all the default web applications that comes with the tomcat installation ?
Even though your webapp is a small one, there might be other applications that are taking time to be installed. You can check this from the server log files with the name catalina___.log files.
I know this post is old, even i wanted to share few check points on this because these are irrespective of tomcat version...
I was facing the same issue and i followed below steps and now my server is starting with in 130 ms.
First verify the console if you are using any IDE, there you can find time in milliseconds for each application. So you will come to know which one is taking long time.
To make sure, your finding is correct just remove that app from 'webapps' folder and start tomcat again.
Remove the default applications which you don't need. Usually we only use tomcat manager, so just keep manager app and remove other applications from 'webapps' folder
Make sure 'temp' folder is empty
Clean up the older log files. And don't write your application log files in server folder.
Start the server first and deploy the file later. So that you don't face timeout error.
This is what i tried any succeed.
Possibly this is due to a lack of availability of random entropy, which Tomcat requires.
See https://cwiki.apache.org/confluence/display/TOMCAT/HowTo+FasterStartUp#HowToFasterStartUp-EntropySource
and
Slow startup on Tomcat 7.0.57 because of SecureRandom
(Edit: first link updated)
I guess you have placed all your libraries (JARs) in the WEB-INF/lib folder. Instead move those to a separate directory and refer the directory or JARs using shared.loader in the catalina.properties
We just discovered that every time we restart JBoss, all of our Java Web Start clients redownload all of their jars, instead of reusing the cached jars, even if our application has not changed.
From what I've seen on the web, Java Web Start does an HTTP HEAD to decide whether or not to download a jar. So I ran HTTP HEAD on all jars in our application, and discovered that after restarting JBoss, the modified time of all the jars has changed!
Why is this, and how can I fix it? The jars inside of my application archives have not changed at all. As near as I can tell, JBoss uses the time of startup or time of deploy as the modified time. This is going to completely short-circuit Java Web Start's ability to use cached jars from previous runs, if I understand correctly.
We use JBoss 6, if that's an issue. Previously we used JBoss 4. I want to check to see if we had the problem under JBoss 4, but we now have so many dependencies on the newer JBoss that it is going to take some work to make that test happen.
Try deploying your application as an exploded web application instead of a WAR file.
That would prevent JBoss having to decompress the application and potentially mess up the modification dates.
You'll have to handle updates to your app in a way that preserves modification dates, e.g., rsync, but that might be easier than downgrading or patching JBoss.
It looks like VFSUtils isn't maintaining the lastModifiedDate of the file when it mounts the filesystem to the tmp directory on server startup. You could patch the copy methods in that class to try to set the timestamp of the new file based on the values from the physical file.
As a response to the comment by chubbard: the problem does not occur with Tomcat (tomcat 7.0.21 to be precise).
There is an issue (https://issues.jboss.org/browse/JBVFS-177) created about the VFSUtils.unzip() which does not preserve timestamps while deploying (still applicable to JBoss 6.1).
As the issue is related to the unzip method the solution of blahdiblah may indeed works.
Another way would be to use Java Web Start with a version based (Modification of the jnlp with versionEnabled and creation of a version.xml).
I'm using jboss server and having all my classes inside a jar file.
Now if I change any of the java files, I need to replace the class file in the jar and have to restart the server.
Is there any way to dynamically load the newly created class file without the server restart?
Thanks in advance.
I've had great success with JRebel (http://www.zeroturnaround.com/jrebel/). This is a very good product that enables seamless class reloading for the vast majority of modifications you can make to a Java class. There is no restarting of the app sever or even the application required, classes simply reload behind the scenes.
It comes with a free 30 day trial so you can see if it works for you.
(Disclaimer: I'm in no way connected to Zero Turnaround)
It appears that you have to trick the server into reloading your application by modifying web.xml -- meaning you can open web.xml in an editor enter a space then delete and save the file or change the modification date on the file with a utility.
JBoss doesn't seem to have a handy feature like Tomcat's reloadable="true" flag in Tomcat's Server.xml file.
there are a number of solutions, none of them particularly clean or easy.
As stated, changing the web.xml will cause the context to reload and hence refresh the source code and this can be done without restarting the server. This works because "WEB-INF/web.xml" is configured as WatchedResource in the TOMCAT/conf/Context.xml file. That is every context inherits this setting and automatically watches this file. You can remove this behaviour but you can also provide WatchedResource values in your own web.xml to watch additional files. While I don't recommend it, you could add all of your class files to this and the context would reload when you change one file.
A better solution relies on the fact that a Class can be reloaded when you discard the ClassLoader that loaded the Class. Therefore if you manage your hot swappable code in your own ClassLoader then you can refresh your code without restarting the context if you refresh the ClassLoader. Easier said than done, unfortunately but it may get you started.