How to Build Custom smart-socket Plugins to Extend Framework Functionality
This article walks through the smart-socket plugin system, explaining the Plugin interface, its lifecycle, the AbstractPlugin base class, and step‑by‑step examples for creating message‑filter, connection‑limit, and heartbeat plugins, followed by registration, execution order, and best‑practice recommendations.
Plugin Interface and Lifecycle
Plugin<T> extends NetMonitor and defines two extension points: preProcess (called before MessageProcessor; returning false drops the message) and stateEvent (listens to state‑machine events such as session creation and closure).
public interface Plugin<T> extends NetMonitor {
boolean preProcess(AioSession session, T t);
void stateEvent(StateMachineEnum stateMachineEnum, AioSession session, Throwable throwable);
}AbstractPlugin
AbstractPlugin<T> implements Plugin<T> with default implementations that return true for preProcess and perform no operation for stateEvent. All other NetMonitor methods have empty bodies, allowing developers to override only the needed methods.
public abstract class AbstractPlugin<T> implements Plugin<T> {
@Override
public boolean preProcess(AioSession session, T t) { return true; }
@Override
public void stateEvent(StateMachineEnum state, AioSession session, Throwable throwable) { }
// other NetMonitor methods have empty implementations
}Plugin Lifecycle
Connection acceptance – shouldAccept decides whether to accept a new connection.
Session creation – stateEvent receives NEW_SESSION.
Message handling – preProcess can filter or modify messages.
Session closure – stateEvent receives SESSION_CLOSED.
Custom Function Plugins
Message Filter Plugin
public class MessageFilterPlugin<T> extends AbstractPlugin<T> {
private final Set<String> forbiddenWords;
public MessageFilterPlugin(Set<String> forbiddenWords) {
this.forbiddenWords = forbiddenWords;
}
@Override
public boolean preProcess(AioSession session, T message) {
if (message instanceof String) {
String msg = (String) message;
for (String word : forbiddenWords) {
if (msg.contains(word)) {
System.err.println("Found illegal message: " + msg + ", contains keyword: " + word);
return false; // drop the message
}
}
}
return true; // allow processing
}
}Connection Limit Plugin
public class ConnectionLimitPlugin<T> extends AbstractPlugin<T> {
private final int maxConnections;
private final AtomicInteger currentConnections = new AtomicInteger(0);
public ConnectionLimitPlugin(int maxConnections) {
this.maxConnections = maxConnections;
}
@Override
public AsynchronousSocketChannel shouldAccept(AsynchronousSocketChannel channel) {
if (currentConnections.get() >= maxConnections) {
System.err.println("Connection limit reached: " + maxConnections);
try { channel.close(); } catch (IOException e) { e.printStackTrace(); }
return null; // reject connection
}
currentConnections.incrementAndGet();
return channel;
}
@Override
public void stateEvent(StateMachineEnum state, AioSession session, Throwable throwable) {
if (state == StateMachineEnum.SESSION_CLOSED) {
currentConnections.decrementAndGet();
}
}
}Heartbeat Detection Plugin
Extend the built‑in HeartPlugin to customize heartbeat request generation and detection.
processor.addPlugin(new HeartPlugin<String>(5, 7, TimeUnit.SECONDS) {
@Override
public void sendHeartRequest(AioSession session) throws IOException {
WriteBuffer writeBuffer = session.writeBuffer();
byte[] content = "heart message".getBytes();
writeBuffer.writeInt(content.length);
writeBuffer.write(content);
}
@Override
public boolean isHeartMessage(AioSession session, String msg) {
return "heart message".equals(msg);
}
});Plugin Registration and Execution Order
Plugins are registered with a MessageProcessor via addPlugin. Execution follows the registration order; the first added plugin runs first. If any plugin's preProcess returns false, subsequent plugins are skipped and the message is not delivered to the processor.
processor.addPlugin(plugin1); // first
processor.addPlugin(plugin2); // second
processor.addPlugin(plugin3); // thirdExample Registration
public class PluginRegistrationExample {
public static void main(String[] args) throws IOException {
MessageProcessor<String> processor = new AbstractMessageProcessor<String>() {
@Override
public void process0(AioSession session, String msg) {
System.out.println("Processing message: " + msg);
}
@Override
public void stateEvent0(AioSession session, StateMachineEnum state, Throwable throwable) {}
};
processor.addPlugin(new MessageFilterPlugin<>(Set.of("badword1", "badword2")));
processor.addPlugin(new ConnectionLimitPlugin<>(100));
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();
}
}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.
Three Knives
Every line of code you contribute to open source could help make the future better.
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.
