Decoupling Java Business Logic with Spring Event: A Hands‑On Example
Learn how to use Spring's Application Event mechanism to separate main and sub‑processes in Java applications, covering custom event and listener creation, publishing events, abstract base event design, singleton manager, and a real‑world order‑cancellation SMS notification case.
Background
In many Java business applications the main flow and auxiliary sub‑processes are tightly coupled, making the code hard to maintain and slowing down the response time of the primary request. Typical sub‑processes such as sending SMS, email, or Feishu notifications can be decoupled from the main transaction.
Spring Event Mechanism
Spring Event (Application Event) implements the Observer design pattern: a bean can publish an event after completing a task, and other beans can listen for that event. This allows asynchronous or loosely‑coupled handling of side‑effects.
2.1 Custom Event
@Data
@ToString
public class SendMessageToUserEvent extends ApplicationEvent {
/** 该类型事件携带的信息 */
private String userId;
public SendMessageToUserEvent(Object source, String userId) {
super(source);
this.userId = userId;
}
}2.2 Custom Listener
@Slf4j
@Component
public class UserMessageSendListener implements ApplicationListener<SendMessageToUserEvent> {
/** 使用 onApplicationEvent 方法对消息进行接收处理 */
@Override
public void onApplicationEvent(SendMessageToUserEvent event) {
String userId = event.getUserId();
long start = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
log.info("{}:事件处理完成:({})毫秒", userId, (end - start));
}
}2.3 Publishing the Event
@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {
/** 注入ApplicationContext用来发布事件 */
private final ApplicationContext applicationContext;
/** 下单 */
public String buyOrder(String orderId) {
long start = System.currentTimeMillis();
// 1.查询商品数据
// 2.校验价格
// 3.组装参数
// 4.保存订单数据入库
// 5.短信通知 (同步处理)
String userId = UserContextHolder.getUserId();
applicationContext.publishEvent(new SendMessageToUserEvent(this, userId));
long end = System.currentTimeMillis();
log.info("完成,总耗时:({})毫秒", end - start);
return "成功";
}
}In practice the @EventListener, @EnableAsync and @Async annotations can be combined to make the handling fully asynchronous.
2.4 Extension Directions
Introduce an async thread pool (e.g., enable with @EnableAsync) so that event handling runs in separate threads, improving the main flow's response time.
Mark a method with @EventListener to turn it directly into an event listener, simplifying registration.
Second‑Level Event Encapsulation
3.1 Base Event Class
/**
* 商城事件基础类,基于Spring Event
* @date 2023-01-04
*/
public class BasicMallEvent extends ApplicationEvent implements MallEvent {
public BasicMallEvent(Object source) {
super(source);
}
}3.2 Abstract Event Listener
/**
* 商城事件抽象配置的统一处理的监听器
* @date 2023-01-04
*/
public abstract class AbstractMallEventListener implements ApplicationListener<BasicMallEvent> {
public AbstractMallEventListener() {}
@Override
public void onApplicationEvent(BasicMallEvent event) {
if (supportsEventType(event.getClass())) {
this.doMallEvent(event);
}
}
/** 判断子类的事件类型是否匹配 */
public abstract boolean supportsEventType(Class<? extends BasicMallEvent> eventType);
/** 为子类暴露新的事件方法 */
protected abstract void doMallEvent(BasicMallEvent event);
}3.3 Event Manager (Singleton)
/**
* 商城事件发布管理器
* @date 2023-01-04
*/
public class MallEventManager {
private static final MallEventManager INSTANCE = new MallEventManager();
private MallEventManager() {}
public static MallEventManager getInstance() {
return INSTANCE;
}
/** 统一发布事件 */
public void publishEvent(BasicMallEvent mallEvent) {
SpringContextUtil.getContext().publishEvent(mallEvent);
}
}The singleton pattern provides a global entry point for publishing events, avoiding the need to inject multiple services across the code base.
3.4 Real‑World Use Case: Order‑Cancellation SMS
MallEventManager.getInstance().publishEvent(new OrderCancelApplyNotifyEvent(this, orders));OrderCancelApplyNotifyEvent extends BasicMallEvent and carries the order information needed for the SMS notification. The caller simply obtains the manager instance and publishes the event, keeping the main order‑cancellation logic untouched.
Conclusion
By leveraging Spring's Application Event mechanism, developers can isolate sub‑processes such as notifications from the core business flow. When a sub‑process changes, only the corresponding listener needs modification, reducing merge conflicts and improving extensibility.
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.
Ubiquitous Tech
A ubiquitous public account for pirate enthusiasts, regularly sharing curated experiences, tech learning, and growth insights. Currently publishing articles on AI RAG customer service, AI MCP technology, and open-source design. Personal free Knowledge Planet: Awakening New World Programmer.
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.
