Skip to content
Daniel Meinicke edited this page Apr 30, 2025 · 2 revisions

πŸš€ Welcome to JPlugin

πŸ“ Summary

JPlugin is a lightweight, annotation-driven Java plugin framework that empowers developers to build modular, extensible applications with ease. By simply annotating your classes, JPlugin automatically discovers, initializes, and manages plugin lifecycle, freeing you from boilerplate code and complex wiring. Whether you're building microservices, game mods, or dynamic feature toggles, JPlugin provides a flexible foundation.


πŸ’‘ Quick Start Example

package com.myapp.plugins;

import dev.meinicke.plugin.annotation.Plugin;
import dev.meinicke.plugin.main.Plugins;
import java.io.Closeable;

// This class can be package-private also.
@Plugin(name = "GreetingPlugin", description = "Says hello and goodbye")
public class GreetingPlugin implements Closeable {
    // This can be private, public, package-private or protected!
    public GreetingPlugin() {
        System.out.println("πŸ‘‹ Hello from GreetingPlugin!");
    }
    //public GreetingPlugin(PluginContext context) {
    //    this();
    //    System.out.println("Context: " + context);
    //}
    
    @Override
    public void close() {
        System.out.println("πŸ‘‹ Goodbye from GreetingPlugin!");
    }
}

public class MainApp {
    public static void main(String[] args) {
        // Scan package and initialize all plugins
        Plugins.initialize("com.myapp.plugins", true);

        // Can also load plugins using the plugin finder (recommended way)
        // Plugins.find().addPackage("com.myapp.plugins").load();
        
        // The manual shutdown is NOT NECESSARY, the framework already does that.
        // Runtime.getRuntime().addShutdownHook(new Thread(Plugins::shutdownAll));
    }
}

πŸ” Detailed Explanation ✨

1. Annotation-Based Discovery πŸ•΅οΈβ€β™‚οΈ

JPlugin uses annotations to automatically find and configure plugins at runtime:

  • @Plugin 🏷️: Marks a class as a plugin entry point. Every plugin must have this annotation.
  • @Dependency πŸ”—: Declare other plugin classes that must be loaded before this one. Supports multiple dependencies.
  • @Category πŸ“‚: Group related plugins under a named category. You can register category-wide handlers that apply to all plugins in that category.
  • @Priority πŸ”’: Fine-tune load order for plugins without direct dependencies. Lower values load first; @Priority without a value defaults to -1 (highest priority).
  • @Attribute πŸ—οΈ: Attach custom key/value metadata at compile-time. Use this to control:
    • Initialization/interruption method name for method plugin initialization (e.g., "start" and "shutdown");
    • Arbitrary plugin-specific settings (e.g., "timeout", "maxRetries").

2. Flexible Initialization Strategies πŸš€

Choose how your plugin starts up using built-in initializers, or write your own:

  • ConstructorPluginInitializer πŸ—οΈ: Invokes either a no-arg constructor or a (PluginContext) constructor β€” whichever is present (context constructor takes priority).
  • StaticPluginInitializer πŸ›οΈ: Relies solely load class (so you can use the class static {} block); no instance is created.
  • MethodPluginInitializer πŸ”§: Invokes a static method for startup and shutdown:
    • Default init: initialize() or initialize(PluginContext) and may return the instance object;
    • Default interrupt: interrupt() or interrupt([instance]);
    • Overrides: Rename methods via @Attribute (keys "initialization method" / "interruption method").

3. PluginContext & Configuration 🧩

During initialization, JPlugin provides a rich context to your plugin:

  • PluginContext πŸ—ƒοΈ:
    • getPluginClass() β€” the actual plugin Class<?>.
    • getCurrentBuilder() and getAllBuilders() β€” view and modify pending PluginInfo.Builder instances before build.
    • getMetadata() β€” mutable runtime metadata from plugins to easily control custom data for plugins.
    • getAttributes() β€” mutable compile-time key/value store for plugin data, normally created using @Attribute annotation.
    • getCallerClass() β€” the class that triggered initialization.
    • getFinder() β€” the PluginFinder used, if the plugin is loaded/loading by one.

Notes

  1. Use Attribute to read annotation values, and Metadata to store or update settings (e.g., themeColor, cacheSize).
  2. Both Attributes and Metadata are mutable, but the attributes have fixed value types, you cannot use any object on it, it's not recommended to use attributes to hold plugin data, just configurations.

4. Lifecycle Management πŸ”„

Plugins go through a well-defined lifecycle:

  1. IDLE πŸ’€ β€” discovered but not yet started.
  2. STARTING ⏳ β€” running initialization code.
  3. RUNNING 🟒 β€” active and operational.
  4. STOPPING βš™οΈ β€” running shutdown/interrupt logic.
  5. FAILED ❌ β€” indicates a failure when the plugin tried to start.

Transitions fire PluginHandler(s) (interfaces or annotated methods) for hooks:

  • Automatic cleanup: invokes close() (if Closeable) or flush() (if Flushable). > only available in some initializers like method or constructor initializers.
  • Custom shutdown: static interrupt methods or PluginHandler implementations.

5. Extensibility & Customization 🎨

JPlugin is built for extension:

  • Implement custom initializers by creating classes that implement PluginInitializer and return specialized PluginInfo.Builder logic.
  • Use category handlers (PluginHandler) to apply cross-cutting behavior to all plugins in a category.
  • Integrate DI frameworks, configuration services, or event buses via PluginContext β€” access any central services during initialization.

With these tools, JPlugin adapts to microservices, game engines, enterprise modules, or dynamic feature flips with ease! πŸŽ‰


🌐 Possible Applications

  • Modular Web Servers: Dynamically load route plugins or middleware at runtime.
  • Game Modding: Easily add gameplay features without restarting the engine.
  • Enterprise Extensions: Allow clients to drop custom business logic modules.
  • Feature Toggles: Swap feature implementations using plugin-based strategies.
  • Testing Harnesses: Isolate test modules as plugins, loaded on demand.

πŸŽ‰ Conclusion

JPlugin offers a unified, annotation-first approach to building Java plugins. With minimal setup and powerful APIs, you can focus on business logic while the framework handles discovery, initialization, and cleanup. Join the community, contribute, and elevate your Java applications!