Master Java SPI: Build a Pluggable Authentication System with Spring Boot
This article explains Java's Service Provider Interface (SPI), compares it with traditional APIs, and provides a step‑by‑step guide to create a multi‑module Maven project, custom class loader, and Spring Boot application that dynamically loads authentication plugins from external JARs.
What is Java SPI
Java SPI (Service Provider Interface) is a service discovery mechanism that allows developers to define multiple implementations for an interface and load them dynamically at runtime.
Core Mechanism
Implementations are placed under META-INF/services with a file named after the interface's fully‑qualified name containing the implementation class name. At runtime the JVM scans this directory, loads the classes and provides them to the caller.
Typical Uses
Provides extension points for frameworks or libraries without changing business code.
Enables dynamic insertion or replacement of components, encouraging loose coupling.
Allows third‑party plugins to replace core library components, increasing flexibility of the Java ecosystem.
SPI vs API
Key differences include definition method, invocation style, flexibility, dependency direction and purpose.
API is written by developers and exposed directly; SPI is defined by a framework for third‑party implementation.
API calls methods directly; SPI uses configuration files and the framework loads implementations automatically.
API implementations are fixed at compile time; SPI implementations can be swapped at runtime.
API callers depend on the library; SPI callers depend on the framework that loads providers.
API describes a contract; SPI provides a plug‑in architecture for dynamic discovery.
Implementation Steps
Create a parent Maven project sa-auth and three sub‑modules: sa-auth-bus, sa-auth-plugin, sa-auth-plugin-ldap.
Define the SPI interface AuthPluginService in sa-auth-plugin.
Provide a default implementation DefaultProviderImpl in the bus module.
Implement a third‑party provider LdapProviderImpl in sa-auth-plugin-ldap.
Place a file
META-INF/services/com.vijay.csauthplugin.service.AuthPluginServicein each module containing the fully‑qualified name of the implementation class.
Package the LDAP module as a JAR and treat it as an external plugin.
Write a custom class loader PluginClassLoader that can add URLs at runtime.
Write ExternalJarLoader to scan a directory, collect all .jar files and set the custom class loader as the thread context loader.
In the Spring Boot entry point, call ExternalJarLoader.loadExternalJars(...) before starting the application.
Create PluginProvider that uses ServiceLoader to obtain the first non‑default provider, falling back to the default one.
Expose the selected AuthPluginService as a Spring bean in PluginConfig.
Add a REST controller TestController that returns the provider name and the result of a login test.
Running the Demo
When the application starts without external JARs, the default provider is used and the endpoint returns DefaultProvider and a successful login for the hard‑coded credentials.
After copying the cs-auth-plugin-ldap JAR into the external plugin directory and restarting, the endpoint returns LdapProvider and the same login result, demonstrating that the SPI mechanism successfully loads the third‑party implementation.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
