Simplify Spring Boot Extensions with Concept Plugin 2: A Plug‑in Guide
Concept Plugin 2 introduces a lightweight, annotation‑driven plug‑in system for Spring Boot that separates core business logic from device integration code, enabling independent testing, dynamic loading, and easy configuration through a management UI, while supporting various injection patterns, nested dependencies, and Spring features.
Background
I previously worked at an IoT company where we needed to integrate many devices from different manufacturers. Initially, all integration code lived inside the main service, using some design patterns and a unified interface, so the coding part was manageable.
However, adding a new device or protocol required extensive testing because any code change in the service triggered a full retest, even though only a few classes changed.
I wondered if we could separate the core business from the integration code so that changes to integration plugins wouldn't require retesting the core service. A plug‑in approach would allow independent deployment and quick fixes without republishing the whole service.
Framework Introduction
Based on that idea, the
Concept Plugin 2framework was created.
https://github.com/Linyuzai/concept/wiki/Concept-Plugin-2
Usage
1. Configure plugins in code
<code>@EnablePluginConcept
@Configuration
public class PluginConfig {
@OnPluginExtract
public void plugin(CustomPlugin plugin) {
// CustomPlugin can be any interface or class defined in your business
}
}</code> @EnablePluginConceptenables the plug‑in functionality; can be placed on the main application class.
@OnPluginExtractmarks a method to receive plug‑in callbacks; the method must be discoverable by Spring.
2. Upload plugins via the management page
Management page URL:
/concept-plugin/management.html3. No third step – the above covers everything.
Advantages
Easy to Use
Spring Boot serves as the foundation; a single annotation integrates all features, providing sensible defaults and a ready‑made management UI that anyone from testing to operations can use.
Low Learning Curve
Only two new annotations (
@EnablePluginConceptand
@OnPluginExtract) are needed. The rest follows standard Spring conventions, so developers can start quickly.
<code>@EnablePluginConcept
@Configuration
public class PluginConfig {
@OnPluginExtract
public void plugin(CustomPlugin plugin) {
// implementation
}
}</code>Free Writing Style
You can define plug‑in methods with any signature you need, such as receiving a class, a list, a set, an array, or even a
Propertiesobject:
<code>@EnablePluginConcept
@Configuration
public class PluginConfig {
@OnPluginExtract
public void plugin(Class<? extends CustomPlugin> plugin) { }
@OnPluginExtract
public void pluginList(List<CustomPlugin> plugins) { }
@OnPluginExtract
public void pluginSet(Set<CustomPlugin> plugins) { }
@OnPluginExtract
public void pluginArray(CustomPlugin[] plugins) { }
@OnPluginExtract
public void plugin(CustomPlugin plugin, Properties properties) { }
}</code>Precise Matching
If a plug‑in package contains multiple
Propertiesfiles, you can target them individually with
@PluginEntryusing Ant‑style patterns:
<code>@EnablePluginConcept
@Configuration
public class PluginConfig {
@OnPluginExtract
public void plugin(@PluginEntry("first.properties") Properties p1,
@PluginEntry("second.properties") Properties p2) { }
}</code>Spring Support
The framework integrates with Spring’s configuration binding, allowing you to place a
plugin.propertiesfile in
resourcesor at the root of the zip package. Example configuration:
<code>#custom configuration
custom.app=${spring.application.name}
custom.value=custom</code>During plug‑in execution you can read these values via
PluginMetadata:
<code>@EnablePluginConcept
@Configuration
public class PluginConfig {
@OnPluginExtract
public void plugin(Plugin plugin) {
PluginMetadata metadata = plugin.getMetadata();
String app = metadata.get("custom.app");
String value = metadata.get("custom.value");
CustomData data = metadata.bind("custom", CustomData.class);
}
}
@Data
public static class CustomData {
private String app;
private String value;
}</code>Automatic Injection
Plug‑ins can use Spring’s dependency injection directly, for example:
<code>public class SpringPlugin implements CustomPlugin, ApplicationContextAware {
@Value("${spring.application.name}")
private String applicationName;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}</code>Nested or Dependent Dependencies
If a plug‑in needs classes that are not present in the main service, you have two options:
Package the required JARs inside the plug‑in (nested dependency).
Create a base plug‑in containing common libraries and let other plug‑ins declare a dependency on it via
plugin.properties:
<code># Base plug‑in configuration
concept.plugin.name=common
concept.plugin.handler.enabled=false</code> <code># Dependent plug‑in configuration
concept.plugin.dependency.names=common</code>Visualization Page
A dedicated UI page provides plug‑in upload, download, load, unload, and other basic operations.
Conclusion
For more detailed usage, refer to the Wiki at the GitHub link above.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
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.