Master Java Plugin Architecture: From ServiceLoader to Spring Factories
This comprehensive guide explains how to implement plugin mechanisms in Java and Spring Boot, covering ServiceLoader (SPI), custom configuration with reflection, dynamic JAR loading, and Spring's spring.factories, complete with code examples and practical micro‑service use cases.
1. Introduction
Plugins help decouple modules, improve extensibility, and simplify third‑party integration.
1.1 Benefits of using plugins
Module decoupling
Enhanced extensibility and openness
Easy third‑party integration
2. Common implementation approaches in Java
2.1 ServiceLoader (SPI)
Java's ServiceLoader loads implementations declared in META‑INF/services files.
public interface MessagePlugin {
String sendMsg(Map msgMap);
}
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";
}
}The configuration file META-INF/services/com.example.MessagePlugin lists the implementation class names.
2.2 Custom configuration + reflection
Define a properties file that lists implementation class names, load the file, and instantiate classes via Class.forName.
@ConfigurationProperties("impl")
public class ClassImpl {
private String name;
private String[] clazz;
}2.3 Loading JARs from a directory
Read JAR files from a designated lib folder, create a URLClassLoader, and invoke methods reflectively.
URL url = path.toURI().toURL();
URLClassLoader loader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getMethod("sendMsg", Map.class);
method.invoke(loader, url);3. Spring Boot plugin mechanism
3.1 Spring’s SPI via META-INF/spring.factories
SpringFactoriesLoader scans META-INF/spring.factories to obtain implementations of a given interface.
List<SmsPlugin> plugins = SpringFactoriesLoader.loadFactories(SmsPlugin.class, null);
for (SmsPlugin p : plugins) {
p.sendMessage(msg);
}3.2 Example
Define SmsPlugin interface, two implementations ( BizSmsImpl, SystemSmsImpl), and register them in spring.factories:
com.example.SmsPlugin=\
com.example.SystemSmsImpl,\
com.example.BizSmsImplA controller can invoke all plugins with a single endpoint.
4. Practical case
A micro‑service ( biz‑pp) defines MessagePlugin. Two separate modules ( bitpt and miz‑pt) implement the interface for Aliyun and Tencent SMS. The main service loads the appropriate plugin based on a configuration property and falls back to a default implementation if none is found.
MessagePlugin plugin = PluginFactory.getTargetPlugin(msgType);
if (plugin != null) {
return plugin.sendMsg(params);
}
return defaultSmsService.sendMsg(params);Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
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.
