Lesson 39 • Advanced

    Modular Java (JPMS)

    Before Java 9, any public class was accessible from anywhere — leading to "JAR hell" and accidental dependencies on internal APIs. The Java Platform Module System (JPMS) fixes this with strong encapsulation and explicit dependencies, letting you build large applications that are maintainable and secure.

    Before You Start

    You should know Maven & Gradle (modules are packaged by build tools) and Interfaces (ServiceLoader uses interface-based design). Understanding Reflection helps for the opens directive.

    What You'll Learn

    • ✅ Why modules were introduced in Java 9
    • ✅ module-info.java: requires, exports, provides
    • ✅ Strong encapsulation vs classpath
    • ✅ ServiceLoader and the provides/uses pattern
    • ✅ Creating custom runtime images with jlink
    • ✅ Migration strategies for existing projects

    1️⃣ Module Directives

    Analogy: Think of a module as an apartment building. exports is the lobby — open to visitors. opens is giving someone a master key (reflection access). requires is your utility connections — you declare which services you need.

    DirectiveWhat It DoesExample
    requiresDeclare dependency on modulerequires java.sql;
    exportsMake package visibleexports com.myapp.api;
    opensAllow reflection accessopens pkg to gson;
    provides...withRegister implementationprovides Svc with Impl;
    usesConsume a serviceuses com.myapp.Plugin;

    Try It: Module Encapsulation

    Try it Yourself »
    JavaScript
    // 💡 Try modifying this code and see what happens!
    // Module encapsulation — controlling what's visible
    
    console.log("=== Module Encapsulation ===\n");
    
    // Simulate module system
    class Module {
      constructor(name) {
        this.name = name;
        this.packages = {};
        this.requires = [];
        this.exports = [];
        this.opens = [];
      }
      
      addPackage(name, classes) { this.packages[name] = classes; }
      addRequires(mod) { this.requires.push(mod); }
      addExports(pkg) { this.exports.push(pkg); }
      add
    ...

    2️⃣ ServiceLoader — Plugin System

    Analogy: ServiceLoader is like a power outlet standard. The outlet (interface) defines the shape. Different plugs (implementations) from different manufacturers (modules) all fit the same outlet. Your app discovers and loads all available "plugs" at runtime — zero coupling.

    Try It: ServiceLoader Plugin System

    Try it Yourself »
    JavaScript
    // 💡 Try modifying this code and see what happens!
    // ServiceLoader — dynamic plugin discovery
    
    console.log("=== ServiceLoader Plugin System ===\n");
    
    // 1. Define the service interface (SPI)
    console.log("1. DEFINE SERVICE INTERFACE:");
    console.log("  // In module: com.myapp.spi");
    console.log("  public interface PaymentProcessor {");
    console.log("      String name();");
    console.log("      boolean process(double amount);");
    console.log("  }\n");
    
    // Simulated service interface
    class PaymentProc
    ...

    Common Mistakes

    • ⚠️ Split packages: Two modules can't export the same package — refactor before modularizing
    • ⚠️ Reflection blocked: Frameworks like Hibernate need opens for entity packages
    • ⚠️ --add-opens everywhere: If you're adding many flags, your modularization is incomplete
    • ⚠️ Trying to modularize everything at once: Migrate incrementally — start with automatic modules

    Pro Tips

    • 💡 jlink creates a custom JRE with only your modules — 30MB instead of 300MB, perfect for Docker
    • 💡 jdeps analyzes JARs and tells you which modules they depend on — invaluable for migration
    • 💡 Most libraries work as automatic modules — just put them on the module-path
    • 💡 ServiceLoader is the standard plugin mechanism — define interface, let modules provide implementations

    📋 Quick Reference

    DirectiveSyntaxPurpose
    requiresrequires java.sql;Depend on module
    exportsexports com.app.api;Public API package
    opensopens pkg to framework;Reflection access
    jlinkjlink --add-modulesCustom slim JRE
    jdepsjdeps --module-pathAnalyze dependencies

    🎉 Lesson Complete!

    You understand Java's module system — the key to building large, maintainable applications! Next: Deployment — packaging, Docker, and deploying Java apps to production.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service