How does classloading work with multiple child layers?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

How does classloading work with multiple child layers?

Alex Sviridov

Hello everybody,
 
I try to understand how classloading works when there are multiple child layers
and have a problem.
 
Let's consider the following situation. There are three layers.
BootLayer (moduleA)
     |
     |_______Child1(moduleB)
                |
                |__________ Child2(moduleC)
 
Child1 is the child of the BootLayer, Child2 is the child of the Child1.
 
Child1 and Child2 were created with the same code:
ClassLoader parentClassLoader = ClassLoader.getSystemClassLoader();
ModuleLayer layer = parentLayer.defineModulesWithOneLoader(cf, parentClassLoader);
 
As you see the parent class loader of both child layers is SystemClassLoader.
 
I am a beginner at classloading, but I've read about parent-first delegation model. However, if for both child layers SystemClassLoader is used, then why they see classes from other layers? I mean, why does moduleC
see classes from moduleB if the parentClass is SystemClassLoader (SystemClassLoader as I understand
delegates to BootLayer, but not to Child1 layer). Could anyone explain?
 
--
Best regards, Alex Sviridov
Reply | Threaded
Open this post in threaded view
|

Re: How does classloading work with multiple child layers?

Alan Bateman
On 14/04/2020 20:48, Alex Sviridov wrote:

> Hello everybody,
>  
> I try to understand how classloading works when there are multiple child layers
> and have a problem.
>  
> Let's consider the following situation. There are three layers.
> BootLayer (moduleA)
>       |
>       |_______Child1(moduleB)
>                  |
>                  |__________ Child2(moduleC)
>  
> Child1 is the child of the BootLayer, Child2 is the child of the Child1.
>  
> Child1 and Child2 were created with the same code:
> ClassLoader parentClassLoader = ClassLoader.getSystemClassLoader();
> ModuleLayer layer = parentLayer.defineModulesWithOneLoader(cf, parentClassLoader);
>  
> As you see the parent class loader of both child layers is SystemClassLoader.
>  
> I am a beginner at classloading, but I've read about parent-first delegation model. However, if for both child layers SystemClassLoader is used, then why they see classes from other layers? I mean, why does moduleC
> see classes from moduleB if the parentClass is SystemClassLoader (SystemClassLoader as I understand
> delegates to BootLayer, but not to Child1 layer). Could anyone explain?
>
Module layers are an advanced topic. ClassLoaders are also an advanced
topic. When working with module layers and using the
defineModulesWithXXX methods to create the module layers, then you
mostly don't need to be too concerned with class loaders. They are still
used to load classes but they are mostly in the background (and not in
your face).

You also don't need to be too concerned with the "parent class loader"
that you specify to the defineOneWithOneLoader method. It's not used
when loading classes from modules, it's only when for cases where the
code in moduleB or moduleC tries to load a class that is not in a
module, maybe Class.forName("Foo") where Foo is on the class path. So
probably best to ignore the parent class loader when starting out.

The API docs [1] explain how the delegation works with modules but maybe
it's not clear enough for what is needed here. In your example, support
L1 is the class loader for module B in child layer 1, and L2 is the
class loader for module C in child layer 2. Further suppose the module
declarations are:

module moduleC {
     requires moduleB;
}

module moduleB {
     exports b;
}

The configuration for Child1 is very simple: one moduleB that reads
java.base

The configuration for Child2 is also very simple: one moduleC that reads
moduleB and java.base.

When Child1 is created it will create L1 and map moduleB to L1. When
code in moduleB tries to resolve a reference to a class in its own
module then it will be loaded by L1 (no delegation). When moduleB
references a class in java.base then L1 will delegate to the boot loader.

When Child2 is created it will create L2 and map moduleC to L2. When
code in moduleC tried to resolve a reference to a class in its own
module then it will be loaded by L1 (no delegation). When moduleC
references a b.* class then it will be delegate to L2 to resolve the
reference. When moduleC references a class in java.base then L1 will
delegate to the boot loader.

If you draw this out then you should see that the class loader
delegation is "direct delegation" and exactly mirrors the edges in the
readability graph (Configuration object).

Hopefully this is enough to get your started. It really needs diagrams
and graphs to explain some of these details probably. As I said, you can
mostly ignore class loader details when working with module layers.

-Alan

[1]
https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/ModuleLayer.html#defineModulesWithOneLoader(java.lang.module.Configuration,java.util.List,java.lang.ClassLoader)
Reply | Threaded
Open this post in threaded view
|

Re[2]: How does classloading work with multiple child layers?

Alex Sviridov

Hi Alan,
 
Thank you very much for such detailed answer! Only one note — is the following
paragraph right?
  «When Child2 is created it will create L2 and map moduleC to L2. When
