在当今的业务场景中,自动化流程处理已经成为提升效率的关键。作为一名长期从事企业级应用开发的工程师,我发现很多团队在处理短信发送这类看似简单的需求时,往往会陷入代码臃肿、难以维护的困境。今天我要分享的是如何利用LiteFlow这一轻量级流程编排引擎,优雅地实现自动化短信发送功能。
LiteFlow的核心价值在于它能够将复杂的业务逻辑拆解为独立的、可复用的节点组件,通过规则文件来定义执行顺序。这种设计特别适合像短信发送这样需要经过多个步骤(如参数校验、模板渲染、渠道选择、实际发送、结果记录等)的业务场景。相比传统的硬编码方式,使用LiteFlow可以让我们的代码更加清晰、灵活,也更容易应对业务变更。
LiteFlow采用了规则驱动和组件化的设计思想。规则驱动意味着业务流程不再硬编码在Java类中,而是通过外部的规则文件(XML/JSON/YAML)来定义,这使得业务逻辑可以动态调整而无需重新部署。组件化则要求我们将每个业务步骤封装成独立的节点(Node),每个节点只需关注自己的职责,通过上下文(Context)来共享数据。
这种架构带来的直接好处是:
在实际开发中,我们需要理解几个核心概念:
FlowExecutor:流程执行器,是触发流程执行的入口。它负责加载规则、创建上下文、调度节点执行,并收集执行结果。我们可以通过@Autowired直接注入使用。
NodeComponent:所有业务节点都需要继承这个基类。它定义了节点的生命周期方法,最重要的是process()方法,我们在这里实现业务逻辑。节点之间通过上下文共享数据,互不干扰。
LiteflowResponse:执行结果封装,包含了执行是否成功、错误信息、每个节点的执行耗时等详细信息,方便我们进行监控和问题排查。
EL表达式:定义流程的核心语法,支持THEN(顺序执行)、WHEN(并行执行)、IF(条件判断)、FOR(循环)等丰富逻辑。例如"THEN(a, b, c)"表示依次执行a、b、c三个节点。
首先在pom.xml中添加依赖:
xml复制<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.12.4.1</version>
</dependency>
然后创建我们的短信发送节点组件。建议将短信流程拆分为以下几个职责单一的节点:
java复制@LiteflowComponent("validate")
@Slf4j
public class ValidateComponent extends NodeComponent {
@Override
public void process() {
SmsContext context = this.getContextBean(SmsContext.class);
if(!isValidMobile(context.getMobile())){
throw new RuntimeException("手机号格式错误");
}
if(StringUtils.isBlank(context.getContent())){
throw new RuntimeException("短信内容不能为空");
}
}
private boolean isValidMobile(String mobile) {
return mobile != null && mobile.matches("^1[3-9]\\d{9}$");
}
}
java复制@LiteflowComponent("template")
@Slf4j
public class TemplateComponent extends NodeComponent {
@Override
public void process() {
SmsContext context = this.getContextBean(SmsContext.class);
String renderedContent = renderTemplate(context.getTemplateId(), context.getParams());
context.setContent(renderedContent);
}
private String renderTemplate(String templateId, Map<String, String> params) {
// 实际项目中可以从数据库或缓存获取模板
String template = "尊敬的{name},您的验证码是{code},5分钟内有效";
return StrUtil.format(template, params);
}
}
java复制@LiteflowComponent("channelSelect")
@Slf4j
public class ChannelSelectComponent extends NodeComponent {
@Override
public void process() {
SmsContext context = this.getContextBean(SmsContext.class);
// 根据手机号前缀、内容长度等选择渠道
String channel = selectChannel(context.getMobile(), context.getContent());
context.setChannel(channel);
}
private String selectChannel(String mobile, String content) {
// 简单的渠道选择逻辑
return content.length() > 70 ? "channelA" : "channelB";
}
}
java复制@LiteflowComponent("send")
@Slf4j
public class SendComponent extends NodeComponent {
@Autowired
private SmsService smsService;
@Override
public void process() {
SmsContext context = this.getContextBean(SmsContext.class);
SendResult result = smsService.send(context.getMobile(),
context.getContent(),
context.getChannel());
context.setResult(result);
}
}
java复制@LiteflowComponent("log")
@Slf4j
public class LogComponent extends NodeComponent {
@Autowired
private SmsLogMapper logMapper;
@Override
public void process() {
SmsContext context = this.getContextBean(SmsContext.class);
SmsLog log = new SmsLog();
log.setMobile(context.getMobile());
log.setContent(context.getContent());
log.setChannel(context.getChannel());
log.setSuccess(context.getResult().isSuccess());
logMapper.insert(log);
}
}
在resources下创建规则文件liteflow.xml:
xml复制<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="smsFlow">
THEN(validate, template, channelSelect, send, log);
</chain>
</flow>
然后在Service中触发流程执行:
java复制@Service
@Slf4j
public class SmsService {
@Autowired
private FlowExecutor flowExecutor;
public void sendSms(String mobile, String templateId, Map<String, String> params) {
SmsContext context = new SmsContext();
context.setMobile(mobile);
context.setTemplateId(templateId);
context.setParams(params);
LiteflowResponse response = flowExecutor.execute2Resp("smsFlow", null, context);
if (!response.isSuccess()) {
log.error("短信发送失败: {}", response.getMessage());
throw new BusinessException("短信发送失败");
}
}
}
LiteFlow支持从数据库或配置中心动态加载规则,这为我们的短信系统带来了极大的灵活性:
xml复制<chain name="smsFlow">
IF(x, THEN(validate, template, channelSelect, send, log), THEN(validate, template, sendBackup));
</chain>
xml复制<chain name="smsFlow">
IF(switch, THEN(newVersionFlow), THEN(oldVersionFlow));
</chain>
xml复制<chain name="smsFlow">
THEN(validate, template, TRY(THEN(channelSelect, send)).CATCH(THEN(sendBackup)), log);
</chain>
在实际使用中,我们发现以下几点对性能影响较大:
java复制public class SmsContext extends ContextBean {
private String mobile;
private String templateId;
private Map<String, String> params;
private String content;
private String channel;
private SendResult result;
// getters & setters
}
节点拆分粒度:不是越细越好,要根据实际业务场景。像短信这种IO密集型业务,建议将网络请求集中在一个节点中,减少上下文切换开销。
并行执行:对于无依赖的节点可以使用WHEN并行执行:
xml复制<chain name="smsFlow">
THEN(validate, WHEN(template, blacklistCheck), send, log);
</chain>
规则不生效:
上下文数据丢失:
性能瓶颈:
我们为短信流程添加了完善的监控:
java复制@Slf4j
public class SmsMonitor extends AbsSlot {
@Override
public void onSuccess() {
Metrics.counter("sms.success").increment();
}
@Override
public void onError(Exception e) {
Metrics.counter("sms.error").increment();
log.error("短信流程执行异常", e);
}
}
日志规范:
报警机制:
在实际项目中,短信发送往往不是独立存在的,而是与其他业务流程相关联。使用LiteFlow可以轻松实现以下复杂场景:
xml复制<chain name="orderFlow">
THEN(createOrder, checkInventory, WHEN(deductStock, sendOrderSms), payment);
</chain>
xml复制<chain name="notifyFlow">
IF(isSmsEnabled, THEN(sendSms), THEN(sendEmail));
</chain>
xml复制<chain name="smsFlow">
TRY(THEN(validate, sendMain)).CATCH(THEN(sendBackup1)).CATCH(THEN(sendBackup2));
</chain>
经过多个项目的实践验证,LiteFlow在短信这类流程化业务中展现出了极大的优势。它不仅让我们的代码更加清晰可维护,还大幅提升了应对业务变化的灵活性。特别是在需要频繁调整短信模板、发送规则的营销场景中,使用规则文件管理流程可以做到实时生效,无需发版。