Why does the AppClassLoader delegate to the ExtClassLoader instead of BootstrapClassLoader? - java

I learn that
Bootstrap ClassLoader loads classes from the location rt.jar.
and the Delegation Model
Bootstrap
|
Extensions
|
Application
When I look at AppClassLoader, it is
Static classes in sun.misc.Lanucher under jre\lib\rt.jar
As mentioned above, BootstrapClassLoader will load the classes under the rt.jar package, that is to say, the loading class of AppClassLoader is BootstrapClassLoader
so why does AppClassLoader delegate to the static inner class ExtClassLoader under the same class instead of BootstrapClassLoader?

Related

Split Packages: Java Modules vs Sealed Jars

Both Sealed Packages/Jars and the Java Module System disallow spliting packages across several jars.
Does that mean that all packages contained within a Module are implicitly sealed? If not what does explicitly sealing the jar change?
Yes, packages within modules are always implicitly sealed. This is specified in the documentation of the Package class:
A Package automatically defined for classes in a named module has the following properties:
The name of the package is derived from the binary names of the classes. Since classes in a named module must be in a named package, the derived name is never empty.
The package is sealed with the module location as the code source, if known.
The specification and implementation titles, versions, and vendors are unspecified.
Any annotations on the package are read from package-info.class as specified above.
I also made a quick test to verify that isSealed() on a module’s package did indeed return true. However, it must be noted that the relationship between (named) modules and packages is of a fundamental nature and hence, independent of the fact that isSealed() returns true. The latter is just the natural way for the old API to interact with this new feature.
A sealed package of an unnamed module only affects the runtime package of the particular class loader, as each class loader can have a package of the same name, which is considered a different runtime package.
In contrast, each package of a named module must unambiguously belong to a single module within the entire module layer and a module layer can span multiple class loaders, e.g. the boot layer spans the bootstrap loader, the platform loader, and the application loader.
This affects the class loading process. The old way of loading, which is still used for the unnamed module, features class loader delegation where each loader queries its parent loader first. When the parent loader failed, the class path entries are queried linearly for the class until a class is found.
When a module layer is initialized, all package names and their owning modules are recorded, so when an attempt to load a class is made, the package name can be derived from the qualified name and mapped to a module even before the class is loaded and therefore, only the module’s known source needs to be queried.

Java Module Layers: Access classes in custom ModuleLayer from unnamed module

We have a plugin system with multiple module layers:
The PluginLoader module inside the boot layer instantiates a custom ModuleLayer for each Module at runtime with ModuleLayer::defineModulesWithOneLoader.
We now have a set of non-modular plugins that need access to the modular plugins inside the custom layers. They will be loaded after the custom layers have been instantiated. How can this be achieved?
Simply putting them on the classpath doesn't work, since the modular classes will be loaded a second time instead of using the (already loaded) classes from the modular plugins.
Our next try was creating a dummy plugin and loading it last inside a layer that has all other layers (and therefore modular plugins) as parents. It doesn't seem to be possible to add URLs to the class loader generated by the defineModulesWithOneLoader method. Instead we created a custom URLClassLoader as a parent of this class loader and added the non-modular JARs via URLClassLoader::addURL.
This works for the non-modular plugin classes. However, if a class already loaded in one of the modular plugins is referenced from such a class, it will also attempt to load the class with our custom URLClassLoader (which fails, since the parent is null) instead of the module's internal class loader, which delegates to parent layers. Is there a way to load our non-modular plugin's classes inside the unnamed module of a class loader that behaves like the JPMS' default class loader (search parent layers first) but still loads the classes inside the non-modular JAR, if they aren't found in the parent layers?
It is possible to solve this by using automatic modules, but we want to avoid this for now since it leads to a slew of other necessary changes (e.g. resolve split packages) which we currently don't have the resources for.

classloader in java is a class itself then who will load the classloader class?

