【问题标题】:Getting NPE while receiving the reply message using RabbitTemplate使用 RabbitTemplate 在接收回复消息时获取 NPE
【发布时间】:2018-05-19 18:00:21
【问题描述】:

我有两个微服务。一个包含具有 Get 方法的 REST 控制器,该方法在发送到特定队列时接收消息。其他微服务只是将回复消息发送到同一个队列,以便在访问 REST API 时可以在浏览器中看到已处理的消息

但是,在接收消息时获取 NPE。 以下是完整的堆栈跟踪:

2018-05-19 15:46:13.409  INFO 30104 --- [nio-8097-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/unit]   : Initializing Spring FrameworkServlet 'dispatcherServlet' 2018-05-19 15:46:13.409  INFO 30104 --- [nio-8097-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started 2018-05-19 15:46:13.443  INFO 30104 --- [nio-8097-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 34 ms 2018-05-19 15:46:13.533  INFO 30104 --- [nio-8097-exec-1] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: [35.154.27.134:5672] 2018-05-19 15:46:13.593  INFO 30104 --- [nio-8097-exec-1] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory#5b2b49d6:0/SimpleConnection@3e4f13fa [delegate=amqp://guest@35.154.27.134:5672/, localPort= 58742] 2018-05-19 15:46:18.681 ERROR 30104 --- [nio-8097-exec-1] o.a.c.c.C.[.[.[.[dispatcherServlet]      : Servlet.service() for servlet [dispatcherServlet] in context with path [/unit] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null
        at com.infy.ci.unitamqpservice.UnitAmqpRestController.getAggregatedDataForSectionOfNightlyBuild(UnitAmqpRestController.java:83) ~[classes!/:0.0.1-SNAPSHOT]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_151]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_151]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.27.jar!/:8.5.27]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151]

此外,当在 Web 浏览器中点击 REST API 时,控制台上会出现以下日志

2018-05-19 15:45:22.328 信息 30023 --- [主要] o.s.j.e.a.AnnotationMBeanExporter : 定位托管 bean 'rabbitConnectionFactory':向 JMX 服务器注册为 MBean [org.springframework.amqp.rabbit.connection:name=rabbitConnectionFactory,type=CachingConnectionFactory] 2018-05-19 15:45:22.423 信息 30023 --- [主要] o.s.c.support.DefaultLifecycleProcessor :分阶段启动 bean 2147483647 2018-05-19 15:45:22.445 信息 30023 --- [cTaskExecutor-1] o.s.a.r.c.CachingConnectionFactory :尝试连接到: [35.154.27.134:5672] 2018-05-19 15:45:22.471 信息 30023 --- [cTaskExecutor-1] o.s.a.r.c.CachingConnectionFactory:已创建 新连接: rabbitConnectionFactory#325fc787:0/SimpleConnection@38a7acf7 [代表=amqp://guest@35.154.27.134:5672/,localPort=58736] 2018-05-19 15:45:22.875 信息 30023 --- [主要] s.b.c.e.t.TomcatEmbeddedServletContainer :Tomcat 在端口上启动: 8099 (http) 2018-05-19 15:45:22.902 信息 30023 --- [主要] com.infy.ci.unitdbamqpservice.RPCServer :在 7.517 中启动 RPCServer 秒(JVM 运行 8.286) 2018 年 5 月 19 日星期六 15:45:23 UTC 警告: 不经过服务器身份验证建立 SSL 连接是 不建议。根据 MySQL 5.5.45+、5.6.26+ 和 5.7.6+ 要求如果显式,则必须默认建立 SSL 连接 选项未设置。为了符合现有的应用程序不使用 SSL 的 verifyServerCertificate 属性设置为 'false'。你需要 通过设置 useSSL=false 显式禁用 SSL,或设置 useSSL=true 并为服务器证书提供信任库 确认。 2018 年 5 月 19 日星期六 15:46:13 UTC 警告:建立 SSL 不推荐没有服务器身份验证的连接。 根据 MySQL 5.5.45+、5.6.26+ 和 5.7.6+ 要求 SSL 如果没有显式选项,则必须默认建立连接 放。为了符合不使用 SSL 的现有应用程序, verifyServerCertificate 属性设置为“假”。你需要要么 通过设置 useSSL=false 或设置 useSSL=true 显式禁用 SSL 和 为服务器证书验证提供信任库。

这可能是 NPE 的原因吗?我已经在 J​​DBC 代码中包含了以下内容,但仍然没有运气。

prop.setProperty("useSSL", "false");
prop.setProperty("autoReconnect", "true");

这两个服务都在 github 上签入:

