jlink images and module layers

Alan Bateman Alan.Bateman at oracle.com
Thu Feb 11 11:59:52 UTC 2021


On 10/02/2021 21:44, Gunnar Morling wrote:
> Hi Alan,
>
> Thanks for your thoughtful reply. The use case I'd see for layers
> within jlink images is isolation of different (transitive) dependency
> versions within an application. While this isn't present (and I
> understand it'd add a fair share of complexity), we can work around
> this by putting the modules of different layers into a separate
> directory and use this as source for the layers running on top of the
> JDK modules from the image. We might envision some tooling support for
> creating such "extended" jlink image.
It would need a lot of consideration and exploration before going there. 
One reason for having different versions of a module in the run-time 
image might be to support different initial modules, say a run-time 
image containing two distinct applications or tools. Both would run with 
in flat name space but for whatever reason can't use the same version of 
some module. At the other extreme might be launching an application that 
is magically started with several layers and different versions of 
modules in each layer. Somewhere in the middle is a container in the 
boot layer and at run-time it uses the APIs to create module layers. The 
set of observable modules that it uses when creating the configurations 
for these modules layer is some subset of the modules in the run-time 
image that include modules that weren't observable at startup when 
creating the boot layer.



>
> Btw. when exploring dynamic plug-in layers and their interaction with
> services, we noticed that you'll also get services provided by parent
> layers. This leads to code patterns like shown here:
>
>      https://urldefense.com/v3/__https://github.com/moditect/layrry-examples/blob/master/modular-tiles/core/modular-tiles-core/src/main/java/org/kordamp/tiles/core/TilePluginLifecycleListener.java*L41-L43__;Iw!!GqivPVa7Brio!L0YyyA2bQu9Mr2QdbMC3mK-U7Vkt8WmI3LIlw_FmwS58Iqo42j9JN77ETD7lxI-Q-Q$
>
> I.e. you need to filter out all those service implementations from
> parent layers. It would be nice if there was a flavour of load()
> (perhaps just a boolean flag "includeParentLayers"), which would make
> this a bit simpler. Also, IIUC, the code using the service loader
> needs to have awareness of the fact that it runs within layers, as the
> traditional load() methods wouldn't find any implementations from
> parent layers, which might present a migration obstacle when moving
> existing libraries to layered architectures.
The load(ModuleLayer, service) is specified to load service providers in 
the given layer and its ancestors. That is consistent with the load 
method that takes a ClassLoader as that has always been specified to use 
the class loaders that are reachable via parent delegation.

The stream() method might be useful for the example as you could use a 
filter to selects providers in the desired layer.

What parent class loader do you specify to defineModulesXXXX when you 
are creating the module layers? I'm asking because the traditional 
ServiceLoader.load will locate providers in named modules when the class 
loader specified to the method has modules in a module layer. This goes 
for class loaders that are reachable via parent delegation too. When 
Layrry creates a layer with defineModulesXXXX then it must specify the 
parent class loader for the resulting class loaders. If you choose one 
of the class loaders from the layer parent (any of them will do) then it 
might get more of the traditional usages of ServiceLoader.load working.

-Alan




More information about the jigsaw-dev mailing list