Java modularity: life after Java 9

47
Java Modularity: life after Java 9 @pbakker sdd @Sander_Mak Luminis Technologies

Transcript of Java modularity: life after Java 9

Java Modularity: life after Java 9

@pbakker sdd @Sander_Mak

Luminis Technologies

Today's journey

Modularity matters

Java 9 modularity

JigSaw & OSGi

The Future

Modularity matters

Modularity is the ultimate agile tool

Good fences make good neighbours

Hide your internals!

Service contract

Module

Contracts & Services

MyInterface i = new MyImpl();

How to use code that you can’t access?

Contracts & Services

Provider module

Service Registry

Consumer module

Register service

Lookup service

Inject service

Use an interface as contract

OSGi modularity demo

We don't have inside info

Java 9: JigSaw, JSR-376

History of JigSaw

JSR-277 Java Module System

2005 2006 2011 2014

JSR-294 Improved Modularity Support

Java 7: No JigSaw

Java 8: No JigSaw

JSR-376 Java Platform Module System

JSR-291 'OSGi 4.1'

Goals‣ Modularise the JDK and runtime ‣ Strong encapsulation - hide platform internals ‣ Reliable application composition ‣ Improved performance and security

Current status‣ JDK9 modularised ‣ JSR 376 requirements DRAFT 2 - no prototype yet

Goals‣ Modularise the JDK and runtime ‣ Strong encapsulation - hide platform internals ‣ Reliable application composition ‣ Improved performance and security

Current status‣ JDK9 modularised ‣ JSR 376 requirements DRAFT 2 - no prototype yet

Final

Yesterday

They modularised the JDK without the module system?

So you're telling me...

JEP 200: The Modular JDK

modules.xml

JEP 200: The Modular JDK

JEP 200: The Modular JDK

JEP 200: The Modular JDK

rt.jar & tools.jar gone

Faster startup, lower footprint

JSR-376 modules module myFirstModule @ 1.0.0 { exports com.public.api; requires myOtherModule @ 1.0; }

module-info.java

‣ Dependencies are transitively resolved on modulepath ‣ Versions: ordered, but not semantic ‣ Access control happens deep in VM

(IllegalAccessException)

JSR-376 modules module myFirstModule @ 1.0.0 { exports com.public.api; requires myOtherModule @ 1.0; }

module-info.java

‣ Dependencies are transitively resolved on modulepath ‣ Versions: ordered, but not semantic ‣ Access control happens deep in VM

(IllegalAccessException)

in Jar, or new jmod container

JSR-376 services module myApi @ 1.0.0 { exports com.api; }

JSR-376 services module myApi @ 1.0.0 { exports com.api; }

module myConsumer @ 1.0.0 { requires myApi; requires service com.api.MyService; }

JSR-376 services module myApi @ 1.0.0 { exports com.api; }

‣ Services resolved and wired by modular runtime ‣ Use with 'enhanced' ServiceLoader API

module myConsumer @ 1.0.0 { requires myApi; requires service com.api.MyService; }

module myProvider @ 1.0.0 { requires myApi; provides service com.api.MyService with myProviders.MyServiceImpl; }

JSR-376 services module myApi @ 1.0.0 { exports com.api; }

‣ Services resolved and wired by modular runtime ‣ Use with 'enhanced' ServiceLoader API

module myConsumer @ 1.0.0 { requires myApi; requires service com.api.MyService; }

module myProvider @ 1.0.0 { requires myApi; provides service com.api.MyService with myProviders.MyServiceImpl; }

Iterable<App> apps = ServiceLoader.load(App.class);

for(App app: apps) { render(app); }

JSR-376 linking

Runtime image

jdk.base

jdk.desktop

my.mod1

my.mod2

JVM

JSR-376 linking‣ Use a linking tool (jlink) to create a custom 'runtime

image' with only the modules you need ‣ Uses explicit dependencies from module-info.class ‣ Allows for whole-program optimization

Runtime image

jdk.base

jdk.desktop

my.mod1

my.mod2

JVM

Comparing Jigsaw & OSGi

Module vs package dependencies

‣ Module dependency: depend on a module, no matter what’s in it ‣ Package dependencies still exist in code (imports) ‣ What if a package moves to a different bundle?

