What exactly is modularity in the new Java9 features

A significant feature in Java9 is the addition of a new type of programming component, the module.

The official definition of a module is: a named, self-describing collection of code and data. (The Module, which is a named, self-describing Collection of code and data)

This has been proposed in Java7, but because of its complexity, it has been jumping to Java7, Java8, and finally Java9 modularity. What is it and what is the use of it in actual coding?

We mainly analyze it from the following three aspects:

  1. What is modularity
  2. How does modularization work
  3. Why modularity

What is modularity?

Module is a new component in Java9, which can be simply understood as the superior container of package. It is a collection of multiple packages. A JAR can have multiple modules, and a module can have multiple packages. Jar > Module > Package > interface.

Java9 modules declare the modules they rely on and the packages they expose through the requires and exports keywords. This module can only use packages that are exported by other modules, and other modules can only use packages that are exported by this module.

The modularity of Java9 differs from Maven in that Maven manages the dependencies of the entire jar and focuses on the whole. Modularity manages what the modules in the JAR need to expose and what modules they depend on, focusing on the details. Maven relies on giving you the entire JAR, even if you only need one of the classes. Modularized dependencies are more fine-grained package management, where you can only use packages exposed under the modules you depend on.

So, how does modularity work?

We set up a simple modular demo project, which is divided into modular-common, modular-persistent, modular- Service, modular- Web 4 sub-projects.

The four sub-projects are positioned as follows:

Modular -common: general layer, which provides general code for constant classes, utility classes, enumerated classes, etc.

Modular – Persistent: The persistence layer, which mainly provides the database domain entity Domain class and the data manipulation interface DAO.

Modular – Service: Service layer, which mainly provides services and their implementation classes for business logic processing.

Modular – Web: Web layer, which provides API, view rendering, and input and output data processing.

The Maven dependencies of the four sub-projects are:

Modular – persistent rely on modular – common

Modular – service rely on modular – persistent

Modular – web relying on modular – service

The code for each project is roughly as follows:

Unlike traditional Maven projects, each subproject has its own module-info.java, which declares the packages exposed by the project’s modules and the modules they depend on.

Note: Modules in Maven refer to Java9 modules, not maven modules. A module in Maven is a project that can be built as a JAR or war. It is essentially a project. Each subproject can have multiple modules. In the demo, each subproject contains only one module, but it does not mean that there can only be one module.

Module-info.java for the common module

Mon module modular.demo.com {/ / declare themselves exposed outside the package name of exports com.hanmc.example.modulardemo.com mon; }Copy the code

Modular.demo.mon after the module declares the module name and is the unique identifier of the module. Other modules can use this identifier to declare their dependencies on the module.

Exports com.hanmc.example.modulardemo.com mon declares this module exposed out of the package, if all the package are not exposed, if such other modules depend on this module, also will not be able to use this code in the module.

Persistent module module-info.java

module modular.demo.persistent { exports com.hanmc.example.modulardemo.persistent.domain; exports com.hanmc.example.modulardemo.persistent.dao; // Declare the required dependency module requires modular.demo.mon; requires mybatis.plus; requires mybatis.plus.core; requires mybatis.plus.annotation; }Copy the code

Exposing the Domain and DAO packages also declares dependence on modules in the modular- Common and Mybatis – Plus frameworks.

Module-info.java for the service module

module modular.demo.service {
    exports com.hanmc.example.modulardemo.service;
    exports com.hanmc.example.modulardemo.service.impl;
    
