Plugin Architecture in Java: SPI, ServiceLoader, and Spring Boot Implementations
This article explains the benefits and common practices of plugin‑based development in Java, covering module decoupling, extensibility, third‑party integration, and detailed implementations using Java SPI, custom configuration loading, and Spring Boot's spring.factories mechanism with practical code examples.
Plugin‑based development is widely used in many programming languages and frameworks such as Jenkins, Rancher, IDEA, and VSCode, providing hot‑plug capabilities that greatly improve system extensibility, scalability, and overall value.
Typical Java plugin implementations include the SPI mechanism, convention‑based configuration with reflection, Spring Boot's Factories mechanism, Java agents, built‑in Spring extension points, and third‑party plugin libraries.
ServiceLoader (Java SPI) example: define a common interface public interface MessagePlugin { String sendMsg(Map msgMap); } and two implementations: public class AliyunMsg implements MessagePlugin { @Override public String sendMsg(Map msgMap) { System.out.println("aliyun sendMsg"); return "aliyun sendMsg"; } } public class TencentMsg implements MessagePlugin { @Override public String sendMsg(Map msgMap) { System.out.println("tencent sendMsg"); return "tencent sendMsg"; } } Register the implementations in META-INF/services/com.congge.plugins.spi.MessagePlugin and load them with: ServiceLoader loader = ServiceLoader.load(MessagePlugin.class); for (MessagePlugin p : loader) { p.sendMsg(context); }
Custom configuration loading: a YAML/Properties file lists implementation class names, e.g. impl: name: com.congge.plugins.spi.MessagePlugin clazz: - com.congge.plugins.impl.TencentMsg - com.congge.plugins.impl.AliyunMsg The ServiceLoaderUtils class reads the file, creates a URLClassLoader for each JAR in a designated directory, and uses reflection to invoke sendMsg on the loaded classes.
Spring Boot plugin via spring.factories : define an interface public interface SmsPlugin { void sendMessage(String message); } and two implementations BizSmsImpl and SystemSmsImpl . Add a META-INF/spring.factories entry: com.congge.plugin.spi.SmsPlugin=\ com.congge.plugin.impl.SystemSmsImpl,\ com.congge.plugin.impl.BizSmsImpl Load all implementations with List plugins = SpringFactoriesLoader.loadFactories(SmsPlugin.class, null); for (SmsPlugin p : plugins) { p.sendMessage(msg); } and expose a controller endpoint to trigger the plugins.
The article also presents a complete case study that combines these techniques: a multi‑module Maven project (biz‑pp, bitpt, miz‑pt) where MessagePlugin is defined in a core module, concrete SMS providers implement it, and a PluginFactory selects the appropriate implementation based on configuration. Controllers, services, and Maven dependencies are shown to illustrate how to integrate the plugin system into a real Spring Boot application.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
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.