Bootstrapping is the process by which you load a very small and very simple pure java program with no dependencies that, in turn, loads, configures, and runs more complex programs with varying dependencies. Bootstrapping lets you run your container without polluting the system classpath. This allows you to run your deployed applications with the unpolluted system classpath as its parent. You’ve achieved classloader isolation.
When would you want to bootstrap? Any time you want an unpolluted system classpath, which I’m finding is often convenient.
Let’s say you want to write some kind of middleware product, a container of some sort that deploys other applications within it. You will run into classloading issues. The dependencies that your container has (say, Spring 2.0.6) may not be what your deployed application requires (maybe, Spring 1.2.6). You will find that you cannot have commons-logging in both applications (container and child). There are many ways to encounter java.lang.LinkageErrors. It’s very easy to cross the streams when running in a mutli-app environment.
What you want to do is load your container and deployed apps in splendid isolation from each other. How do you do that? Bootstrapping!
Here’s how you bootstrap…
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class Bootstrap {
public static void main(String[] args) throws Exception {
/*
Assume your application has a "home" directory
with /classes and /lib beneath it, where you can put
loose files and jars.
Thus,
/usr/local/src/APP
/usr/local/src/APP/classes
/usr/local/src/APP/lib
*/
String HOME = "/usr/local/src/YOURAPP";
String CLASSES = HOME + "/classes";
String LIB = HOME + "/lib";
// add the classes dir and each jar in lib to a List of URLs.
List urls = new ArrayList ();
urls.add(new File(CLASSES).toURL());
for (File f : new File(LIB).listFiles()) {
urls.add(f.toURL());
}
// feed your URLs to a URLClassLoader!
ClassLoader classloader =
new URLClassLoader(
urls.toArray(new URL[0]),
ClassLoader.getSystemClassLoader().getParent());
// relative to that classloader, find the main class
// you want to bootstrap, which is the first cmd line arg
Class mainClass = classloader.loadClass(args[0]);
Method main = mainClass.getMethod("main",
new Class[]{args.getClass()});
// well-behaved Java packages work relative to the
// context classloader. Others don't (like commons-logging)
Thread.currentThread().setContextClassLoader(classloader);
// you want to prune the first arg because its your main class.
// you want to pass the remaining args as the "real" args to your main
String[] nextArgs = new String[args.length - 1];
System.arraycopy(args, 1, nextArgs, 0, nextArgs.length);
main.invoke(null, new Object[] { nextArgs });
}
}
You can try this code out for yourself. Cut & paste the bootstrap code above into your favorite IDE, put that single Bootstrap.class onto your classpath, and run it like so:
java -cp . Bootstrap sample.HelloWorldMain Hello!
.
Click here to download the sample /usr/local/src/YOURAPP application.
Tip for Windows users, you can make the path c:\usr\local\src\YOURAPP it’ll work.
I'm Mark Turansky, I'm the founder of
#1 by Dan on January 18, 2008 - 11:10 pm
Quote
You forgot to set the context classloader before the main invocation, NEWB!
#2 by Mark Turansky on January 20, 2008 - 3:04 am
Quote
It’s funny ’cause it’s true! Nice catch, Dan.
The above code works just fine except that you *will* want to add this single line before you reflectively invoke the
mainmethod:Thread.currentThread().setContextClassLoader(classloader);
Lots of well-written Java software use the thread’s context classloader to resolve classes and classpath-based resources. This is a very effective way to avoid crossing the streams between classloaders.
Other software packages don’t always play as nicely with classloaders, even when you set the context classloader. Bootstrapping helps in this case, but well-behaved software would be even better.
FYI: Dan is one hell of a smart developer, groks all the bootstrapping and classloading challenges you’re likely to face, and — best of all — works for me on whatever madness our bosses let us pursue
#3 by Casper on January 22, 2008 - 5:04 pm
Quote
I used a similar approach to make a JSR-296 app restartable (for changing language), but it did not seem to work in a Web Start scenario so I gave up on that. Will this work in such an environment?
#4 by Mark Turansky on January 22, 2008 - 5:10 pm
Quote
Casper,
Thanks for the inquiry. Short answer, I don’t know.
I’m unfamiliar with Web Start. I don’t know how to bootstrap in that scenario.
I work mostly with web applications and back-end systems (messaging/integration). I know we can boostrap Jetty as part of our system as well as all the disparate components deployed around the network.
I hope the code I posted can help you figure out how to bootstrap a Web Start app. If you figure it out, please post the solution online! I’d love to see it.
Mark
#5 by Casper on January 22, 2008 - 9:13 pm
Quote
Hello Mark,
I gave it another shot, motivated by this blog entry. It poses a few problems though, the JNLPClassLoader is package private in com.sun.jnlp namespace and hence completely inaccessable. But by casting to an URLClassLoader, the remote CLASSES (in fact, works for non-jws execution too) can be fetched and passed along to the new ClassLoader instance.
URLClassLoader jnlpClassLoader = (URLClassLoader)this.getClass().getClassLoader();
ClassLoader bootstrapClassLoader = new URLClassLoader( jnlpClassLoader.getURLs());
…and that works, but causes issues with the security manager later on. Another approach:
URLClassLoader jnlpClassLoader = (URLClassLoader)this.getClass().getClassLoader();
URLClassLoader classLoader = URLClassLoader.newInstance( jnlpClassLoader .getURLs(), jnlpClassLoader);
…seems to get slightly further, but causing errors on the EDT. I feel I’m getting close, but I am not sure how to attempt this off the EDT or possibly simply empty the EDT first. Now I remember why I am no fan of classloaders!
/Casper
Pingback: » Terracotta Server as a Message Bus
#6 by skanga on January 29, 2008 - 2:32 am
Quote
I always hate seeing hard coded unix filename conventions in Java code. Using File.separatorChar is a much better idea.
#7 by Mark Turansky on January 29, 2008 - 5:16 am
Quote
This was just an example program to learn from. I presume that people reading this HOW TO would understand to set their HOME variable from the outside. Maybe they’d use a command line argument to their bootstrapper, maybe a -D system property. Either way, you could then use an environment-specific path that’s appropriate for your deployment without string concatentation or File.separatorChar.
#8 by Christian Bohm on March 7, 2008 - 2:16 pm
Quote
Hi guys! Nice trick.
My question is…. will this work in a swing application?
I mean… I have a swing application that calls to another swing application using the main method.
I want the caller application be in a separated classloader than the invoked one.
The problem is that the current Thread is the swing thread so if I modify swing thread’s classloader, it will be modified for both applications. Right?
Pingback: » No one should work alone. Ever.
#9 by scm on March 31, 2008 - 8:52 pm
Quote
Hi, what do you mean by an “unpolluted system classpath”?
#10 by Mark Turansky on April 1, 2008 - 10:04 am
Quote
@scm,
Whenever you start the JVM with a “-cp” argument, all those jars and libs on your classpath are on the system classpath. Any code you run in that JVM will have those libs in their classloader.
When you’re writing middleware or some kind of container, you’ll run into a problem where your container might need one version of a library but the application you want to deploy has the same library but a different version. You need bootstrapping to reconcile this. The code example I gave shows how you would set the system classloader (which is empty, because you’re bootstrapping) as the parent classloader to the application you want to deploy. This leaves the application free of your container’s dependencies.
I hope that helps. All this stuff becomes a lot clearer when you write a server that deploys other apps within it. Most people probably never do that, but we did when we wrote our message bus (http://blog.markturansky.com/archives/26)
Mark
#11 by Brad on April 30, 2008 - 11:42 am
Quote
Hi Mark:
How could we modify the above bootstrap program to load multiple apps? Should we run each app within a seperate thread?
Great Article btw
Pingback: » You can’t keep a good idea down
Pingback: Booting - Bootstrapping, Self-hosting, Self-interpreter « CK Wong’s Microscopic Universe
#12 by Ronald Kurr on December 19, 2009 - 1:16 pm
Quote
Mark, I found your post interesting and thought provoking. Although many Java applications are web-based and run inside a servlet container, I’ve also seen the need for standalone headless Spring-based apps. The ability to simplify the launching program’s classpath is worth the price of admission alone. Moving the burden of creating a proper classpath from the installer into the application itself minimizes certain types of errors — “I swear didn’t touch anything. Well, I did make a minor tweek to the launch script but what harm could that do?” Kudos.
#13 by Bernd Adamowicz on June 14, 2012 - 7:45 am
Quote
Hi Mark!
Thanks for this post. Used it as the basis for a similar problem I had. One question: Why are you using ‘ClassLoader.getSystemClassLoader().getParent()’ as the parent for the new classloader? I couldn’t resolve all classes once the new thread was active. Instead I had to use simply ‘ClassLoader.getSystemClassLoader()’.
Thanks
Bernd
#14 by Mark Turansky on June 14, 2012 - 2:23 pm
Quote
HI Bernd,
The current classloader will have all dependencies you need to run your program. Imagine writing a server. You will need more than a few libraries! The parent, meanwhile, has none.
When you create a new classloader and assign the current parent as the parent of the new loader, you will have a brand new classloader free of any dependency and you can load any library you want.
#15 by Bernd Adamowicz on June 15, 2012 - 5:15 am
Quote
Hi Mark,
I also did some debugging and it turned out that ‘ClassLoader.getSystemClassLoader().getParent()’ at runtime is ’sun.misc.Launcher$ExtClassLoader’ which is completely empty whereas ‘ClassLoader.getSystemClassLoader()’ retrieves ’sun.misc.Launcher$AppClassLoader’ which is of course already full of classes. Now it’s obvious to me. Thanks for the hint!
Bernd
#16 by sumit on October 27, 2012 - 12:44 pm
Quote
hi
this is sumit
If you have a class loader in java example please send it to me with how to execute it pleaseits urgent it can save my life.
kumarsumit912@gmail.com
#17 by carpinteyroyal on March 29, 2013 - 12:31 am
Quote
シャネル バッグ 激安新着シャネル,綺麗な商品を販売しています.今は全国送料無料ですから,ぜひ一度ご来店ください!
シャネルアウトレット店舗http://www.chanelsaleoutletsjapan.com
激安 シャネル バッグシャネル 通販,シャネル店舗,新作ココシャネル 女性に最安値 シャネル店舗,Chanel バッグ 2013ならこちら!送料無料でお届けします!名グッチ 財布など幅広く販売しております.ご安心ください,本物保証!
#18 by Linkbucks on March 29, 2013 - 4:51 pm
Quote
Howdy very cool site!! Guy .. Excellent .. Superb .. I will bookmark your web site and take the feeds additionally?I am satisfied to seek out a lot of helpful info right here within the submit, we need develop extra strategies on this regard, thank you for sharing. . . . . .
#19 by tresDraisiods on March 30, 2013 - 4:02 am
Quote
Hx1Vd7Lw5 approximately Nike Surroundings Utmost buy air jordans authentic 97 athletic shoes.A Nike Oxygen Fatmus Ninety seven athletic shoes authentic retro jordans cheap arrived to market trends when it comes to The mid jordans for sale online nineties.you can acquire those relaxed Nike Air conditioning Potential Ninety-seven cheap jordans for sale boots because running footwear for discount charge because of TradeTang.world-wide-web. authentic jordans Personal choice of that Nike Surroundings optimum 97 will give jordan concords you very good enjoyments all through numerous hours associated with buy air jordans authentic work out.Nike Discuss Spot 360 footwear is an additional variety.The jordan concords particular Fatmus 3 boots or shoes
Yis21Ph5Si2Mf5Mp3
#20 by Daklevip on March 30, 2013 - 4:44 am
Quote
daily cialis, information
buy cialis
buy cialis online registered users
20 mg cialis
#21 by Gus on March 30, 2013 - 9:47 am
Quote
I am really glad to read this weblog posts which consists of
plenty of valuable information, thanks for providing these
kinds of statistics.
#22 by MCM on March 30, 2013 - 9:51 am
Quote
When renters in an apartment living situation are building decorating decisions, one of the most crucial factors to consider is whether or not a modification to the apartment is reversible. In most cases, the action is probably be permissible as long since it is easily reversible. However, the case of painting the apartment is really a common exception to this specific rule. Although painting can very easily be reversed, most apartment complexes thanks not allow residents in order to pain the apartment during which they reside. This is because although painting is usually reversible, the process of returning the wall to the original color is not necessarily easy. MCM http://www.lovemcmbag.com/
#23 by Fivranid on March 30, 2013 - 10:08 pm
Quote
does cialis work multiple attempts
buy cialis
online pharmacy, viagra, cialis, uk
cialis 20mg review forum rules
#24 by コーチ メンズ on March 31, 2013 - 7:19 pm
Quote
Hello There. I discovered your weblog using msn. This is a very smartly written article. I will be sure to bookmark it and return to read more of your helpful info. Thanks for the post. I will certainly comeback.
#25 by コーチ アウトレット on March 31, 2013 - 8:23 pm
Quote
I was recommended this website through my cousin. I’m not certain whether this post is written by means of him as no one else understand such targeted approximately my difficulty. You are amazing! Thank you!
#26 by shaneruhanbaijapan.com on May 18, 2013 - 12:27 am
Quote
If some one wants to be updated with hottest technologies after
that he must be visit this web site and be up to date
every day.
#27 by nike free 5.0 on May 19, 2013 - 11:39 pm
Quote
I like what you guys are up too. Such clever work and exposure!
Keep up the superb works guys I’ve added you guys to our blogroll.