Memra

provides/uses (ServiceLoader) and opens for reflection

◈ 4 cards

Decoupling implementations with services, and granting reflective access with opens.

The ServiceLoader pattern

JPMS has built-in support for service-provider decoupling. A consumer module declares the interface it needs:

module com.acme.app {
    uses com.acme.spi.PaymentProcessor;
}

A provider module declares the implementation:

module com.acme.stripe {
    requires com.acme.app;
    provides com.acme.spi.PaymentProcessor
        with com.acme.stripe.StripeProcessor;
}

At runtime, ServiceLoader.load(PaymentProcessor.class) discovers all provider modules on the module path without the consumer knowing the implementation class:

ServiceLoader<PaymentProcessor> loader =
    ServiceLoader.load(PaymentProcessor.class);
for (PaymentProcessor p : loader) {
    p.charge(amount);
}

The consumer and provider are loosely coupled — swap providers by changing which jar is on the module path, with no code changes.

opens — granting reflective access

Reflection can read private members, but JPMS blocks it by default even for exported packages. The opens directive grants reflective access:

module com.acme.app {
    opens com.acme.app.model;             // reflection allowed by all
    opens com.acme.app.model to java.base; // qualified — only java.base
}

An open module (open module com.acme.app { ... }) opens every package for reflection — useful during migration. Frameworks like Hibernate and Spring use reflection heavily and often require opens on your entity/component packages.

usesimplementscom.acme.appusesPaymentProcessorthe interfacecom.acme.stripeprovides … withServiceLoader.load supplies the arrow at runtime.
The missing arrow is the point: com.acme.app never names com.acme.stripe, so swapping the provider jar on the module path changes no code.
directivecompile-time public APIreflection on privateexports Pyesnoopens Pnoyesexports P + opens Pyesyes
exports and opens are independent grants. A framework that reads private fields needs opens; a caller that writes code against your types needs exports.
NORMAL ~/memra/learn/java-from-zero/services-and-opens utf-8 LF