Sponsored Link •
One aspect of the Java virtual machine that plays an important role in both security and network- mobility is the class loader architecture. In the block diagrams of Figures 1-3 and 1-4, a single mysterious cube identifies itself as "the class loader," but in reality there may be more than one class loader inside a Java virtual machine. Thus the class loader cube of the block diagram actually represents a subsystem that may involve many class loaders. The Java virtual machine has a flexible class loader architecture that allows a Java application to load classes in custom ways.
A Java application can use two types of class loaders: a "bootstrap" class loader and user-defined class loaders. The bootstrap class loader (there is only one of them) is a part of the Java virtual machine implementation. For example, if a Java virtual machine is implemented as a C program on top of an existing operating system, then the bootstrap class loader will be part of that C program. The bootstrap class loader loads classes, including the classes of the Java API, in some default way, usually from the local disk. (The bootstrap class loader has also been called the primordial class loader, system class loader, or default class loader. In 1.2, the name "system class loader" was given a new meaning, which is described in Chapter 3.)
At run-time, a Java application can install user-defined class loaders that load classes in custom ways, such as by downloading class files across a network. While the bootstrap class loader is an intrinsic part of the virtual machine implementation, user-defined class loaders are not. Instead, user-defined class loaders are written in Java, compiled to class files, loaded into the virtual machine, and instantiated just like any other object. They are really just another part of the executable code of a running Java application. You can see a graphical depiction of this architecture in Figure 1-5.
Because of user-defined class loaders, you don't have to know at compile-time all the classes that may ultimately take part in a running Java application. User-defined class loaders enable you to dynamically extend a Java application at run-time. As it runs, your application can determine what extra classes it needs and load them through one or more user-defined class loaders. Because you write the class loader in Java, you can load classes in any manner expressible in Java code. You can download them across a network, get them out of some kind of database, or even calculate them on the fly.
For each class it loads, the Java virtual machine keeps track of which class
loader--whether bootstrap or
user-defined--loaded the class. When a loaded class first refers to another
class, the virtual machine requests
the referenced class from the same class loader that originally loaded
referencing class. For example, if the virtual machine loads class
Volcano through a particular class loader, it will attempt to load
Volcano refers to through the same class loader. If
refers to a class named
Lava, perhaps by invoking a method in class
Lava, the virtual machine will request
Lava from the
Lava class returned by the
is dynamically linked with class
Because the Java virtual machine takes this approach to loading classes, classes can by default only see other classes that were loaded by the same class loader. In this way, Java's architecture enables you to create multiple name-spaces inside a single Java application. Each class loader in your running Java program has its own name-space, which is populated by the names of all the classes it has loaded.
A Java application can instantiate multiple user-defined class loaders either from the same class or from multiple classes. It can, therefore, create as many (and as many different kinds of) user-defined class loaders as it needs. Classes loaded by different class loaders are in different name- spaces and cannot gain access to each other unless the application explicitly allows it. When you write a Java application, you can segregate classes loaded from different sources into different name-spaces. In this way, you can use Java's class loader architecture to control any interaction between code loaded from different sources. In particular, you can prevent hostile code from gaining access to and subverting friendly code.
One example of dynamic extension is the web browser, which uses user-defined class loaders to download the class files for applets across a network. A web browser fires off a Java application that installs a user-defined class loader--usually called an applet class loader-- that knows how to request class files from an HTTP server. Applets are an example of dynamic extension, because the Java application doesn't know when it starts which class files the browser will ask it to download across the network. The class files to download are determined at run-time, as the browser encounters pages that contain Java applets.
The Java application started by the web browser usually creates a different user-defined class loader for each location on the network from which it retrieves class files. As a result, class files from different sources are loaded by different user-defined class loaders. This places them into different name-spaces inside the host Java application. Because the class files for applets from different sources are placed in separate name- spaces, the code of a malicious applet is restricted from interfering directly with class files downloaded from any other source.
By allowing you to instantiate user-defined class loaders that know how to download class files across a network, Java's class loader architecture supports network-mobility. It supports security by allowing you to load class files from different sources through different user-defined class loaders. This puts the class files from different sources into different name-spaces, which allows you to restrict or prevent access between code loaded from different sources.
The Java class file helps make Java suitable for networks mainly in the areas of platform-independence and network-mobility. Its role in platform independence is serving as a binary form for Java programs that is expected by the Java virtual machine but independent of underlying host platforms. This approach breaks with the tradition followed by languages such as C or C++. Programs written in these languages are most often compiled and linked into a single binary executable file specific to a particular hardware platform and operating system. In general, a binary executable file for one platform won't work on another. The Java class file, by contrast, is a binary file that can be run on any hardware platform and operating system that hosts the Java virtual machine.
When you compile and link a C++ program, the executable binary file you get is specific to a particular target hardware platform and operating system because it contains machine language specific to the target processor. A Java compiler, by contrast, translates the instructions of the Java source files into bytecodes, the "machine language" of the Java virtual machine.
In addition to processor-specific machine language, another platform- dependent attribute of a traditional binary executable file is the byte order of integers. In executable binary files for the Intel X86 family of processors, for example, the byte order is little-endian, or lower order byte first. In executable files for the PowerPC chip, however, the byte order is big-endian, or higher order byte first. In a Java class file, byte order is big-endian irrespective of what platform generated the file and independent of whatever platforms may eventually use it.
In addition to its support for platform independence, the Java class file plays a critical role in Java's architectural support for network-mobility. First, class files were designed to be compact, so they can more quickly move across a network. Also, because Java programs are dynamically linked and dynamically extensible, class files can be downloaded as needed. This feature helps a Java application manage the time it takes to download class files across a network, so the end-user's wait time can be kept to a minimum.