    requires modular.demo.persistent;
    requires spring.context;
    requires spring.beans;
}
Copy the code

Exposing the Package Service also declares dependence on modules in the Modular – Persistent and Spring frameworks.

Note: Modular – service module exposes com. Only hanmc. Example. Modulardemo. Service this package, has revealed little. Com hanmc. Example. Modulardemo. Service. Impl this package, Therefore, the implementation class of the Service interface cannot be used externally. It can only be called through the service interface, and the concrete implementation is hidden from the consumer.

Module-info.java for the Web module

module modular.demo.web { requires spring.web; requires spring.beans; requires spring.boot; requires modular.demo.service; requires modular.demo.persistent; requires modular.demo.common; requires org.mybatis.spring; requires spring.boot.autoconfigure; / / statement com. Hanmc. Example. Modulardemo package is open to the spring, Allow spring at run time by reflection mechanism to access the code opens. Com hanmc. Example. Modulardemo to spring. The core of spring. Beans, spring. The boot, spring. The context, spring.web; }Copy the code

It declares dependencies on the Spring framework and modules of modular-common, modular- Persistent, and modular- Service. . At the same time will com hanmc. Example. Modulardemo package open for use by the module of the spring, so that the spring when it starts by reflection mechanism to access the project code to initialize the container.

Note: The difference between exports and exports is that exported packages of exports can access their public members during compilation and runtime. The netanya package can also access its public and private members through reflection at run time.

Why modularity

So why modularity, and what are the benefits of modularity? It looks like writing code is getting more complicated!

Explicitly managing dependencies:

Each module needs to explicitly declare the packages it exposes, and the packages it depends on and uses internally are not exposed or referenced externally. This mechanism completely eliminates the buy-one-get-one-free Jar dependency of Java9 and greatly reduces Jar conflicts.

Scene: For example, my project already relied on hibernate-Validator for parameter verification. In the subsequent development, due to the need of encryption and decryption, I introduced a third-party JAR that provided encryption and decryption API, and this third-party JAR also relied on another version of Hibernate-Validator. Then you have two different versions of hibernate-Validator in your project, and jar package conflicts can occur. In this case, modularization can solve this problem perfectly. The third-party jar can export only the package of its own encryption and decryption function in module-info.java, and not export other JAR packages on which the JAR itself depends.

Strong encapsulation:

Modules explicitly choose to expose only required classes or interfaces to other modules, perfectly hiding internal implementation details and other internal members, achieving true encapsulation.

Scene: For example, the enumeration class DefaultResponseEnum in module-common below defines several built-in response codes because it is defined in the inner package that is not declared exports. So this enumeration class can only be used within module-common, avoiding direct use by other modules.

Security:

Explicit dependency management and strong encapsulation greatly reduce the loading of unnecessary modules when the program is running, and reduce the attack surface during Java running. Code can truly be exposed and hidden as the author designed it, limiting the abuse of reflection and better protecting inner classes that are not recommended for direct external use or that are obsolete.

Standardization:

The content exposed by the display declaration allows third-party library developers to better manage their internal implementation logic and internal classes. Third party library authors can more easily manage their own inner class access permissions and reflection call permissions, avoid sun.misc.BASE64Encoder inner classes have been officially declared obsolete and not recommended to use the premise, there are still a large number of developers to arbitrarily use the situation. Because prior to Java9, JDK developers could only suggest, not enforce, constraints.

Scene: For example, we advocate interface oriented programming, which requires that only the interface of the Service layer can be injected into the Controller, instead of directly injecting its implementation class. However, this requirement is only a specification and cannot be enforced. Before Java9, we can still directly inject the implementation class of the Service layer, and the code can still run as usual. It’s just not that standardized. After Java9, however, we could export only interfaces to service modules, so that controllers could not directly inject implementation classes and would report errors at compile time, implementing strong constraints.

Custom minimum runtime image:

Java, because of its backward compatibility principles, is not easily removed from its content and contains more and more old and outdated technologies, resulting in the JDK becoming increasingly bloated. Java9’s display dependency management makes it possible to load the minimum required modules. We can choose to load only the required JDK modules, discarding modules such as java.awt, Javax. swing, java.applet, and others that are not needed. This mechanism, which greatly reduces the memory resources required to run the Java environment, can be useful for embedded system development or other scenarios where hardware resources are limited.

Incubator module support:

In Java9, the incubator module was introduced with the fixed prefix jdk.incubator. The incubator module is a mechanism that provides an experimental API, which is equivalent to a beta release and may be changed or removed in subsequent releases. The existence of this mechanism allows developers to be aware of its instability and, if they are interested, to try and use these experimental features in advance so that the new features can be refined in the real world.

Scenarios: Such as the JDK.incubator. Httpclient module provided in Java9, which provides a brand new HttpClient API, and incubated in Java11 into the formal pattern java.net.http, which provides high-performance asynchronous non-blocking call support.

This article is for personal study, if there is any wrong description or interested in the relevant content, welcome to comment or private communication, discuss together, common progress.