Spring观察者模式--publishEvent事件发布处理

Spring发布事件publishEvent 发布-订阅(观察者模式)

一、应用场景

我们一般是在不同的bean之间进行信息传递,比如我们beanA的事件处理完后,需要beanB进行处理一些业务逻辑的时候这种情况就一般可以使用publishEvent解决。(可以用作日志处理)

二、实现原理

ApplicationContext中的事件处理是通过ApplicationEvent类和ApplicationListener接口来提供的,通过ApplicationContext的publishEvent()方法发布到ApplicationListener。

一个事件模型有三个组成部分:被监听对象source(也称为事件源),事件event和监听对象listener。事件发布者在发布事件的时候->通知事件的监听者。

image-20220713175601846

三、事件触发和监听处理过程

(1) 使用 org.springframework.context 包下的 ApplicationContext.publishEvent(ApplicationEvent appEvent) 发布事件。
(2) 使用 org.springframework.context.event 包下的 @EventListener(事件名) 监听事件并处理。

注意:
(1) ApplicationContext.publishEvent 默认是同步操作, 并非发布后不管的异步操作,发布事件后需要等 @EventListener 执行完。
(2) 如果需要开启异步操作需要在@EventListener上增加@Async 注解。

四、简单代码实现(记录操作日志)

1、自定义注解

/**
 * 自定义操作日志记录注解
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperLog {

    /**
     * 模块
     */
    public String title() default "";

    /**
     * 功能
     */
    public String content() default "";

}

2、切面类

/**
 * 操作日志记录处理
 */
@Aspect
@Slf4j
@Component
public class OperLogAspect {

    @Autowired
    private ApplicationContext applicationContext;

    // 配置织入点
    @Pointcut("@annotation(com.lkl.spring.log.annotation.OperLog)")
    public void logPointCut() {
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "logPointCut()")
    public void doAfterReturning(JoinPoint joinPoint) {
        handleLog(joinPoint, null);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e);
    }

    protected void handleLog(final JoinPoint joinPoint, final Exception e) {
        try {
            // 获得注解
            OperLog controllerLog = getAnnotationLog(joinPoint);
            if (controllerLog == null) {
                return;
            }
            // *========数据库日志=========*//
            SysOperLog operLog = new SysOperLog();
            operLog.setTitle(controllerLog.title());
            operLog.setContent(controllerLog.content());

            if (e != null) {
                //日志异常内容记录
            }

            // 发布事件
            applicationContext.publishEvent(new SysOperLogEvent(operLog));
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 是否存在注解,如果存在就获取
     */
    private OperLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(OperLog.class);
        }
        return null;
    }
}

3、自定义事件(继承ApplicationEvent类

/**
 * 系统日志事件
 */
public class SysOperLogEvent extends ApplicationEvent
{
    private static final long serialVersionUID = 8905017895058642111L;

    public SysOperLogEvent(SysOperLog source)
    {
        super(source);
    }
}

4.1、自定义监听器(注解方式 @EventListener(监听某个类)),@Async开启异步处理

/**
 * 异步监听日志事件 注解方式
 */
@Slf4j
@AllArgsConstructor
@Component
public class LogListener {

    @Async
    @Order
    @EventListener(SysOperLogEvent.class)
    public void listenOperLog(SysOperLogEvent event) {
        SysOperLog sysOperLog = (SysOperLog) event.getSource();
        System.out.println("数据库插入操作");
        log.info("远程操作日志记录成功:{}", sysOperLog);
    }

}

主启动类开启异步操作 @EnableAsync

@EnableAsync
@SpringBootApplication
public class SpringApplyApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringApplyApplication.class, args);
    }

}

测试如下:

image-20220713183416866

验证成功

image-20220713183748665

4.2、自定义监听器(实现 ApplicationListener接口

/**
 * 实现 ApplicationListener 接口
 */
@Slf4j
@Component
public class LogListenerOther implements ApplicationListener<SysOperLogEvent> {

    @Override
    public void onApplicationEvent(SysOperLogEvent event) {
        SysOperLog sysOperLog = (SysOperLog) event.getSource();
        System.out.println("数据库插入操作222");
        log.info("远程操作日志记录成功222:{}", sysOperLog);
    }
}

验证成功

image-20220713183933925

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不进大厂不改名二号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值