【问题标题】:VerifierMappingExceptions with Spring Boot 1.3.1 when using Spring Data JPA and Spring Data Cassandra使用 Spring Data JPA 和 Spring Data Cassandra 时 Spring Boot 1.3.1 的 VerifierMappingExceptions
【发布时间】:2016-06-22 16:57:12
【问题描述】:

我正在使用 Spring-boot-starter-parent 让 Spring 管理我的项目的所有依赖项,并且我正在使用 Spring Data Cassandra 和 Spring data JPA

Spring-boot-starter-parent 的版本是 1.2.8.RELEASE。最近我将版本更新到 1.3.1.RELEASE 并开始面临 Spring Data Cassandra 的一个奇怪问题

 21:23:21.783 [localhost-startStop-1] WARN  org.apache.catalina.loader.WebappClassLoaderBase   - Failed to check for ThreadLocal references for web application [ROOT]
java.lang.UnsupportedOperationException: null
    at com.zaxxer.hikari.util.FastList.iterator(FastList.java:209) ~[HikariCP-2.4.3.jar:na]
    at org.apache.catalina.loader.WebappClassLoaderBase.loadedByThisOrChild(WebappClassLoaderBase.java:2195) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks(WebappClassLoaderBase.java:2105) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalsForLeaks(WebappClassLoaderBase.java:2060) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.clearReferences(WebappClassLoaderBase.java:1575) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.stop(WebappClassLoaderBase.java:1521) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappLoader.stopInternal(WebappLoader.java:447) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5517) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1424) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1413) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_72]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_72]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_72]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_72]
21:23:21.791 [main] ERROR org.springframework.boot.SpringApplication         - Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.service.intf.UserService com.sarvint.rest.UserController.uService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.repositories.UserRepository com.sarvint.service.UserServiceImpl.userRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is org.springframework.data.cassandra.mapping.VerifierMappingExceptions: com.sarvint.domain.User:
Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation

    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:764) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:357) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:305) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1124) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1113) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at com.sarvint.Application.main(Application.java:18) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.service.intf.UserService com.sarvint.rest.UserController.uService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.repositories.UserRepository com.sarvint.service.UserServiceImpl.userRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is org.springframework.data.cassandra.mapping.VerifierMappingExceptions: com.sarvint.domain.User:
Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation

    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    ... 17 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.repositories.UserRepository com.sarvint.service.UserServiceImpl.userRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is org.springframework.data.cassandra.mapping.VerifierMappingExceptions: com.sarvint.domain.User:
Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation

它说我必须用 @Table 等注释实体,但这些实体属于 Spring data JPA 我用 @Table 等注释的 Spring 数据 Cassandra 的实体

开始类:

@SpringBootApplication
@EnableJpaRepositories( repositoryFactoryBeanClass =    GenericRepositoryFactoryBean.class )
@EntityScan("com.sarvint.domain")
@Import(CassandraConfig.class)
public class Application {

public static void main( String[] args ) throws Exception
{
    SpringApplication.run(Application.class, args);
}

}

Spring Data JPA 配置:

@Configuration
@ComponentScan( basePackages = "com.sarvint" )
@PropertySource( value = { "classpath:application.properties" } )
public class AppConfig extends WebMvcConfigurerAdapter {

@Autowired
private Environment environment;

                                                                                                                                                                                                                                            @Override
public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer )
{
    configurer.enable();
}

@Bean
public DataSource dataSource()
{
    HikariConfig config = new HikariConfig();
    int poolSize = 20;
    config.setMaximumPoolSize(poolSize);
    config.setDataSourceClassName(environment.getRequiredProperty("spring.datasource.driver-class-name"));
    config.addDataSourceProperty("url", environment.getRequiredProperty("spring.datasource.url"));
    config.addDataSourceProperty("user", environment.getRequiredProperty("spring.datasource.username"));
    config.addDataSourceProperty("password", environment.getRequiredProperty("spring.datasource.password"));
    return new HikariDataSource(config);
}

Spring Data JPA 实体:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table( name = "user" )

public class User implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
@Column( name = "u_id" )
private Integer userId;

@Column( name = "u_first_name" )
private String firstName;

@Column( name = "u_last_name" )
private String lastName;
}

现在进入 Spring Data Cassandra 配置:

    package com.sarvint.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.cassandra.config.CassandraClusterFactoryBean;
