Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a Java Class loaded?

I searched the internet for more than couple of hours and could not reach any conclusion.

Recently I decided to use BouncyCastle for SSL but I wanted it to off by default, so that BouncyCastle jar may not be in the class path.

private void enableBouncyCastleForSSL() {
   if (config.isBouncyCastleEnabled()) {
        Security.insertProviderAt(new BouncyCastleProvider(), 1);
    }
} 

Even when config is disabled, it was looking for BouncyCastle and it failed with class loader error. java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProvider

I tried moving just the line Security.insertProviderAt(new BouncyCastleProvider(), 1); to a new method it exhibited the same problem.

But when I introduce a class and move the BouncyCastle inside it, when the config is disabled, class loader issue does not appear

private void setupSSLProvider() {
    if (voldemortConfig.isBouncyCastleEnabled()) {
        SetupSSLProvider.useBouncyCastle();
    }
}
public class SetupSSLProvider {
  public static void useBouncyCastle() {
    Security.insertProviderAt(new BouncyCastleProvider(), 1);
  }
}

Some articles claim that Class is loaded only when it is first used. http://www.programcreek.com/2013/01/when-and-how-a-java-class-is-loaded-and-initialized/

Apparently in my case, Java8 loads the class referenced in a class.

So my understanding is Java will load the classes one level deep, before executing first line of code in a class. Is that right ?

like image 927
Arun Thirupathi Avatar asked Dec 14 '15 03:12

Arun Thirupathi


People also ask

How is a class loaded in Java?

In order to actually load a class, the JVM uses Classloader objects. Every already loaded class contains a reference to its class loader, and that class loader is used to load all the classes referenced from that class.

Which classes are loaded when JVM starts?

Initially when a JVM starts up, nothing is loaded into it. The class file of the program being executed is loaded first and then other classes and interfaces are loaded as they get referenced in the bytecode being executed.

How many times a class is loaded in Java?

As we can see, there are three different class loaders here: application, extension, and bootstrap (displayed as null). The application class loader loads the class where the example method is contained. An application or system class loader loads our own files in the classpath.

What happens when class is loaded?

Class loading is done by ClassLoaders in Java which can be implemented to eagerly load a class as soon as another class references it or lazy load the class until a need of class initialization occurs. If Class is loaded before its actually being used it can sit inside before being initialized.


1 Answers

There is no simple answer to this question. The specification leaves room for different implementation strategies and even within one implementation, it will depend on how the class is been used. Further, your question is more about “when can it fail” which depends on why it may fail, e.g. a class may be loaded at one point of time to verify its existence but initialized at a later time when it is actually first‑time used. At both points of time, the operation may fail causing a NoClassDefFoundError.

We may categorize referenced classes into three groups:

  • classes that must be resolved at linkage time (e.g. the superclass)
  • classes that must be loaded at verification time
  • classes whose loading can be deferred to it’s first actual use

In your case, BouncyCastleProvider must be loaded at verification time, rather than its first actual use, because you are passing the result of new BouncyCastleProvider() as argument to the method Security.insertProviderAt(…) and the verifier must check whether the class actually extends the Provider type which the method’s formal parameter mandates.

When verification will happen, is also implementation specific as at least the following possibilities are allowed:

  • eagerly traversing all referenced classes
  • on the loading of the containing class or its first use
  • on the containing method’s first use
  • right before executing the offending instruction

Oracle’s JVM prefers a method’s first use, read: verify it at the method entry, thus, moving the invocation into another method that won’t get executed, be it in another class or not, is sufficient in your case.

But to be compatible with other JVMs, moving it into another class is safer, but to comply to all possible JVMs, you need to even load this other class via Reflection to avoid a direct reference that can be traversed by an eager implementation (or instantiate BouncyCastleProvider reflectively via Class.forName("… .BouncyCastleProvider").newInstance() in the first place).

like image 105
Holger Avatar answered Oct 25 '22 11:10

Holger