code in moduleC tried to resolve a reference to a class in its own
module then it will be loaded by L1 (POINT X) (no delegation). When moduleC
references a b.* class then it will be delegate to L2 (POINT Y) to resolve the
reference. When moduleC references a class in java.base then L1 will
delegate to the boot loader.»
 
Maybe  POINT X = L2 and  POINT Y = L1 ???
 
Best regards
 

>Среда, 15 апреля 2020, 14:12 +03:00 от Alan Bateman <[hidden email]>:

>On 14/04/2020 20:48, Alex Sviridov wrote:
>> Hello everybody,
>>
>> I try to understand how classloading works when there are multiple child layers
>> and have a problem.
>>
>> Let's consider the following situation. There are three layers.
>> BootLayer (moduleA)
>>      |
>>      |_______Child1(moduleB)
>>                 |
>>                 |__________ Child2(moduleC)
>>
>> Child1 is the child of the BootLayer, Child2 is the child of the Child1.
>>
>> Child1 and Child2 were created with the same code:
>> ClassLoader parentClassLoader = ClassLoader.getSystemClassLoader();
>> ModuleLayer layer = parentLayer.defineModulesWithOneLoader(cf, parentClassLoader);
>>
>> As you see the parent class loader of both child layers is SystemClassLoader.
>>
>> I am a beginner at classloading, but I've read about parent-first delegation model. However, if for both child layers SystemClassLoader is used, then why they see classes from other layers? I mean, why does moduleC
>> see classes from moduleB if the parentClass is SystemClassLoader (SystemClassLoader as I understand
>> delegates to BootLayer, but not to Child1 layer). Could anyone explain?
>> Module layers are an advanced topic. ClassLoaders are also an advanced
>topic. When working with module layers and using the
>defineModulesWithXXX methods to create the module layers, then you
>mostly don't need to be too concerned with class loaders. They are still
>used to load classes but they are mostly in the background (and not in
>your face).
>
>You also don't need to be too concerned with the "parent class loader"
>that you specify to the defineOneWithOneLoader method. It's not used
>when loading classes from modules, it's only when for cases where the
>code in moduleB or moduleC tries to load a class that is not in a
>module, maybe Class.forName("Foo") where Foo is on the class path. So
>probably best to ignore the parent class loader when starting out.
>
>The API docs [1] explain how the delegation works with modules but maybe
>it's not clear enough for what is needed here. In your example, support
>L1 is the class loader for module B in child layer 1, and L2 is the
>class loader for module C in child layer 2. Further suppose the module
>declarations are:
>
>module moduleC {
>     requires moduleB;
>}
>
>module moduleB {
>     exports b;
>}
>
>The configuration for Child1 is very simple: one moduleB that reads
>java.base
>
>The configuration for Child2 is also very simple: one moduleC that reads
>moduleB and java.base.
>
>When Child1 is created it will create L1 and map moduleB to L1. When
>code in moduleB tries to resolve a reference to a class in its own
>module then it will be loaded by L1 (no delegation). When moduleB
>references a class in java.base then L1 will delegate to the boot loader.
>
>When Child2 is created it will create L2 and map moduleC to L2. When
>code in moduleC tried to resolve a reference to a class in its own
>module then it will be loaded by L1 (no delegation). When moduleC
>references a b.* class then it will be delegate to L2 to resolve the
>reference. When moduleC references a class in java.base then L1 will
>delegate to the boot loader.
>
>If you draw this out then you should see that the class loader
>delegation is "direct delegation" and exactly mirrors the edges in the
>readability graph (Configuration object).
>
>Hopefully this is enough to get your started. It really needs diagrams
>and graphs to explain some of these details probably. As I said, you can
>mostly ignore class loader details when working with module layers.
>
>-Alan
>
>[1]
>https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/ModuleLayer.html#defineModulesWithOneLoader(java.lang.module.Configuration,java.util.List,java.lang.ClassLoader )
 
 
--
Alex Sviridov
 
Reply | Threaded
Open this post in threaded view
|

Re: How does classloading work with multiple child layers?

Alan Bateman
On 15/04/2020 12:45, Alex Sviridov wrote:

> Hi Alan,
>  
> Thank you very much for such detailed answer! Only one note — is the following
> paragraph right?
>    «When Child2 is created it will create L2 and map moduleC to L2. When
> code in moduleC tried to resolve a reference to a class in its own
> module then it will be loaded by L1 (POINT X) (no delegation). When moduleC
> references a b.* class then it will be delegate to L2 (POINT Y) to resolve the
> reference. When moduleC references a class in java.base then L1 will
> delegate to the boot loader.»
>  
> Maybe  POINT X = L2 and  POINT Y = L1 ???
>
Sorry about, I don't know how they got transposed.

In any case, I hope it is clearer how these class loaders delegate.

-Alan