将springboot执行器与Prometheus和RestTemplate一起使用时,Bean名称“prometheusMeterRegistry”出现循环引用错误

xxe27gdn  于 2023-02-28  发布在  Spring
关注(0)|答案(1)|浏览(455)

我发现“prometheusMeterRegistry”bean当前处于创建错误状态(请参阅下面的确切堆栈跟踪)当使用Prometheus与springboot执行器沿着RestTemplate时。这似乎是由于当与RestTemplate/Builder一起使用时循环引用prometheusMeterRegistry,RestTemplate/Builder在我的应用程序和springboot依赖性库中自动连接。我已经花了三天的时间来分析和修复这个问题,并参考了几个论坛提供的解决方案,但没有运气。我在服务器启动时得到这个错误,但令人惊讶的是/actuator/promethus url在我的本地运行良好,但当然没有API细节,因为restTemplate由于PrometheusMeterRegistry而存在一些依赖注入问题。(我试图部署在服务器上,因为它是在本地工作,除了有启动错误),由于启动时出错,应用程序无法成功部署到内置的Tomcat服务器上。请分享您对如何解决此问题的想法。

错误堆栈跟踪:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'metricsRestTemplateCustomizer' defined in class path resource [org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.class]: Unsatisfied dependency expressed through method 'metricsRestTemplateCustomizer' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prometheusMeterRegistry': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1616)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1573)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1417)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1349)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.resolveStream(DefaultListableBeanFactory.java:2119)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.orderedStream(DefaultListableBeanFactory.java:2113)
    at org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.restTemplateBuilderConfigurer(RestTemplateAutoConfiguration.java:61)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 140 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prometheusMeterRegistry': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:355)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:227)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1391)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)

正如在一些论坛中建议的那样,我也配置了below属性来打破循环引用,它在打破循环引用时工作得很好,因为它是预期的,但我在启动时再次得到不同的错误。
属性条目:

spring.main.allow-circular-references=true

错误堆栈跟踪:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'healthRegistryCustomizer' defined in class path resource [org/sample/monitor/MeterConfig.class]: Unsatisfied dependency expressed through method 'healthRegistryCustomizer' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.actuate.health.HealthContributorRegistry' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at app//org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
    at app//org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
    at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
    at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
    at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
    at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    at app//org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at app//org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at app//org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at app//org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at app//org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1616)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1573)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1417)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1349)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.resolveStream(DefaultListableBeanFactory.java:2119)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.orderedStream(DefaultListableBeanFactory.java:2113)
    at app//org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryConfigurer.asOrderedList(MeterRegistryConfigurer.java:90)
    at app//org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryConfigurer.customize(MeterRegistryConfigurer.java:77)
    at app//org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryConfigurer.configure(MeterRegistryConfigurer.java:63)
    at app//org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryPostProcessor.postProcessAfterInitialization(MeterRegistryPostProcessor.java:64)
    at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:455)
    at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1808)
    at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
    ... 111 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.actuate.health.HealthContributorRegistry' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1801)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1357)
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311)
    at app//org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
    at app//org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)

下面是我对RestTemplate和MeterRegistryCustomizer Bean的实现

@Configuration
    public class MeterConfig {
        @Bean
        public MeterRegistryCustomizer<MeterRegistry> healthRegistryCustomizer(@Autowired HealthContributorRegistry healthRegistry) {
    
            return  registry -> healthRegistry.stream()
                    .forEach(namedContributor -> registry.gauge("health",
                            details(namedContributor),
                            healthRegistry, health -> {
                                Status status = ((HealthIndicator) health
                                        .getContributor(namedContributor.getName()))
                                        .getHealth(true)
                                        .getStatus();
                                return healthToCode(status);
                            }));
        }

      private static  Iterable<Tag> details(NamedContributor<HealthContributor> contributor) {
        HealthContributor contrib = contributor.getContributor();
        HealthIndicator healthContributor = (HealthIndicator) contrib;
        String name = contributor.getName();
        List<Tag> tagList = new ArrayList<>();
        tagList.add(Tag.of("name", name));
        String details = healthContributor.getHealth(true).getDetails().toString();
        tagList.add(Tag.of("details", details));
        return tagList;
    }

    public static int healthToCode(Status status) {
        return status.equals(Status.UP) ? 1 : 0;
    }
}
    
    @Configuration
    @EnableScheduling
    public class AppConfig {
        @Bean
        @ConditionalOnMissingBean
        public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
            return restTemplateBuilder.build();
        }
    }

    @Component
    public class MyHealthIndicator implements HealthIndicator {
        
        @Autowired
        MyRepo myrepo;
        
        @Override
        public Health health() {
            return myrepo.ping() == "SUCCESS" ? Health.UP.build(): Health.DOWN.build(); //this will return the 
        }
    }

    @Repository
    public class MyRepo {
        
        @Autowired
        RestTemplate restTemplate;
        
        public String ping() {
                return restTemplate.exchange("url", GET, new HttpEntity(requestBody, headers), String.class);
        }
    }

如果您在我的代码中观察到,假设PrometheusMeterRegistryMeterRegistryBean的创建依赖于restTemplate/PrometheusMeterRegistry,我还尝试了@Lazy初始化和@DependsOn来延迟Bean初始化。
我可能在这里做了一些关于注入bean的错误。请分享你的想法如何解决这个问题。我正在使用Springboot 2. 7. 2和依赖管理来控制依赖版本,并且还为io. micronium注册表添加了prometheus的依赖。

qzwqbdag

qzwqbdag1#

我分享了我的经验,因为它花了更多的时间来检查循环引用的根本原因。我在升级到sprintboot 2.6.x和2.7.x后遇到了prometheusMeterRegistry相同的问题,因为我在POM文件中依赖于micrometer-registry-prometheus。
代码是手动将prometheus的metricRegistry设置为HikariDataSource,但是在新版本的springboot中,它会自动设置每个Hikari数据源,所以我只需从我的方法中删除该代码,然后它就可以正常工作。

@Bean(name = "myDataSource")
public DataSource dataSource(/* final MeterRegistry metricRegistry */) {
    final var dataSource = DataSourceBuilder.create().build();
   /* if (dataSource instanceof HikariDataSource) {
        final var hikariDs = (HikariDataSource) dataSource;
        hikariDs.setMetricRegistry(metricRegistry);
    } */

    return dataSource;
}

注意:设置spring.main.allow-circular-references=true不适用于我的多数据源项目。
希望能有所帮助。

相关问题