Grails 4.0.3中RabbitMQ消费者调用服务层保存数据库报错求助
问题根因
- 你代码中的
PidService pidService是写在handleMessage方法内部的局部变量,既没有手动初始化,也没有被Spring依赖注入,值为null,调用它的方法自然会触发空指针异常。 - Grails框架的依赖注入仅对类的公开属性生效,方法内的局部变量不会被自动注入实例。
修复方案
1. 调整消费者类的PidService声明位置
把PidService从方法内部移到类的属性层级,和RabbitMessagePublisher同级,框架会自动注入实例:
package br.gov.cmb.pid.consumers import br.gov.cmb.pid.services.PidService import com.budjb.rabbitmq.consumer.MessageContext import com.budjb.rabbitmq.publisher.RabbitMessagePublisher import grails.gorm.transactions.Transactional import org.grails.web.json.JSONObject @Transactional class PidIssuingConsumer { RabbitMessagePublisher rabbitMessagePublisher PidService pidService // 移到类属性层级,框架会自动注入实例 static rabbitConfig = [ queue : "detran.transactions.191.requests" ] JSONObject icomResp def handleMessage(Map body, MessageContext messageContext) { icomResp = new JSONObject().accumulate("status","No response available") // 删掉原来方法内部的PidService pidService声明行 try { icomResp = pidService.sendPidIssuingToIcom(body as JSONObject) publishIcomPidIssuingResponse(icomResp) pidService.saveRenachLog(icomResp.toString()) } catch (Exception e){ pidService.saveRenachLog(e.getLocalizedMessage()) println(e.printStackTrace()) } } def publishIcomPidIssuingResponse(JSONObject pidIssuingResponse){ rabbitMessagePublisher.send { exchange = "detran.requests" routingKey = "191-response" body = [response: pidIssuingResponse] } println(pidIssuingResponse) } // sendPidIssuingToIcom、saveRenachLog方法可以从消费者类中删除 }
2. 确认PidService编写符合要求
确保PidService在指定包下,已经迁移了对应方法并添加了事务注解:
package br.gov.cmb.pid.services import br.gov.cmb.pid.domain.RenachLog import grails.gorm.transactions.Transactional import org.grails.web.json.JSONObject @Transactional class PidService { def sendPidIssuingToIcom(JSONObject pidIssuingDocument){ println(pidIssuingDocument) return pidIssuingDocument } def saveRenachLog(String icomResp){ RenachLog renachLog = new RenachLog() renachLog.transactionId = "191" renachLog.loggedOn = new Date() renachLog.logDescription = icomResp renachLog.save(flush: true, failOnError: true) } }
额外注意事项
- 所有需要依赖注入的Bean(Service、消息发布器等)都需要声明为类属性,不要在方法内部声明
- 如果消费者类不需要全局事务,可以把类上的
@Transactional注解放到需要事务的方法上,减少不必要的事务开销。
内容的提问来源于stack exchange,提问作者D Nunes
相关产品推荐
相关产品推荐

