Friday, April 29, 2011

Namespaces in class loading

In general, a running Java environment can have many Class Loaders active, each defining its own namespace. Namespaces allow Java classes to see different views of the world depending on where they originate.
Eg. - classes from some url, OR classes from local environment, classes from particular firewall.

Simply put, a namespace is a set of unique names of classes loaded by a particular Class Loader and a binding of each name to a specific class object. Though some people say that namespaces are disjoint and do not overlap, this is not true in general. There is nothing to stop namespaces from overlapping.

Most VM implementations have used different class loaders to load code from different origins. This allowed these implementations to assign a single security policy to all code loaded by the same class loader, and to make security decisions based on which class loader loaded the class that is asking to perform a dangerous operation. With the addition of code signing in JDK 1.1, there are now two characteristics for categorization of code: origin (usually represented as a URL) and signer (the identity associated with the private key used to sign the file). Only the Class Loader that loaded a piece of code knows for sure where the code was loaded from.

According to the Java specification, every Class Loader must keep an inventory of all the classes it has previously loaded. When a class that has already been loaded is requested again, the class loader must return the already loaded class.

Every different class loader represents a different namespace. Static fields of classes inside one namespace are separate from static fields of classes from other namespaces. If we set a value of a specific static field in namespace A, objects from namespace B will not be able to read it, and vice versa.

Let’s see how it works. We will have a public static Integer field in some class, and we will be trying to access this field from classes loaded with different class loaders. Here is this field:

public class StaticHolder {
    public static Integer value = null;
}

Below is also the class used to access the field. It will read the value of the field and then change it to 4. Default value for any class field is null, so that’s what we expect to see as the start value. In a normal, single-classloader program, after changing the value of the static field, the change would be visible to other objects reading that field. We will see what happens with multiple classloaders.

public class StaticAccessor {
    /**
     * Accesses the static field from StaticHolder class.
     * It reads its value and after that sets it to 4.
     */
    @Override
    public void runMe() {
        System.out.println("--- Starting runMe. Static value: "
            + StaticHolder.value);
        StaticHolder.value = 4;
        System.out.println("--- Finishing runMe. Static value: "
            + StaticHolder.value);
    }
}

In our experimental main method we will create this time two CustomClassLoaders and load our StaticAccessor field with both of them. We will then create two instances of the StaticAccessor class, each of them from the different class loader, and run their runMe() methods.

 You can find the implementation of our CustomClassLoader in the previous article.

When we run the program, we will get the following output:
loading class 'javablogging.StaticAccessor'
...
--- Starting runMe. Static value: null
loading class 'java.lang.Integer'
--- Finishing runMe. Static value: 4
loading class 'javablogging.StaticAccessor'
...
--- Starting runMe. Static value: null
loading class 'java.lang.Integer'
--- Finishing runMe. Static value: 4
When you look at the “— Starting runMe” lines, you will notice that both of them show null! Although we changed the static field to 4 in the first run of runMe(), the value read in the second runMe() shows once again null.

In normal programs it may be hard to see a usage for such tricks. Separating namespaces in such a way may be however useful for example when doing unit tests, when you want to be sure that every test runs in a completely separate sandbox, or when implementing frameworks or application servers, where every deployed application should be isolated from others.

References
You can read more about class loaders and namespaces in Java for example in this article: http://www.artima.com/underthehood/classloadersP.html.



No comments:

Post a Comment

Chitika