import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;

@Configuration
@PropertySource(value = { "classpath:cassandra.properties" })
@EnableCassandraRepositories(basePackages="com.sarvint.cassandra.domain")
public class CassandraConfig extends AbstractCassandraConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(CassandraConfig.class);


    @Autowired
    private Environment environment;

    @Bean
    public CassandraClusterFactoryBean cluster() {
        LOG.info("INSIDE cluster()");
        CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
        cluster.setContactPoints(environment.getProperty("cassandra.contactpoints"));
        cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port")));
        return cluster;
    }

    @Override
    protected String getKeyspaceName() {
        LOG.info("INSIDE getting keyspace name");
        return environment.getProperty("cassandra.keyspace");
    }

    @Bean
    public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
        LOG.info("INSIDE cassandra mapping");
        return new BasicCassandraMappingContext();
    }
}

Spring Cassandra 实体:

import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.Table;

@Table( value = "biometric_param" )
public class BiometricParam {

    @PrimaryKeyColumn(name="user_id",ordinal=0,type=PrimaryKeyType.PARTITIONED)
    private Integer userId;

    @PrimaryKeyColumn(name="workout_uuid",ordinal=1,type=PrimaryKeyType.PARTITIONED)
    private String workoutUUID;

    @PrimaryKeyColumn(name="bio_param_key",ordinal=2,type=PrimaryKeyType.CLUSTERED)
    private String bioParamKey;

    @Column(value="bio_param_val")
    private Float bioParamValue;
}

Cassandra.properties

cassandra.contactpoints=127.0.0.1
cassandra.port=9042
cassandra.keyspace=test

感谢您的帮助!

【问题讨论】:

    标签: spring-boot spring-data-cassandra


    【解决方案1】:

    有什么问题?

    这是 Spring Data Cassandra 中的一个错误。您的类路径上有多个 Spring Data 模块。在这种情况下,Spring Data 会尝试找出特定存储库属于哪个模块。 Spring Data Cassandra 错过了识别您的 JPA 实体 User 不属于 Cassandra 的位,因此 Spring Data Cassandra 尝试为您的 UserRepository 创建一个存储库实例。

    如果您启用 DEBUG 日志记录,您将看到一些 DEBUG 日志消息说 Spring Data 正在进入严格配置模式。

    为什么现在出现这个错误,而不是早期的 Spring Boot 版本?

    Spring Boot 1.3.0 引入了 Spring Data Cassandra 存储库的自动配置。由于此更改,Spring Boot 执行 scan for Spring Data Cassandra repositories 就像您仅使用 @EnableCassandraRepositories 配置它一样。

    只有使用多个 Spring Data 模块的默认 EnableCassandraRepositories 组合才会显示此错误。

    那么,现在呢?

    在您的application.properties 中设置spring.data.cassandra.repositories.enabled=false 以禁用自动配置,因为您自己使用的是@EnableCassandraRepositories(basePackages="com.sarvint.cassandra.domain")

    我创建了一个错误报告here,因此您可以根据需要跟踪进度。

    【讨论】:

    • 如果我在 application.properties 中添加 spring.data.cassandra.repositories.enabled=false 它表示没有与 Spring Data JPA 相关的 Repository 类的构造函数
    • 太好了,这样您就摆脱了 Cassandra 问题。接下来是 JPA,所以创建一个包含另一个堆栈跟踪的新帖子。
    • 我打算向 Cassandra 和 Neo4J 提出同样的问题。不像这样,我最初没有任何 neo4j 存储库。但它给了我与 cassandra 相同的错误。然后我设置 spring.data.neo4j.repositories.enabled=false 并开始正常工作。感谢@mp911de 提供此信息。看起来与 spring neo4j 存在相同的错误。
    【解决方案2】:

    尝试升级到 HikariCP 2.4.4。它包含此修复:

    issue 495: implemented iterator() method on custom FastList to support Tomcat memory leak detection.

    【讨论】:

    • 这确实解决了 FastList 和 HikariCp 的问题,但没有解决实际的 spring 数据模块冲突!无论如何谢谢你
    猜你喜欢
    • 2017-11-29
    • 2017-05-09
    • 1970-01-01
    • 2017-09-22
    • 2018-08-06
    • 2014-07-21
    • 2014-10-21
    • 2018-08-06
    • 1970-01-01
    相关资源
    最近更新 更多