ClassLoader in Java is a class which is used to load class files in Java.
The java.lang.ClassLoader is an abstract class
here my question is does this java.lang.ClassLoader class is any way related to JVM's classloaders(1. Bootstrap class loader 2. Extensions class loader 3. System class loader)?
or this java.lang.ClassLoader is a separate class which can be used to create a custom classloader?
Class loaders are the part of the Java Runtime Environment that dynamically loads Java classes into the Java virtual machine. It is responsible for locating libraries, reading there content and loading the classes contained within the libraries When JVM is started three class loaders are used
Bootstrap class loader
Extensions class loader
System class loader
Bootstrap class loader loads the core java libraries. It is written in native code. The bootstrap class loader is responsible for loading key java classes like java.lang.Object and other runtime code into memory. The runtime classes are packaged inside jre/lib/rt.jar file.
Extensions class loader loads the code in the extension directories. It is implemented by ExtClassLoader class.
System class loader the code found on the java.class.path which map to the system class path variables. It is implemented by AppClassLoader class. All user classes by default are load by the system class loader.
Java ClassLoader are hierarchical and whenever a request is raised to load a class, it delegates it to its parent and in this way uniqueness is maintained in the runtime environment. If the parent class loader doesn’t find the class then the class loader itself tries to load the class.
so that means first System class loader will delegate request to Extensions class loader that will delegate request to Bootstrap class loader here it will search for class if not found then Extensions class loader will search for class if not found then System class loader will search for class if not found then it throws ClassNotFoundException
does JVM always starts with System class loader for loading class?
correct me if i'm wrong any where
The term “System class loader” is a misnomer. As you stated correctly, it’s responsible for loading the classes from locations of the class path, which are the application classes.
As of Java 8, both, AppClassLoader and ExtClassLoader, are subclasses of java.net.URLClassLoader, which is a subclass of java.security.SecureClassLoader, which is a subclass of java.lang.ClassLoader. All of these classes are loaded by the Bootstrap loader, solving the chicken-and-egg problem.
Each runtime class has a defining class loader. For those classes defined by the Bootstrap loader during startup, the defining class loader is the Bootstrap loader. When the JVM initialization is completed and an attempt to start an application is made, the Application class loader (aka System class loader) will be queried for the main class. The Application class loader will follow the standard delegation model querying the parent first, likewise does the Extension class loader and whichever class loader will create the class will be the class’ defining class loader.
Now, when resolving a class referenced by another class or when Class.forName(String) is invoked, the defining loader of the class containing the reference will be used to resolve the class. So when the Application class loader has loaded your class myapp.foo.Bar and it contains a reference to javax.swing.JButton, its defining class loader, i.e. the Application class loader, will be queried for that class, follow the delegation model to end up with a javax.swing.JButton defined by the Bootstrap loader. So class references within javax.swing.JButton are resolved only through the Bootstrap loader, which implies that javax.swing.JButton can not contain a reference to your myapp.foo.Bar class, as it is not in scope.
So, the JVM does not always starts with “System class loader” for loading a class, but only for resolving class references of classes defined by it (or a child loader) or when being queried explicitly, like when resolving the main class.
There are 3rd party class loaders not strictly following the parent delegation model, but regardless of how and to which loader they delegate, there will be a defining loader for each class (the one returned by getClassLoader()), which will be the one used for resolving references within the class. The JVM ensures that identical symbolic names within one class always resolve to the same runtime class, regardless of how the particular class loader implements lookups.
Note that in Java 9, the Extension class loader has been replaced by the Platform class loader. This class loader may deviate from the simple parent delegation, i.e. it might delegate to the Application class loader for loading application provided modules that supersede a platform provided module. Also, the builtin class loaders are not subclasses of URLClassLoader anymore.

Difference between AppClassloader and SystemClassloader

I am so confused about these two class loaders. When talking about the hierarchy of Java class loaders, usually the bootstrap classloader and ext class loader and the third one (system classloader or app classloader) are mentioned.
To be more accurate, I checked the source code of JDK. In class Launcher, there is the code:
loader = AppClassLoader.getAppClassLoader(extcl);
In class ClassLoader, the method:
getSystemClassloader()
Also says the system classloader is used to start the application.
So which is the third one in the hierarchy, or are the two classloaders the same?
Both AppClassLoader and SystemClassLoader are same.
Have a look at hierarchy.
ClassLoader follows three principles.
Delegation principle
Bootstrap ClassLoader is responsible for loading standard JDK class files from rt.jar and it is parent of all class loaders in Java. Bootstrap class loader don't have any parents.
Extension ClassLoader delegates class loading request to its parent, Bootstrap and if unsuccessful, loads class form jre/lib/ext directory or any other directory pointed by java.ext.dirs system property
System or Application class loader and it is responsible for loading application specific classes from CLASSPATH environment variable, -classpath or -cp command line option, Class-Path attribute of Manifest file inside JAR.
Application class loader is a child of Extension ClassLoader and its implemented by sun.misc.Launcher$AppClassLoader class.
Except Bootstrap class loader, which is implemented in native language mostly in C, all Java class loaders are implemented using java.lang.ClassLoader.
Have a look at this blog for better understanding of these three class loaders.
Visibility Principle
According to visibility principle, Child ClassLoader can see class loaded by Parent ClassLoader but vice-versa is not true.
If class Abc is loaded by Application class loader then trying to load class ABC explicitly using Extension ClassLoader will throw java.lang.ClassNotFoundException
Uniqueness Principle
According to this principle a class loaded by Parent should not be loaded by Child ClassLoader again
System class loader is a different name for Application class loader.
Source:
https://blogs.oracle.com/sundararajan/entry/understanding_java_class_loading
Application class loader ... is also (confusingly) called as "system class
loader" - not to be confused with bootstrap loader which loads Java "system"
classes.
The third in the class loader hierarchy is the SystemClassloader. It is also referred as ApplicationClassloader (or AppClassLoader) at some places. This loader loads the our application code and classes found in the classpath.
Regarding the below method in the Classloader:
public static ClassLoader getSystemClassLoader()
Javadoc says:
Returns the system class loader for delegation. This is the default
delegation parent for new ClassLoader instances, and is typically the
class loader used to start the application.
The important piece here is
This is the default delegation parent for new ClassLoader instances, and is typically the class loader used to start the application
Which means, if we create our own Custom or new classloader in our application, the System or Application class loader becomes the parent for our Custom or new classloader. And calling the getSystemClassLoader() method in Custom or new Classloader returns the System(aka Application) classloader. This aligns with the java class loader delegation model as well.
And the System (aka Application) class loader is the one which has loaded our class or app from classpath.

How to load jar classes as if they were referenced library?

I loaded my jar classes with:
ClassLoader.getSystemClassLoader().loadClass(name)
in my Plugin loader. But it seems JVM does not register them as a class as if they were referenced, therefore they get garbage collected I get:
ClassNotFoundException at runtime
How can I register them as if they were a referenced library?
Also, how does JVM load referenced library classes and keeps them registered during JVM lifetime? Can we register runtime loaded classes that way?
Example:
I have an abstract class called AbstractAction in my main project. Then a jar calls x.jar implemented it in ActionImpl. I loaded the jar at runtime and used ActionImpl. But classes that are used in ActionImpl like Utils are not loaded and I get ClassNotFoundException on Utils.

Categories