【问题讨论】:

    标签: spring-amqp


    【解决方案1】:
    return rabbitTemplate.convertSendAndReceive("myExchange", requestQueueName, message).toString();
    

    您在回复时无条件致电toString()

    如果在收到回复之前超过了模板的replyTimeout,则回复将是null(超时默认为5秒)。

    您必须在调用toString() 之前检查null 结果。

    只是将回复消息发送到同一个队列

    您不能将回复发送到同一个队列 - 它必须发送到请求中的 replyTo 标头。

    如果您在服务器端使用@RabbitListenerMessageListenerAdapter,它将为您处理。

    这与 SSL 无关

    警告:不建议在没有服务器身份验证的情况下建立 SSL 连接。根据 MySQL 5.5.45+、5.6.26+ 和 5.7.6+ 的要求,如果未设置显式选项,则默认情况下必须建立 SSL 连接。

    那个警告是关于 MySQL 的。

    编辑

    我刚刚将你的应用程序破解到最低限度,它们对我来说工作得很好......

    @Controller
    @Configuration
    @PropertySource("classpath:/application.properties")
    @RequestMapping("/unittestdata")
    public class UnitAmqpRestController {
    
        private final String requestQueueName = "rpc_queue1";
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    
        private final Logger logger = LoggerFactory.getLogger(UnitAmqpRestController.class);
    
        private final RabbitTemplate rabbitTemplate;
    
        @Autowired
        public UnitAmqpRestController(RabbitTemplate rabbitTemplate) {
            this.rabbitTemplate = rabbitTemplate;
            rabbitTemplate.setReplyTimeout(15_000L);
        }
    
        @RequestMapping(value = "/{projectid}/ut/aggregate",
                method = RequestMethod.GET,
                produces = MediaType.TEXT_HTML_VALUE)
        public @ResponseBody String getAggregatedDataForSectionOfNightlyBuild(@PathVariable("projectid") int projectid,
                @RequestParam("buildtype") String buildtype, @RequestParam("build") String build) throws Exception {
    
            if (build.toLowerCase().equals("latest") && buildtype.equals("nightly")) {
    
                String message = String.format("aggregate");
                logger.info("Sending: " + message);
                Object returned = rabbitTemplate.convertSendAndReceive("", requestQueueName, message);
                logger.info("Reply: " + returned);
                if (returned == null) {
                    throw new RuntimeException("failed to get a response");
                }
                return returned.toString();
    
            }
            else {
                return null;
            }
    
        }
    
    }
    

    @Configuration
    @SpringBootApplication
    @PropertySource("classpath:/application.properties")
    public class RPCServer {
    
        private static final Logger logger = LoggerFactory.getLogger(RPCServer.class);
    
        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            SpringApplication.run(RPCServer.class, args);
        }
    
        private static final String RPC_QUEUE_NAME = "rpc_queue1";
    
        @Bean
        public Queue queue() {
            return new Queue(RPC_QUEUE_NAME);
        }
    
        @Component
        public static class RpcListener {
    
            @RabbitListener(queues = RPC_QUEUE_NAME)
            public String reply(String request) throws IOException, TimeoutException, ClassNotFoundException, SQLException {
                logger.info(request);
                return request.toUpperCase();
            }
    
        }
    
    }
    

    2018-05-20 12:46:00.298  INFO 13369 --- [nio-8097-exec-1] c.i.c.u.UnitAmqpRestController           : Sending: aggregate
    ...
    o.s.amqp.rabbit.core.RabbitTemplate      : Publishing message on exchange [], routingKey = [rpc_queue1]
    2018-05-20 12:46:00.554 DEBUG 13369 --- [nio-8097-exec-1] o.s.amqp.rabbit.core.RabbitTemplate      : Reply: (Body:'AGGREGATE' MessageProperties [headers={}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=amq.rabbitmq.reply-to.g2dkABByYWJiaXRAbG9jYWxob3N0AAAHFAAAAAAC.3M1LyvOdR9dHQehSV4l67A==, receivedDelay=null, deliveryTag=1, messageCount=null, consumerTag=null, consumerQueue=null])
    2018-05-20 12:46:00.561  INFO 13369 --- [nio-8097-exec-1] c.i.c.u.UnitAmqpRestController           : Reply: AGGREGATE
    

    【讨论】:

    • 谢谢 Gary> 你能告诉我如何增加 replyTimeout 吗?请问有任何语法文档吗?此外,您是否建议从上述行中删除 toString() ?我试图删除它,它要求我进行铸造....请建议
    • 此外,我在回复消息时已经在使用@RabbitListener。所以我认为回复同一个队列并不重要。这已经被处理了。你能进一步建议吗?
    • 在这种情况下,您不会向同一队列发送“回复消息”。要更改超时,请参阅RabbitTemplate.setReplyTimeout()。如果您使用的是 Spring Boot,则该属性为 spring.rabbitmq.template.reply-timeout= # Timeout for sendAndReceive() 操作。` - 请参阅 boot properties
    • Task1 :我添加了 RabbitTemplate.setReplyTimeout() 文件并将时间设置为 15000ms 但仍然是同样的问题。 NPE task2:我在发送和接收阶段验证了队列名称相同。任务3:我验证了所有连接并且工作正常。 Mysql连接和rabbit主机连接,但仍然是问题请帮助
    • 仍然在调用toString() 之前没有检查null。为什么要在第二个服务中创建连接工厂和通道?你没有使用它们。 @RabbitListener 看起来不错,只要服务及时回复,应该可以工作。我建议您为两个应用程序打开 DEBUG 日志记录,并按照双方的消息流查看发生了什么。也将一些 DEBUG 日志记录添加到您的代码中(双方)。
    猜你喜欢
    • 2018-06-05
    • 1970-01-01
    • 2016-10-24
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    • 2011-09-04
    • 2012-07-12
    • 1970-01-01
    相关资源
    最近更新 更多