Wednesday, November 27, 2019
Several traditional ORMs do not fully honor Java module encapsulation (JPMS). This often means a lot of unnecessary files and classes are used when deploying microservices. The latest major release 3.2 of Speedment solves this problem by introducing module system support across the entire product suite, allowing efficient deployment of cloud applications and providing a more stringent API.
The biggest feature in Speedment 3.2 is undoubtedly native support for JPMS. Every module in Speedment now contains its own module-info.java
file and honors strict encapsulation.
As a developer, it is completely optional to use the module system and thanks to its multi-release JARs, Speedment can still be run under Java 8. Users can select to migrate to JPMS now, later or never.
Other ORMs, such as Hibernate, might support parts of JPMS but does not honor strict encapsulation (e.g. requires --add-opens
to be added manually, thereby bypassing protection from accessing internal/protected classes).
The Speedment modules have been internally restructured to reduce inter-module coupling. As a result, some of the modules are now optional, allowing even smaller microservices to be deployed. For example, the various database connectors are now individually pickable and the JoinComponent
is also optional.
The need for several internal modules (such as “lazy” and “mutable-stream”) has been eliminated and some of the others have been optimized and reduced in size.
Thanks to the module system, internal classes are now fully hidden and are even protected from deep-reflection. This strengthens the API (because only intentionally visible classes and methods are accessible) and therefore allows for future migration of internal classes without affecting the public API.
It is possible to create a custom JRE + application + Speedment libraries that is 10 times smaller and that is using 25% less memory compared to running the application under a standard JDK. For companies running a large number of microservices in the cloud, this adds up to a significant difference.
The following example is further described in the article “Java: How to Create Lightweight Database Microservices”. The database application connects to a public MySQL cloud instance of the “Sakila” database with films, actors, etc. It retrieves the ten longest films and prints them on the console in length order.
The custom JRE still has all the bells and whistles of a real JVM like garbage collect, JIT-compiler, etc. It is just the unused modules and tools that have been removed.
final Speedment app = new SakilaApplicationBuilder() .withPassword("sakila") .build(); final FilmManager films = app.getOrThrow(FilmManager.class); System.out.println("These are the ten longest films rated as PG-13:"); films.stream() .filter(Film.RATING.equal("PG-13")) .sorted(Film.LENGTH.reversed()) .limit(10) .map(film -> String.format( "%-18s %d min", film.getTitle(), film.getLength().orElse(0)) ) .forEach(System.out::println);
The application will produce the following output:
These are the ten longest films rated as PG-13: GANGS PRIDE 185 min CHICAGO NORTH 185 min POND SEATTLE 185 min THEORY MERMAID 184 min CONSPIRACY SPIRIT 184 min FRONTIER CABIN 183 min REDS POCUS 182 min HOTEL HAPPINESS 181 min JACKET FRISCO 181 min MIXED DOORS 180 min
Storage requirement for the standard open JDK 11 is 300 MB compared to the custom JRE which only occupies 30 MB (even including the application and the Speedment runtime). Thus, it is possible to reduce the storage requirements by about 90%. When examining heap usage with jmap
, it was concluded that the RAM usage was also reduced by about 25%.
New users can download Speedment 3.2 using the Initializer. Users of Java 11 can select or deselect JPMS depending on their preference. Selecting JPMS will include the proper requirements in a module-info.java
file.
Existing users can just update the Speedment version in their pom.xml
file and re-generate the domain model by issuing the following command:
mvn speedment:generate
For users interested in using the module system, the following module-info.java
file needs to be added to the Java 8+ application’s root:
module your.module.name { requires com.speedment.runtime.application; requires com.speedment.runtime.connector.mysql; // (*) }