Monitoring and Analyzing Modular Applications with JFR & JMX

Illustration for Monitoring and Analyzing Modular Applications with JFR & JMX
By Last updated:

When teams migrate from traditional classpath-based projects to the Java Platform Module System (JPMS), one of the overlooked areas is monitoring and diagnostics. Many developers assume tools like Java Flight Recorder (JFR) and Java Management Extensions (JMX) work seamlessly without modular considerations. The reality? Improperly configured modules often lead to errors like:

  • “package not visible to JFR”
  • “access denied to JMX MBeans”

For cloud-native and enterprise applications, monitoring is as critical as the application itself. Without proper observability, debugging performance issues or memory leaks in modular systems can become a nightmare. This is why understanding how JFR and JMX interact with modules is essential.

Think of JPMS modules like secure office departments. JFR is the security camera, and JMX is the management dashboard. Both need the right keys (exports/opens) to function without breaking encapsulation.


Monitoring with Java Flight Recorder (JFR)

What is JFR?

  • Low-overhead profiling and event collection tool integrated into the JDK
  • Records CPU usage, GC activity, thread contention, class loading, and more

Enabling JFR in Modular Apps

java --module-path mods      --add-exports java.base/jdk.internal.perf=ALL-UNNAMED      -XX:StartFlightRecording=filename=recording.jfr,duration=60s      -m com.example.app/com.example.app.Main

Key Considerations

  • Some internal JDK packages require --add-exports for JFR access
  • Recordings can be analyzed in Java Mission Control (JMC)

Monitoring with Java Management Extensions (JMX)

What is JMX?

  • Framework for monitoring and managing Java applications
  • Exposes MBeans for runtime inspection and operations

Enabling JMX in Modular Apps

java --module-path mods      --add-opens com.example.app/com.example.app.monitoring=java.management      -Dcom.sun.management.jmxremote      -Dcom.sun.management.jmxremote.port=9010      -Dcom.sun.management.jmxremote.authenticate=false      -m com.example.app/com.example.app.Main

Key Considerations

  • Use opens or --add-opens for reflective access to MBeans
  • Avoid exposing sensitive MBeans without authentication in production

Example: Modular Monitoring Setup

module-info.java

module com.example.app {
    requires java.management; // for JMX
    exports com.example.app.api;

    opens com.example.app.monitoring to java.management; // reflective access
}

Main Class

package com.example.app.monitoring;

import javax.management.*;
import java.lang.management.ManagementFactory;

public class MonitoringAgent {
    public static void registerMBean() throws Exception {
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = new ObjectName("com.example:type=AppMonitor");
        server.registerMBean(new AppMonitor(), name);
    }
}

Pitfalls

❌ Forgetting to opens packages → JMX access errors
❌ Using --add-exports excessively → weakens modular encapsulation
❌ Ignoring security when enabling JMX remotely
❌ Mixing classpath and module path in monitoring agents


Best Practices

✅ Use explicit requires java.management for JMX
✅ Export only monitoring-specific APIs
✅ Restrict JMX access with authentication in production
✅ Document runtime flags (--add-exports, --add-opens) in CI/CD pipelines
✅ Use JFR for low-overhead production profiling


What's New in Java Versions?

  • Java 5–8 → N/A (no JPMS)
  • Java 9 → JPMS introduced; JFR integrated into JDK (commercial feature before)
  • Java 11 → JFR open-sourced, widely available
  • Java 17 → Performance and stability improvements in JFR
  • Java 21 → No significant updates across Java versions for this feature

Real-World Analogy

Monitoring modular applications is like installing CCTV cameras (JFR) and dashboards (JMX) in an office building. Without proper keys (exports and opens), the cameras and dashboards can’t access the right rooms. Once configured, they provide visibility without disrupting operations.


Summary & Key Takeaways

  • JFR provides profiling and performance analysis for modular apps
  • JMX exposes MBeans for runtime management and debugging
  • Use --add-exports and --add-opens carefully for monitoring needs
  • Always secure JMX connections in production
  • Modular monitoring requires explicit configuration in module-info.java

FAQ: Monitoring Modular Apps with JFR & JMX

1. What’s the difference between JFR and JMX?
JFR records runtime events, JMX exposes management interfaces.

2. Why do I get “package not visible” errors with JFR?
Because internal JDK packages need --add-exports for access.

3. Why can’t my JMX MBeans be registered?
Because the package wasn’t opened to java.management.

4. Can I use JFR in production?
Yes, it’s low-overhead and designed for production use.

5. Is JMX safe for production use?
Yes, but enable authentication and SSL for remote access.

6. Do I need to modularize monitoring agents?
Yes, agents should declare proper requires and opens.

7. Does JPMS improve monitoring security?
Yes, by enforcing explicit exports and opens for monitoring packages.

8. Can I use ALL-UNNAMED for quick fixes?
Yes, but it weakens modular security—avoid in production.

9. Do frameworks like Spring Boot support JFR and JMX with JPMS?
Yes, but they may need extra --add-opens flags for reflection.

10. Do these flags affect jlink custom runtimes?
Yes, you must include required modules and opens in your runtime image.