12

I am learning the process of loading java class and encounter some confusion.

I know when loading a java class, current classLoader wont load the java class directly and it will delegate to its parent classLoader(a recursive process) until it parent cant load this class.


The question is that :what is the current classLoader? Bootstrap? Extension? App?
how to get the current classLoader?. and I know there is an API:

xxx.Class.getClassLoader();

but I am not sure whether the return value is currentClassLoader. I think it should be the classLoader which load this java class in reality.

To describe my question more detail I will give an example.
I get the follow content in a blog.

ThreadContextClassLoader is used to deal with java SPI, Interface is defined in java core lib and loaded by Bootstrap ClassLoader and third party implement these interface then the jar are loaded by AppClassLoader
Solution: traditional classLoader cant deal with this case,because it cant discovery the third party jar when we use the third party implement in core lib.

most of the above that I can understand but the solution make me confusion: for example, the Interface CoreA and class CoreB are in java core lib and should be loaded by Bootstrap ClassLoader and the AImpl is a implement of A by third party and should be loaded by AppClass loader.

the code segment as below:

 public Interface CoreA{
     void add();
 }

 public Interface AImpl implements CoreA{
     void add(){};
 }

 public class B{
      public void demo(){
         a = new AImpl();
      }
 }

then if we reference B in main method, then we will load B because the class loader of B is Bootstrap then about AImpl the current Loader is Bootstrap so it cant be found? I dont know whether it is as what I guess?

Any advice will be appreciated.

3
  • 1
    Different environments use different class loading strategies. The default is to first propagate the class loading request to the parent class loader. If it is unable to load the class, this class loader will try to load it. However, some application server class loaders will not ask their parent class loader first, if they are able to load the class by themselves. Next, there is even more complex class loader magic in OSGi to implement a module system. Commented Dec 12, 2016 at 14:12
  • 1
    There is no such thing as a “current ClassLoader.” Every class is loaded by a particular ClassLoader. That’s all there is to it. Commented Dec 12, 2016 at 14:24
  • 1
    Sometimes I'm facing with term current classloader and it's fine, it's just a classloader of currently executed class. Commented Dec 12, 2016 at 15:44

3 Answers 3

14

Generally speaking you are right, it can't be found. Let me show you the following example. Let's say we have 3 classes: A, B and Main like these:

public class A {
    public String a() {
        return "a";
    }
}

public class B {
    public String b() {
        return new A().a();
    }
}

public class Main {
    public static void main(String... args) {
        System.out.println(new B().b());
    }
}

And we package these classes into correspondent jars: a.jar, b.jar and place Main.class into the working directory. After that let's test the following scenarios:

1) Everything (A.class, B.class, Main.class) is loaded by system classloader and works fine:

$ java -cp .:a.jar:b.jar Main
a

2) B.class is loaded by system classloader and A.class is loaded by bootstrap classloader and everything still works fine because system classloader delegates loading to bootstrap classloader (just because bootstrap classloader can load it):

$ java -Xbootclasspath/a:a.jar -cp .:b.jar Main
a

3) A.class is loaded by system classloader and B.class is loaded by bootstrap classloader (your case). In this scenario during loading of B.class current classloader is bootstrap classloader, but it can't found B.class and fails:

$ java -Xbootclasspath/a:b.jar -cp .:a.jar Main
Exception in thread "main" java.lang.NoClassDefFoundError: A
        at B.b(B.java:4)
        at Main.main(Main.java:4)

Lets take a look at the last example more carefully. What's happening here:

  1. Try to find class with public static main(String[] args) method

    1.1. system classloader hasn't loaded it yet so delegates to extension classloader

    1.2. extension classloader hasn't loaded it yet so delegates to bootstrap classloader

    1.3. bootstrap classloader hasn't loaded it yet and tries to load, it can't load it and returns control to extension classloader

    1.4. extension classloader tries to load, it can't load it and returns control to system classloader

    1.5. system classloader loads Main.class

  2. Main.class is processed and we try to load B.class with current classloader system classloader

    2.1. system classloader hasn't loaded it yet so delegates to extension classloader

    2.2. extension classloader hasn't loaded it yet so delegates to bootstrap classloader

    2.3. bootstrap classloader hasn't loaded it yet and loads B.class

  3. B.class is processed and and we try to load A.class with current classloader bootstrap classloader

    3.1. bootstrap classloader hasn't loaded it yet and tries to load and fails

I hope it will help you.

Sign up to request clarification or add additional context in comments.

3 Comments

thanks for your contribution. It does a great help for me. But I think there exist a small flaw in section 2 because system classloader delegates loading to bootstrap classloader if can't load class itself. system classloader delegates loading to its parent classLoader is not beacuse it cant load class itself. Only if its parent classloader cant deal with loading the java class then current class will try to load class itself.
This answer should have more upvotes. Extremely helpful.
follow up question: This implies that if I am within a class loaded with bootstrap classloader , then I can only find and load other classes within core java. However, the implementations for classes like ArrayList (which to my understanding is loaded by bootstrap classloader) includes generics.
4

When a class A attempts to load another class B, the ClassLoader that loaded A is the current ClassLoader. The word current vaguely refers to the execution context - e.g. how do you end up in the method that triggers the current class loading call.

There is no method - say getCurrentClassLoader - that simply gives the current ClassLoader, but there are api methods that internally use the concept of current ClassLoader. For example, Class.forName(String className)

If you check how that method is implemented, it tells you the meaning of "current class loader":

public static Class<?> forName(String className) throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

If you can get hold of a Class instance, you can always ask for the loader behind it by calling Class::getClassLoader() method. That will be your current class loader. The tricky bit, however, is to decide if the loader is bootstrap, or extension, or system class loader. The reason of the trickiness is that it is implementation specific, and you can always implement your own class loading mechanism.

The example given by @dmitrievanthony is an example of how things can become really complicated. It is a similar situation faced by JNDI, and the reason why the hack Thread.getContextClassLoader() was introduced. More about it here

Quote the most relevant piece from the article:

... By definition, a current classloader loads and defines the class to which your current method belongs. This classloader is implied when dynamic links between classes resolve at runtime, and when you use the one-argument version of Class.forName(), Class.getResource(), and similar methods. It is also used by syntactic constructs like X.class class literals ...

Comments

1

the 'current classloader' is the real classloader(load this class in reality) of class that refer it.

e.g. if the classLoader of class A is ext classloader and class A refer class B C D. Then the 'current classloader' of B C D is ext classLoader. And of course the 'current classLoader' of main class is System classLoader.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.