Two things hamper this kind of scaling. First, the class data is likely stored on the same disk,
so two classloaders running concurrently will issue disk reads to the same device. Operating
systems are pretty good at dealing with that situation; they can split up the reads and grab
bytes as the disk rotates. Still, there is every chance that the disk will become a bottleneck in
Until Java 7, a bigger issue existed in the design of the ClassLoader class itself. Java class-
loaders exist in a hierarchy as shown in Figure 12-1 , which is an idealized version of the
classloaders in a Java EE container. Normally, classloading follows a delegation model.
When the classloader running the first servlet application needs a class, the request flows to
the first web app classloader, but that classloader delegates the request to the its parent: the
system classloader. That's the classloader associated with the classpath; it will have the Java
EE-based classes (like the Java Server Faces, or JSF, interfaces) and the container's imple-
mentation of those classes. That classloader will also delegate to its parent classloader, in this
case the bootstrap classloader (which contains the core JDK classes).
Figure 12-1. Idealized structure of multiple classloaders
The net result is that when there is a request to load a class, the bootstrap classloader is the
first code that attempts to find the class; that is followed by the system (classpath) classload-
er, and then the application-specific classloader(s). From a functional point of view, that's
what makes sense: the bytecodes for the java.lang.String class must come from the boot-
strap classloader and not some other implementation that was accidentally (or maliciously)
included in some other classloader in the hierarchy.