Tech and Media Labs
This site uses cookies to improve the user experience.

ModRun Tutorial

Jakob Jenkov
Last update: 2016-11-20

ModRun brings modularity to Java without the Jigsaw project. Modularity means the ability to package your applications and APIs as "modules" (JAR files) with extra meta data. The extra meta data tells what version the module (JAR file) is, and which dependencies (other modules in specific versions) your module uses. Having this meta data makes it easier to load your module and its dependencies into the JVM at runtime, as well as resolving dependency conflicts etc.

ModRun GitHub Repository

You can find the ModRun GitHub repository here:

ModRun GitHub Repository

ModRun Uses Maven Repositories

Instead of inventing a new module repository and meta data standard, ModRun uses the tried and tested Maven repository structure. ModRun can load modules directly from a Maven repository at runtime. This means that you can keep all your modules in a local Maven repository and load and run all modules directly from there.

Standardized Run Scripts

When all JAR files are loaded from a Maven repository, the scripts needed to run applications become much more standardized. You just tell what module that contains the main class to run, and ModRun resolves and loads all its dependencies too.

Building the Module Dependency Graph

When ModRun loads a module it builds a dependency graph for the module. The dependency graph contains all immediate and transitive dependencies for the module. This dependency graph can traversed and searched for classes. ModRun does this when loading classes. You can also traverse the dependency graph yourself.

An example module dependency graph

One ClassLoader Per Module

ModRun assigns a separate ClassLoader to every module in the dependency graph. Remember, a module means an application or API in a specific version.

Each module has its own ClassLoader

By loading the classes of a module with its own ClassLoader, ModRun can control what classes are visible to each module. A module can only see the classes from itself or from its dependencies (modules) and transitive dependencies. A module cannot see classes from modules "above" itself in the dependency graph.

By loading each module with its own ClassLoader, ModRun can load the same API in different versions into the JVM at the same time. The JVM will consider classes loaded from the two different versions of the API as different classes because they are loaded with different ClassLoader instances.

A module can be loaded in multiple versions at the same time in the same JVM.

ModRun can also load the same module in the same version multiple times into the same JVM. Each instance of the module have the classes loaded from its dependency graph isolated from the other instances of the same module (at least it can - if you want to).

A module can be loaded multiple times isolated from each other in the same JVM.

Multi Tenancy

Loading the classes from each module with its own ClassLoader makes application multi tenancy easier. Application multi tenancy means having multiple separate applications run within the same JVM at the same time.

ModRun can load multiple applications into the same JVM at the same time, and have their classes be completely isolated from each other, so one application cannot access the classes of another application. ModRun thus provides a simple, secure model for application multi tenancy.

Multiple applications can be loaded into the same JVM while keeping their classes separated.

ModRun Java Example

Here is an example that creates a module from a Maven repository, loads a class from the module, creates an instance of the class and calls a method on the instance via reflection:

Repository repository = new Repository("test-repo");

Module modRunDepA = repository.createModule("com.nanosai", "ModRunDepA", "1.0.0");

String className1 = "com.nanosai.modrun.a.ComponentA";
Class  theClass1  = modRunDepA.getClassFromThisModule(className1);

Object theObject1 = theClass1.newInstance();

Method method1 = theClass1.getMethod("doIt");
String result1 = (String) method1.invoke(theObject1, new Object[0]);

Jakob Jenkov

Copyright  Jenkov Aps
Close TOC