1、前提:项目以前使用springboot+spring-data-mongodb。如今须要加入elasticsearch作搜索引擎,这样mongo和elasticsearch共存了。java
2、报错信息:mysql
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'TTSAudioInfoEsRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property index found for type TTSAudioInfo! at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1082) at org.springframework.data.repository.support.Repositories.cacheRepositoryFactory(Repositories.java:95) at org.springframework.data.repository.support.Repositories.populateRepositoryFactoryInformation(Repositories.java:88) at org.springframework.data.repository.support.Repositories.<init>(Repositories.java:81) at org.springframework.data.repository.support.DomainClassConverter.setApplicationContext(DomainClassConverter.java:98) at org.springframework.data.web.config.SpringDataWebConfiguration.addFormatters(SpringDataWebConfiguration.java:87) at org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite.addFormatters(WebMvcConfigurerComposite.java:49) at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration.addFormatters(DelegatingWebMvcConfiguration.java:117) at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.mvcConversionService(WebMvcConfigurationSupport.java:542) at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$f6948e02.CGLIB$mvcConversionService$45(<generated>) at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$f6948e02$$FastClassBySpringCGLIB$$43c05aaf.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356) at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$f6948e02.mvcConversionService(<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:162) ... 73 common frames omitted Caused by: org.springframework.data.mapping.PropertyReferenceException: No property index found for type TTSAudioInfo! at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:329) at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309) at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272) at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:243) at org.springframework.data.repository.query.parser.Part.<init>(Part.java:76) at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:235) at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:373) at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:353) at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:84) at org.springframework.data.mongodb.repository.query.PartTreeMongoQuery.<init>(PartTreeMongoQuery.java:60) at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory$MongoQueryLookupStrategy.resolveQuery(MongoRepositoryFactory.java:168) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:435) at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:220) at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:266) at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:252) at org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean.afterPropertiesSet(MongoRepositoryFactoryBean.java:108) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574) ... 98 common frames omitted
3、错误分析:web
一、TTSAudioInfo类是pojo类,既是mongo的document也是elasticsearch的documentredis
/** * @author: george * @date: 2018/6/26-16-39 * @description: */ @org.springframework.data.elasticsearch.annotations.Document(indexName = "tts_audio_info", type = "tts_audio_info") //spring-data-elasticsearch注解 @org.springframework.data.mongodb.core.mapping.Document(collection = "TTSAudioInfo") //spring-data-mongodb注解 @Data //lombok注解 public class TTSAudioInfo extends BaseModel { private static final long serialVersionUID = 1L; public static final String FIELD_QUESTION = "question"; public static final String FIELD_ANSWER = "answer"; public static final String FIELD_FILE_URI = "fileUri"; public static final String FIELD_FILE_PATH = "filePath"; private String question; @Field(type = FieldType.String, index = FieldIndex.analyzed) private String answer; private String fileUri; private String filePath; public TTSAudioInfo() { } }
二、而后是elasticsearch的repository接口,继承的是ElasticsearchRepositoryspring
import ai.deepbrain.admin.domain.TTSAudioInfo; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; /** * @author: george * @date: 2018/6/26-17-05 * @description: */ public interface TTSAudioInfoEsRepository extends ElasticsearchRepository<TTSAudioInfo, String> { }
分析:spring-data-mongo和spring-data-elasticsearch都属于spring的spring-data项目,提供各类数据库数据访问的封装(mongo、redis、oracle、mysql、jpa、elasticsearch等等等等)。他们封装的格式基本同样;sql
而在本文的错误中,咱们使用了mongodb和elasticsearch,咱们在查看TTSAudioInfoEsRepository继承的ElasticsearchCrudRepository的继承关系后得知,他和MongoRepository都继承spring-data-commons的PagingAndSortingRepository。mongodb
(这里还有一点就是全部repository接口写在同一包下)因此致使了在mongodb扫描repository的时候也会扫描elasticsearch的repository,spring-data-mongodb会试图代理TTSAudioInfoEsRepository ,可是发现TTSAudioInfoEsRepository 使用的TTSAudioInfo中没有index属性,从而报错No property index found for type。数据库
stackoverflow中有一篇相似的错误文章:https://stackoverflow.com/questions/36252099/no-property-index-found-for-type-user。springboot
4、解决办法:mvc
既然知道错误的缘由了,那解决起来就相对简单了。无非就是让spring-data-mongo扫描mongodb的repository,spring-data-elasticsearch扫描elasticsearch的repository。
一、把不一样类型的repository分别放在不一样包下,而后在配置的地方指定扫描位置
mongodb的配置类
@Configuration @Import(value = MongoAutoConfiguration.class) @EnableMongoRepositories(basePackages = "com.test.mongodb") public class MongoConfiguration extends AbstractMongoConfiguration { @Autowired private MongoProperties mongoProperties; @Override protected String getDatabaseName() { return mongoProperties.getDatabase(); } @Override public Mongo mongo() throws Exception { MongoClientURI clientURI = new MongoClientURI(mongoProperties.getUri()); return new MongoClient(clientURI); } @Bean public ValidatingMongoEventListener validatingMongoEventListener() { return new ValidatingMongoEventListener(validator()); } @Bean public LocalValidatorFactoryBean validator() { return new LocalValidatorFactoryBean(); } @Bean public MappingMongoConverter mappingMongoConverter() throws Exception { DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory()); MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext()); // remove _class field converter.setTypeMapper(new DefaultMongoTypeMapper(null)); converter.setCustomConversions(customConversions()); return converter; } }
elasticsearch的配置类
@Configuration @EnableElasticsearchRepositories(basePackages = "com.test.elasticsearch") public class ElasticsearchConfiguration { @Bean public ElasticsearchTemplate elasticsearchTemplate(Client client, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) { MappingElasticsearchConverter converter = new MappingElasticsearchConverter( new SimpleElasticsearchMappingContext()); DefaultResultMapper mapper = new DefaultResultMapper(converter.getMappingContext(), new CustomEntityMapper(jackson2ObjectMapperBuilder.createXmlMapper(false).build())); return new ElasticsearchTemplate(client, converter, mapper); } public class CustomEntityMapper implements EntityMapper { private ObjectMapper objectMapper; public CustomEntityMapper(ObjectMapper objectMapper) { this.objectMapper = objectMapper; objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); } @Override public String mapToString(Object object) throws IOException { return objectMapper.writeValueAsString(object); } @Override public <T> T mapToObject(String source, Class<T> clazz) throws IOException { return objectMapper.readValue(source, clazz); } } }
二、在配置enabled注解的时候添加includeFilters
mongo:
@Configuration @Import(value = MongoAutoConfiguration.class) @EnableMongoRepositories(basePackages = "com.test",includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository.class)) public class MongoConfiguration extends AbstractMongoConfiguration {
elasticsearch:
@Configuration @EnableElasticsearchRepositories(basePackages = "com.test",includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ElasticsearchRepository.class)) public class ElasticsearchConfiguration {