spring - Spring Boot 2.0.5 中来自 PrometheusPushGateway 的 @PreDestroy 注释的 BeanCreationNotAllowedException

标签 spring spring-boot spring-integration

我正在使用PushGatewayConfiguration配置 PrometheusPushGateway 时需要进行一些小的更改。

PrometheusPushGateway 设置为在任务结束时通过 @PreDestroy 注释发送指标。在 Spring 2.0.3 中,PushGateway 工作正常,但在 Spring 2.0.5 中,我从 PushGatewayHandler.shutdown() 调用中获取堆栈跟踪。

一般来说,我认为正在发生的事情是在 DefaultSingletonBeanRegistry.destroySingletons() 方法调用期间删除了单例。

我注意到在 2.0.5 中删除了 PushGatewayHandler.push() 所依赖的单例,但在 2.0.3 中并未删除。我正在努力解决这个问题,欢迎提出建议。

堆栈跟踪:

 org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'channelRemoteTaskOut': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:208) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:514) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:502) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1198) [spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.integration.support.management.IntegrationManagementConfigurer.lambda$registerComponentGauges$1(IntegrationManagementConfigurer.java:395) ~[spring-integration-core-5.0.8.RELEASE.jar:5.0.8.RELEASE]
        at io.micrometer.core.instrument.internal.DefaultGauge.value(DefaultGauge.java:40) ~[micrometer-core-1.0.6.jar:1.0.6]
        at io.micrometer.prometheus.PrometheusMeterRegistry.lambda$newGauge$3(PrometheusMeterRegistry.java:230) ~[micrometer-registry-prometheus-1.0.6.jar:1.0.6]
        at io.micrometer.prometheus.MicrometerCollector.lambda$collect$0(MicrometerCollector.java:81) ~[micrometer-registry-prometheus-1.0.6.jar:1.0.6]
        at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:267) ~[na:1.8.0_152-ea]
        at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948) ~[na:1.8.0_152-ea]
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_152-ea]
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_152-ea]
        at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_152-ea]
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_152-ea]
        at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_152-ea]
        at io.micrometer.prometheus.MicrometerCollector.collect(MicrometerCollector.java:82) ~[micrometer-registry-prometheus-1.0.6.jar:1.0.6]
        at io.prometheus.client.CollectorRegistry$MetricFamilySamplesEnumeration.findNextElement(CollectorRegistry.java:183) ~[simpleclient-0.4.0.jar:na]
        at io.prometheus.client.CollectorRegistry$MetricFamilySamplesEnumeration.nextElement(CollectorRegistry.java:216) ~[simpleclient-0.4.0.jar:na]
        at io.prometheus.client.CollectorRegistry$MetricFamilySamplesEnumeration.nextElement(CollectorRegistry.java:137) ~[simpleclient-0.4.0.jar:na]
        at io.prometheus.client.exporter.common.TextFormat.write004(TextFormat.java:22) ~[simpleclient_common-0.4.0.jar:na]
        at io.prometheus.client.exporter.PushGateway.doRequest(PushGateway.java:290) ~[simpleclient_pushgateway-0.4.0.jar:na]
        at io.prometheus.client.exporter.PushGateway.pushAdd(PushGateway.java:171) ~[simpleclient_pushgateway-0.4.0.jar:na]
        at com.build.task.batch.metrics.PushGatewayHandler.push(PushGatewayHandler.java:57) [api-task-batch-2.0.3-SNAPSHOT.jar:2.0.3-SNAPSHOT]
        at com.build.task.batch.metrics.PushGatewayHandler.shutdown(PushGatewayHandler.java:70) [api-task-batch-2.0.3-SNAPSHOT.jar:2.0.3-SNAPSHOT]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_152-ea]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_152-ea]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_152-ea]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_152-ea]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeDestroyMethods(InitDestroyAnnotationBeanPostProcessor.java:324) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeDestruction(InitDestroyAnnotationBeanPostProcessor.java:156) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:240) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:954) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:961) [spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1041) [spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1017) [spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:967) [spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at com.build.task.customer.CustomerAnalyticsApplication.main(CustomerAnalyticsApplication.java:23) [classes/:na]

最佳答案

那个PrometheusMetricsExportAutoConfiguration确实有问题:

(Do not request a bean from a BeanFactory in a destroy method implementation!)

shutdown()调用 push();它执行 DefaultGauge.value()最终,这个与此调用中的 lambda 完全相同:

this.metricsCaptor.gaugeBuilder("spring.integration.channels", this,
            (c) -> this.applicationContext.getBeansOfType(MessageChannel.class).size())
            .description("The number of message channels")
            .build();

根据 Spring Framework 中的修复,我们无法调用 getBean()来自BeanFactory在其毁灭期间。

除非禁用该PrometheusMetricsExportAutoConfiguration,否则我看不到直接修复您的问题的方法。通过management.metrics.export.prometheus.enabled=false并将该类的内容复制/粘贴到您自己的类中并替换 @PreDestroyApplicationListener<ContextClosedEvent> 。这个将在 beans 销毁之前被调用。请参阅AbstractApplicationContext.doClose() :

 try {
            // Publish shutdown event.
            publishEvent(new ContextClosedEvent(this));
        }
        catch (Throwable ex) {
           ...
        }

        // Destroy all cached singletons in the context's BeanFactory.
        destroyBeans();

另外,请针对 Micrometer 项目提出问题,以在 PrometheusMetricsExportAutoConfiguration 中解决此问题。我为您建议的方式。

关于spring - Spring Boot 2.0.5 中来自 PrometheusPushGateway 的 @PreDestroy 注释的 BeanCreationNotAllowedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52785517/

相关文章:

java - Spring Cloud Stream 验证

spring-boot - 启动期间未调用自定义 HealthIndicator

java - Spring 集成 AbstractReplyProducingMessageHandler doInit 与 onInit

java - Spring Integration 通过控制总线手动启动/停止 channel 适配器

java - 使用 Spring Security ACL - 如何将对象的 READ 权限分配给所有用户(注册和匿名)?

java - Spring Security OAuth2 纯资源服务器

java - 异步进行一些调用并立即从 Spring Controller 返回

java - Spring Integration 4.1.0 迁移问题

java - @ExceptionHandler 没有捕获 HttpMessageNotReadableException

java - 超时动态 HTTP 出站网关请求工厂