Spring Boot Data Cassandra Reactive JmxReporter问题

21

我把我的项目更新到了spring-boot 2.1.0.RELEASE 版本。
现在我遇到了以下错误:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.cassandra.ReactiveSession]: Factory method 'reactiveSession' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'session' defined in class path resource [ch/sbb/kat/fc/config/CassandraConfig.class]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/codahale/metrics/JmxReporter
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.lambda$instantiate$2(ConstructorResolver.java:615)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:614)
    ... 120 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'session' defined in class path resource [ch/sbb/kat/fc/config/CassandraConfig.class]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/codahale/metrics/JmxReporter
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1745)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:339)
    at ch.sbb.kat.fc.config.CassandraConfig$$EnhancerBySpringCGLIB$$a22674d7.session(<generated>)
    at org.springframework.data.cassandra.config.AbstractCassandraConfiguration.getRequiredSession(AbstractCassandraConfiguration.java:66)
    at org.springframework.data.cassandra.config.AbstractReactiveCassandraConfiguration.reactiveSession(AbstractReactiveCassandraConfiguration.java:47)
    at ch.sbb.kat.fc.config.CassandraConfig$$EnhancerBySpringCGLIB$$a22674d7.CGLIB$reactiveSession$7(<generated>)
    at ch.sbb.kat.fc.config.CassandraConfig$$EnhancerBySpringCGLIB$$a22674d7$$FastClassBySpringCGLIB$$7973a63.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
    at ch.sbb.kat.fc.config.CassandraConfig$$EnhancerBySpringCGLIB$$a22674d7.reactiveSession(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 123 more
Caused by: java.lang.NoClassDefFoundError: com/codahale/metrics/JmxReporter
    at com.datastax.driver.core.Metrics.<init>(Metrics.java:146)
    at com.datastax.driver.core.Cluster$Manager.init(Cluster.java:1501)
    at com.datastax.driver.core.Cluster.init(Cluster.java:208)
    at com.datastax.driver.core.Cluster.connectAsync(Cluster.java:376)
    at com.datastax.driver.core.Cluster.connect(Cluster.java:332)
    at org.springframework.data.cassandra.config.CassandraCqlSessionFactoryBean.connect(CassandraCqlSessionFactoryBean.java:89)
    at org.springframework.data.cassandra.config.CassandraCqlSessionFactoryBean.afterPropertiesSet(CassandraCqlSessionFactoryBean.java:82)
    at org.springframework.data.cassandra.config.CassandraSessionFactoryBean.afterPropertiesSet(CassandraSessionFactoryBean.java:59)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$invokeInitMethods$5(AbstractAutowireCapableBeanFactory.java:1795)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1794)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1741)
    ... 143 more
Caused by: java.lang.ClassNotFoundException: com.codahale.metrics.JmxReporter
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 155 more

使用本问题中介绍的属性https://github.com/spring-projects/spring-boot/issues/14778似乎对解决我的问题没有影响。

我如何禁用Cassandra的JMX?

我的当前Cassandra配置如下:

@Configuration
@EnableReactiveCassandraRepositories({"repository"})
public class CassandraConfig extends AbstractReactiveCassandraConfiguration {

    @Value("${cassandra.host}")
    private String host;

    @Override
    protected String getKeyspaceName() {
        return "keyspace";
    }

    @Override
    public String[] getEntityBasePackages() {
        return new String[]{"model"};
    }

    @Override
    public SchemaAction getSchemaAction() {
        return SchemaAction.CREATE_IF_NOT_EXISTS;
    }

    @Override
    public String getContactPoints() {
        return host;
    }
}

ch.sbb.kat.fc.config.CassandraConfig 是做什么的?从它的名称来看,我猜测您正在手动配置Cassandra。因此,Boot的自动配置将会被取消,因此该属性将不起作用。 - Andy Wilkinson
@AndyWilkinson CassandraConfig继承AbstractReactiveCassandraConfiguration,我覆盖了keyspace、contactpoints、entitybasepackage和schema action。集群bean由Spring创建。 - locohost
5个回答

33

spring.data.cassandra.jmx-enabled属性用于在Spring Boot自动配置Cassandra Cluster bean时使用。如果扩展AbstractReactiveCassandraConfiguration,则会选择由AbstractClusterConfiguration创建的Cluster bean,而不是自动配置。因此,该属性没有任何效果。

有两种方法可以解决问题:

  1. 删除AbstractReactiveCassandraConfiguration子类,并使用各种spring.data.cassandra.*属性进行配置。
  2. CassandraConfig中覆盖AbstractClusterConfiguration上的cluster,调用super.cluster()来获取CassandraClusterFactoryBean,然后在返回之前在工厂bean上调用setJmxReportingEnabled(false)

或者,如果您的应用程序中未在其他地方使用Dropwizard,则可以通过覆盖pom.xmlbuild.gradle中的dropwizard-metrics.version属性,将其降级为与Cassandra的JMX报告兼容的较旧版本。


感谢您提供的有用答案。 - locohost
1
来自票证的降级提示:问题在于cassandra-driver-core 3.6.0依赖于dropwizard版本3.2.2。版本4.0.3包含了一个破坏性变更,导致类找不到错误。 - kisna
1
对于那些使用TestContainers的人,请注意CassandraContainer在执行CQL init脚本时使用JMX Reporting:https://github.com/testcontainers/testcontainers-java/issues/1011 - Michael Técourt

24

与Andy Wilkinson提到的覆盖cluster的方法不同,您可以选择覆盖getMetricsEnabled方法,使其始终返回false

@Override
protected boolean getMetricsEnabled() { return false; }

谢谢您指出这一点。我也在寻找覆盖该值的方法,但总是在寻找带有jmx名称的东西;)这比从超类获取集群更方便。 - locohost
不客气。cluster的默认实现调用getMetricsEnabled。仅重写getMetricsEnabled,我们可以保持cluster的默认实现(和行为)。 - Heny Kamoun
这是一种更干净的禁用指标的方式,非常喜欢。 - Marco Capo

17

我尝试了这里的答案,但错误仍然存在。我从docs.datastax.com阅读到他们谈到将Metrics 4中的JMX reporting移动到单独的模块metrics-jmx中。他们明确指出这可能会导致问题/错误。

要解决这个问题,我只需要调用下面这个方法:.withoutJMXReporting()

Cluster cluster = Cluster.builder()
        .withoutJMXReporting()
        .build();

您可以安静地跟随这里


6
包含旧版本库也可以解决问题: implementation("io.dropwizard.metrics:metrics-core:3.2.2")

1

@Bean public CassandraClusterFactoryBean cluster() { CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean(); cluster.setContactPoints(environment.getProperty("spring.data.cassandra.contact-points")); cluster.setPort(Integer.parseInt(environment.getProperty("spring.data.cassandra.port"))); cluster.setJmxReportingEnabled(false); return cluster; }

cluster.setJmxReportingEnabled(false) 这个是答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接