Java的spring事件监听模型还是很好用的。这里主要讲监听器的注解的使用方式。
最重要的有俩种注解
| 作用 | 适用场景 | ||
|---|---|---|---|
@EventListener |
标记方法为事件监听器 | 通用事件监听,*(非事务) | |
@TransactionalEventListener |
事务相关的事件监听 | 需要事务绑定的事件(事务) |
对于@EventListener,有三个参数
value、classes、condition
value和classes主要是指定相关事件的
condition是最常用的,使用Spring Expression Language (SpEL) 实现动态过滤。.
SpEL 表达式可以访问以下变量:
| 变量名 | 等价形式 | 说明 |
|---|---|---|
#root.event |
event |
当前事件对象 |
#root.args |
args |
方法参数数组 |
#a0, #p0 |
args[0] |
第一个参数 |
#a1, #p1 |
args[1] |
第二个参数 |
#orderEvent |
参数名为 orderEvent 的参数 |
也可以动态的注册一个spel函数
java
public static boolean calculateLength(int type, String article) {
//通过枚举解析type
//解析长度
}
讲其注入到context中去
java
static class SpelFunctionRegister implements BeanFactoryAware, ApplicationContextAware {
@Override
public void setBeanFactory(BeanFactory beanFactory)
throws BeansException {
// 注册自定义函数
StandardEvaluationContext context =
((StandardEvaluationContext)
beanFactory.getBean(StandardEvaluationContext.class));
try {
// 注册一个计算评论内容的函数
context.registerFunction("calculateLength",
CustomSpELFunctions.class.getDeclaredMethod(
"calculateLength",
Integer.class, String.class));
} catch (NoSuchMethodException e) {
throw new RuntimeException("注册SpEL函数失败", e);
}
}
}
java
@EventListener(condition =
"#calculatLenth(#event.commentType, #event.article)")
public void handleDiscountOrder(OrderEvent event) {
//符合评论类型、评论内容
}
实际项目更常用的还是@TransactionalEventListener
它将事件监听与数据库事务的生命周期绑定,解决了"何时触发事件处理"这个关键问题。
退可当普通监听器使用,进可处理事务相关的监听,
定义了四个参数
1:phase(重要参数) :以下四个策略
java
public enum TransactionPhase {
// 四个关键阶段
BEFORE_COMMIT, // 事务提交前
AFTER_COMMIT, // 事务提交后(默认)是最常用的
AFTER_ROLLBACK, // 事务回滚后
AFTER_COMPLETION // 事务完成后(无论成功失败)
}
2**:value() 就是指定监听具体的事件的,含义差不多
3: classes() 就是指定监听具体的事件的,含义差不多**
4:condition() 与@EventListenner差不多一个东西
为什么说@EventListener在实际项目好像使用的更多一点,平时写代码不怎么使用这玩意呢
1:大部分表的update、delete、add肯定都会用事务进行包装,而对于这些增删改操作又会涉及到一系列的问题。比如清理缓存、一致性补偿、异步编排等等十分常见,将代码解耦合。对于实际项目的一个接口而言代码过长不利于扩展、理解以及数据的正确性
2:清理多节点本地缓存也十分常用,对于多节点的分布式系统而言,不可能都采用的远程缓存来做,必然有很多的本地缓存,或者是本地+远程远程来做的,如果涉及到缓存数据相关业务数据的变更,如果我只在当前节点进行清理缓存,那么其他节点就有可能有脏数据的问题,如果缓存时间还长,那线上环境的影响是很大的。比如清理所有节点的更新的业务缓存数据。对于采用了本地缓存的业务,在业务变更需要进行publis事件来清除缓存是最高效的。