最近在做项目时,在“发送系统通知”功能模块采用kafka作为消息中间件,使用生产者发送消息时出现空指针异常,后发现与日志记录功能(使用AOP织入)出现冲突,修改后解决问题,具体如下。
版权声明:本文为博主原创文章,禁止转载
作者博客:codesong.cn
created: 2019-12-05
功能描述
项目为一个类似于百度贴吧的社区项目,采用Spring Boot框架。
在评论(comment)、点赞(like)、关注(follow)等高频使用的功能上采用了kafka消息队列,出现以上三种行为时,生产者(producer)会发送一个事件(event)到消息队列中。
触发事件后,生产者将消息以JSON串的格式发送到队列中。在评论、点赞等功能对应的controller加入生产者,部分代码如下:
// 触发评论事件
Event event = new Event()
.setTopic(TOPIC_COMMENT)
.setUserId(hostHolder.getUser().getId()) //用户id
.setEntityType(comment.getEntityType()) //实体类型
.setEntityId(comment.getEntityId()) //实体id
.setData("postId", discussPostId); //帖子id
eventProducer.fireEvent(event); //发送系统通知
报错及原因
启动zookeeper、kafka后启动项目进行测试,在帖子下发表评论,访问数据库发现评论事件没有存在数据库中(没有加入消息队列),且控制台出现如下报错:
kafka报错1
kafka报错2
点击错误信息,发现之前“统一记录日志”功能中,使用AOP织入了日志记录功能:
aop报错
空指针异常出现在attribute对象,attribute是与请求有关的对象,在加入生产者-消费者模型之前,AOP拦截的是service,而所有的service都是通过controller调用的。
加入消费者之后,消费者会调用评论、点赞等service,而不是controller调用了service,因此没有请求(request),此时attribute对象为空,导致报错。
解决方法
在记录日志功能的AOP出现异常的地方,判断当前对象是否为空,如果为空(消费者调用而不是controller调用)就返回
aop报错处理
重新启动项目进行测试,发现数据库中已经能查询到评论、点赞、关注等操作触发的消息事件,说明使用生产者-消费者模式统一发送通知功能已经正确实现,问题解决。
消息事件
因此,在写代码时要多考虑业务的逻辑,思考会不会出现为空的情况。