从上一篇“java自定义函数”已经了解到函数式编程也能做到依赖反转,也已经清晰的看到了监听器模式的编码方式。
下面我们看看这种监听器模式可以有几种写法。
我们以流程引擎处理流程为例
public class ProcessManager {
public void doProcess(Process process, User user) {
// 用户处理流程
System.out.println("流程已正常处理完成");
// 后面可能要发信息通知申请的人
}
}
函数监听器模式
public class ProcessManager {
// 流程成功时的监听器
public static final List<BiConsumer<Process, User>> PROCESS_SUCCESS_LISTENERS = new ArrayList<>();
public void doProcess(Process process, User user) {
// 用户处理流程
System.out.println("流程已正常处理完成");
// 后面可能要发信息通知申请的人,
// 这里将所有的监听器都执行一次,异常情况暂时忽略
PROCESS_SUCCESS_LISTENERS.forEach(l -> l.accept(process, user));
}
}
这样我们可能需要在main函数,或spring启动后,或在外部请求时加入监听者
public static void main(String[] args) {
ProcessManager.PROCESS_SUCCESS_LISTENERS.add((p, u) ->
System.out.println(String.format("用户%s 批准了%s的申请", u.getName(), p.getApplyUser().getName()))
);
}
当ProcessManager.doProcess完毕后,就会调用main函数中注册的函数式代码。
函数式监听器看起来比较没有规范,到处可以使用简短的函数即可添加监听器,而且监听器没有名字。如果我们需要更规范化的定义方式,那其实只需要将BiConsumer使用自定义接口替换即可
Spring bean监听器模式
// 定义接口
public interface IProcessListener {
public void notice(Process process, SecurityProperties.User user);
}
// 定义实现
public class NoticeListener implements IProcessListener {
@Override
public void notice(Process process, SecurityProperties.User user) {
System.out.println(String.format("用户%s 批准了%s的申请", u.getName(), p.getApplyUser().getName()))
}
}
// 修改流程引擎中的定义
// 流程成功时的监听器
public static final List<IProcessListener> PROCESS_SUCCESS_LISTENERS = new ArrayList<>();
如果ProcessManager, NoticeListener 都是spring bean的话
可以使用自动注入
// 流程成功时的监听器
@Autowired
private List<IProcessListener> PROCESS_SUCCESS_LISTENERS;
监听器同步异步执行
spring自带的监听器中对事件的处理,有同异步之分,这里其实也就是把如下代码使用线程池包装一下即可。特别要注意的是线程池的队列配置与拒绝策略,避免异步执行时报错影响主线程。
// 这里将所有的监听器都执行一次,异常情况暂时忽略
PROCESS_SUCCESS_LISTENERS.forEach(l -> l.accept(process, user));