You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:54:03