我使用Spring引导启动程序父级,让Spring管理我项目的所有依赖项,并使用Spring Data Cassandra和Spring Data JPA
Spring启动程序的父版本是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数据JPASpring数据的实体Cassandra i用@Table等进行了注释
起始类别:
@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);
}
}
春季数据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属性
cassandra.contactpoints=127.0.0.1
cassandra.port=9042
cassandra.keyspace=test
谢谢你的帮助!
问题出在哪里
这是Spring Data Cassandra中的一个错误。类路径上有多个Spring Data模块。在这种情况下,SpringData试图弄清楚特定Repository属于哪个模块。Spring Data Cassandra错过了识别您的JPA实体User
不属于Cassandra的位置,因此Spring Data Cas桑德拉试图为您的UserRepository
创建一个Repository实例。
如果启用DEBUG
日志记录,您将看到一些DEBUG
日志消息,表示Spring Data正在进入严格的配置模式。
为什么现在出现这个bug而不是早期的Spring Boot版本
Spring Boot 1.3.0引入了Spring Data Cassandra存储库的自动配置。由于这一更改,Spring Boot对Spring Data Cassandra存储库执行扫描,就像您仅使用@EnableCassandraRepositories
配置它一样。
只有使用多个Spring Data模块的默认EnableCassandraRepositories
的组合才能揭示此错误。
那么,现在怎么办
在application.properties
中设置spring.data.cassandra.repositories.enabled=false
以禁用自动配置,因为您自己使用的是@EnableCassandraRepositories(basePackages="com.sarvint.cassandra.domain")
。
我在这里创建了一个错误报告,所以如果你愿意,你可以跟踪进度。
尝试升级到HikariCP 2.4.4。它包含此修复程序:
issue 495: implemented iterator() method on custom FastList to support Tomcat
memory leak detection.