‣ Package dependency: depend on a package, no matter where it comes from ‣ Better decoupling

Module vs package dependencies

class

package

module

imports

exports

exports imports

class

package

bundleexports

exports

Java 9 OSGi

imports

imports

Exported packages

‣ Has qualified exports ('permits') ‣ Exported packages only visible to pre-defined 'friend

modules' ‣ Necessary to split up JDK

‣ Multiple modules may export same package ‣ Can re-export packages from imported modules

JigSaw

Services

‣ Services are explicit in module metadata ‣ Service wiring statically verifiable?

JigSaw

OSGi‣ Services wired programmatically ‣ Service dynamics & bundle lifecycle ‣ Services can have properties, filters

‣ Java 9 might include a module index ‣ Maps from annotation to annotated

classes for direct lookup

Classpath scanning

Alternative: register a service, don't rely on classpath scanning

‣ Requiring multiple module versions is common

‣ Breaks in a flat class path

Module versions

MyModule

LoggingLib 2.0

LoggingLib 1.0

SomeLib

‣ OSGi supports this with version ranges

Import-Package: org.slf4j;version=“[1,2)”

Module versions

‣ JSR-376 draft spec states:

“It is not necessary to support more than one version of a module within a single configuration.”

Module versions

‣ Load/unload additional modules at runtime

‣ Alternate module versions in dynamic configurations

Java 9 dynamic configurations

Module versions

‣ Add, remove, update bundles at runtime ‣ Services are inherently dynamic

OSGi

Java 9‣ Dynamic configurations need to be

supported for Java EE ‣ Unclear how

How would the OSGi demo be structured in Java 9/JigSaw?

jdeps carprov.music.jar carprov.music (carprov.music.jar)

-> carprov.dashboard.api carprov.dashboard.api.jar -> java.lang java.base -> java.lang.invoke java.base -> javafx.collections jfxrt.jar -> javafx.event jfxrt.jar -> javafx.geometry jfxrt.jar -> javafx.scene jfxrt.jar -> javafx.scene.effect jfxrt.jar -> javafx.scene.image jfxrt.jar -> javafx.scene.input jfxrt.jar -> javafx.scene.layout jfxrt.jar -> javafx.scene.paint jfxrt.jar -> org.osgi.framework org.osgi.core.jar

module-info.java module carprov.dashboard @ 1.0.0 { exports carprov.dashboard.api requires org.osgi.core @ 5.0 requires service carprov.dashboard.api.App }

module carprov.music @ 1.0.0 { requires carprov.dashboard @ 1.0 requires org.osgi.core @ 5.0 provides service carprov.dashboard.api.App with carprov.music.MusicApp }

... is OSGi too complex?

So that looks simple enough ...

‣ Modularity requires clean design ‣ Import / export declarations are step 1 to

modularity ‣ Services need to be a first class citizen ‣ Reloadable modules come with dynamics

‣ ... which brings some complexity

Modularity isn’t trivial

Is OSGi too complex?

The future

The future - OSGi on top of Java 9?

Interoperation — It must be possible for another module system, such as OSGi, to locate Java modules and resolve them using its own resolver, except possibly for core system modules.

Not all JigSaw concepts map cleanly to OSGi

‣ A future OSGi could use the module definitions of Java 9

‣ Project Penrose: OSGi/JigSaw interop (looks inactive currently)

‣ Jars with module-info.class & OSGi metadata possible

The future - OSGi on top of Java 9?

‣ Use jdeps to audit your code ‣ Escape hatch: -XaddExports:java.base/sun.misc

‣ Java 9: a long way from being complete ‣ Services need more love than just

ServiceLoader (CDI integration?) ‣ Classpath/jars won't die ‣ Will it ever be enough?

The future - state of Java 9

‣ JSR-376 forces module-aware tooling ‣ Modularity throughout all

development phases ‣ Gradual migration possible (other

than with OSGi)

Java 9's promise

‣ JSR-376 forces module-aware tooling ‣ Modularity throughout all

development phases ‣ Gradual migration possible (other

than with OSGi)

Java 9's promise

Spotlight on modularity == good

@pbakker sdd @Sander_Mak

Luminis Technologies

Thank you.

code @ bit.ly/carprov