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.
Related
Is there a way for a Servlet to do a hot re-deploy the webapp it is part of?
I know that I can configure Tomcat to do a hot re-deploy on changes to web.xml but I can't find any way to do the same from java code. I don't want tomcat to having to watch the web.xml for changes all the time.
I believe it can be done using JMX.
The Tomcat Manager is a web application that can be used interactively (via HTML GUI) or programmatically (via URL-based API) to deploy and manage web applications.
There is the link - http://tomcat.apache.org/tomcat-7.0-doc/deployer-howto.html
A Servlet has a life cycle that depends on the container. This is explained here
http://docs.oracle.com/javaee/5/tutorial/doc/bnafi.html
What this means is from the web.xml the container figures out a match depending on a request and if there is such a class that exists it loads it as a classloader resource. Once this has happened the instance stays loaded till the container is shutdown so replacing .class files wont actually achieve the "hot-deploy" unless you set the reloadable flag in the tomcat's context.xml
http://tomcat.apache.org/tomcat-5.5-doc/config/context.html#Common_Attributes
In any case, Tomcat or not, once a resource has been loaded by a ClassLoader changing the .class files wont exactly change the behaviour of the running jvm which you would probably know. So even deleting the class files from the file system also wont affect the running java process in ordinary situations.
However it may be possible that a servlet can start a background task that does a basic file copy of the new .class files you want to 'hot deploy' (if the context attribute 'reloadable' is true). This then forces these classes to be reloaded and so you achieve a hot deploy. So although this is out of the scope of what a servlet is designed to achieve the answer is yes.
Hope this helps.
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.
I have a java application. All I have with me is a set on class files. Iwant to replace one class file with a new one. Replacing the old class file with the new one and restrting tomcat is not reflecting the changes. How can I do this? I know its not a recommended way, but all I have is just one new class file.
I've done this the way you describe before, and Tomcat reflected the changes just fine after restart.
Perhaps your application's files are in multiple locations, and you aren't replacing the class file in the correct deployment? Make sure if Tomcat is auto-expanding the WAR that you are replacing it in the expanded folder of files. If you app is deployed somewhere besides webapps, double-check where your <Context> is pointing to for its doc base.
You can configure Tomcat and make your webapp "reloadable". To do so, add reloadable=true to the <Context> element of your webapp.
Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. You can use the Manager web application, however, to trigger reloads of deployed applications on demand.
Why do we need to restart a tomcat server whenever a class file is changed, is there no other way?
You can configure Tomcat and make your webapp "reloadable". To do so, add reloadable=true to the <Context> element of your webapp. About the reloadable attribute, the documentation says:
Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. This feature is very useful during application development, but it requires significant runtime overhead and is not recommended for use on deployed production applications. That's why the default setting for this attribute is false. You can use the Manager web application, however, to trigger reloads of deployed applications on demand.
There certainly is! Start Tomcat in development mode, then each webapp will restart itself upon being redeployed.
From the Tomcat docs:
The servlet which implements Jasper is configured using init parameters in your global $CATALINA_BASE/conf/web.xml.
...
development - Is Jasper used in development mode (will check for JSP modification on every access)? true or false, default true.
There are settings you can change to adjust what exactly Tomcat will look for to check for updates. I usually deploy individual class files to their appropriate directory under WEB-INF/classes and then
touch WEB-INF/web.xml
to kick-start a restart of the application; I think web.xml is one of the files Tomcat checks by default.
On a more general note, the reason you have to do this is because in Java, when a classloader loads a class, it cannot unload it. What Tomcat has to do is use a new classloader and reload all the classes it needs.
Check out JRebel.
If you develop, your IDE should be able to do this transparently on a suitable server. E.g. the Dynamic Web Project in Eclipse knows how to talk to Tomcat.
If you deploy, then create WAR-files and deploy those. Tomcat knows how to redeploy a WAR-file.
If you're using WAR files to deploy, you can set autoDeploy=true in the Tomcat config, which causes Tomcat to watch the web application root ("webapps" by default) for new or changed WAR files. If such a file is found, it is automatically deployed.
As Pascal Thivent said, though, you can use the Tomcat Manager application (/manager/html) to start, stop, deploy, and undeploy specific applications. If the files you're changing are in a specific application, this is a good way to get Tomcat to recognize the changes.
Besides setting autoDeploy=true in server.conf , you also should be careful not to put any classes in the shared classloader. Classes which are loaded by the shared class loader cannot be re-loaded.
Your question doesn't actually say whether you are concerned about a production downtime (i.e. reduce it by reloading the classes) or you want non-stop development. So I will try to clarify using the following points:
1) using <Context reloadable=true... in your catalina.home/conf directory you can make sure that your webapp reloads when a any class changes. You can add the resource change watchlist in <WatchedResources> element.
2) But this will reload the context, re-initialise the classloader, empty it's cache, and everything will be as if the webapplication has just started.
This approach will still leave your server unusable, because you have reloaded the Servlet's context. The true "Reload" is
1) You swap the byte code of the class, with some restrictions
2) JVM will return that class when "loadClass()" is called for that classloader.
This is java instrumentation. You can write your own agent which can hook into your JVM either at the beginning or in flight. However, you cannot define new method, and change static variables. These are JVM native restrictions (for Oracle HotSpot JVM, that I know of). You can use a different JVM e.g. DCEVM which doesn't have such restriction. So it's up to you how you want to handle your problem. If you know what you are doing (!), you can get away with replacing classes one-by-one. And you can even define a "Brand New Class", reference that class object/method in an existing/loaded class and instrument it to to pick up changes.
I hope this helps. All the answers here are what you need to make your decision.
I used to run Tomcat separately on my machine. I had an Ant script that would rebuild my project, deploy it locally, and restart Tomcat. That all worked ok, but I wasn't able to debug the web app inside Eclipse.
So I learned how to setup Tomcat inside Eclipse and got my web app running. Now the problem is that I don't understand fully how to manage it this way. Eclipse is set to automatically build my project on changes, but those changes don't seem to always be reflected in the web app. Sometimes I have to manually build the project and manually "clean" the server for the changes to be reflected.
Are there rules somewhere about how to manage this setup? For instance, if I only change a JSP then will it automatically be synchronized? If I change a servlet class, then I need to manually rebuild the project? Are these rules consistent, or should I just manually rebuild and clean every time?
I would really appreciate it if someone could give me the best practice rules or point me to a good resource to learn how to manage this environment.
PS. I am using Eclipse 3.4.1 Java EE package and Tomcat v5.5
You can use Eclipse and Tomcat in the way you mention. First the basics of how to set it up:
In the Servers view setup a new Tomcat server pointing to your TOMCAT_HOME
Make sure your project is an Eclipse "web project". You may need to create a dummy one and copy over some of the files in .settings (look at the wst files).
Deploy your project to Tomcat by right clicking on the server in the Servers view and "Add and Remove Projects..." to add your project to the server.
You can run your server and test it out just like you were running Tomcat outside of Eclipse. If you run the server in Debug mode you can set breakpoints and step through the code.
As for when you will need to restart the server Eclipse is usually pretty good about auto-deploying the changes. You will pretty much never need to restart for changes to jsp pages. If you change a class it will auto-deploy the change (usually) if you change the body of a method. If you change the signature of a class (add or remove a method or change args for it) you will almost always need to restart. Any changes to configuration files (web.xml or similar) will also almost always require a restart.
To restart just click on the "Debug" or "Run" button in the Server view. All your changes will be redeployed into Tomcat.
One thing to watch out for is that in the default configuration your "webapp" directory in TOMCAT_HOME will not be used. Instead it will use a folder under your Eclipse workspace directory (WORKSPACE/.metadata/.plugins/org.eclipse.wst.server.core/tmp0).
Normally you should republish the application to get latest changes, don't forget to synchronize with file system first in case your files modified extrernally.
You can specify that your application is automatically reloaded when modified, look for Auto-reload attribute in server.xml of your server configuration project. When set to true, tomcat will automatically reload your application. It's not always a good idea by the way.
Modified JSP's should work automatically, no need to restart the applciation.
If you change the structure of a class that has already been loaded and used (add/remove members, change method signature etc.) your code changes will not be reflected. This is not an eclipse issue but a JVM issue. If you make simple code changes, like logic changes inside an existing method, your changes will take effect after the class is compiled and re-deployed.
Regardless of that, if you change a public constant, you have to rebuild your project(s).
I found two things important to understand:
Eclipse does not automatically realize if files were changed outside of Eclipse. clicking Refresh on a project does that, so does F5. You can also change a setting to refresh automatically, which, however, does not detect changes instantly (my gut feeling says up to 10 secs delay)
Working with servers has the concept of "Publishing" files to Tomcat. This normally happens automatically within a second after any change. Changing many classes can cause many server reloads, which can be a drag if a context reload takes some time (as complex Spring apps certainly do). So I changed a setting to not publish automatically (double-click Server instance)