报警如下:
Please use 'MongoMappingContext#setAutoIndexCreation(boolean)' or override 'MongoConfigurationSupport#autoIndexCreation()' to be explicit.
However, we recommend setting up indices manually in an application ready block. You may use index derivation there as well.
> -----------------------------------------------------------------------------------------
> @EventListener(ApplicationReadyEvent.class)
> public void initIndicesAfterStartup() {
>
> IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);
>
> IndexResolver resolver = new MongoPersistentEntityIndexResolver(mongoMappingContext);
> resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);
> }
> -----------------------------------------------------------------------------------------
其实这个自动创建索引的开关我们关了就不会报这个警告了,但是同时那些带有@Indexed注解的字段也不会自动的创建索引了 那给个警告什么意思呢?官方是这么说的 就是让我们自己主动的去创建索引,我这个版本是2.多,默认还是开启自动配置的,那首先就是要关闭自动配置,然后去按照官方写法创建索引
一、使用spring自动配置的MongoTemplate
application.yml
spring: data: mongodb: host: 192.168.1.1 # mongo地址 database: database # 要连接的数据库 auto-index-creation: false # 关闭自动索引创建
以下引至官方示例
1、为单个类(@Document)创建索引@Component
class MyListener {
@EventListener(ContextRefreshedEvent.class)
public void initIndicesAfterStartup() {
MappingContext extends MongoPersistentEntity>, MongoPersistentProperty> mappingContext = mongoTemplate
.getConverter().getMappingContext();
IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);
IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);
resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);
}
}
2、为所有类(@Document)创建索引 (一般用这个)
@Component
class MyListener{
@EventListener(ContextRefreshedEvent.class)
public void initIndicesAfterStartup() {
MappingContext extends MongoPersistentEntity>, MongoPersistentProperty> mappingContext = mongoTemplate
.getConverter().getMappingContext();
// consider only entities that are annotated with @Document
mappingContext.getPersistentEntities()
.stream()
.filter(it -> it.isAnnotationPresent(Document.class))
.forEach(it -> {
IndexOperations indexOps = mongoTemplate.indexOps(it.getType());
resolver.resolveIndexFor(it.getType()).forEach(indexOps::ensureIndex);
});
}
}
二、自定义配置类继承 AbstractMongoClientConfiguration
第二种就是我使用的了,自定义一些MongoTemplate的配置,因为我要用到spring config+bus自动刷新配置,要在一些Bean上面加个注解
application.yml (因为自定义配置了, 这些字段也可以自定义)
spring:
data:
mongodb:
host: mongodb://192.168.1.1:27017 # mongo地址,跟上面有些差别
database: database # 数据库
配置类:
@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class ToolsMongoConfig extends AbstractMongoClientConfiguration implements ApplicationContextAware {
private String host;
private String database;
private ApplicationContext applicationContext;
@Override
public MongoClient mongoClient() {
return MongoClients.create(this.host);
}
@Override
protected String getDatabaseName() {
return this.database;
}
@Bean(name = "mongoTemplate")
@Override
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(super.mongoDbFactory(),super.mappingMongoConverter());
}
// 关闭自动配置:
@Override
protected boolean autoIndexCreation() {
return false;
}
//添加监听事件
@EventListener(ContextRefreshedEvent.class)
public void initIndicesAfterStartup() throws Exception {
MongoTemplate mongoTemplate = mongoTemplate();
//mongo 映射
MappingContext extends MongoPersistentEntity>, MongoPersistentProperty> mappingContext = mongoTemplate
.getConverter().getMappingContext();
//映射解析器
IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);
//获取启动类
Map beansWithAnnotation = applicationContext.getBeansWithAnnotation(SpringBootApplication.class);
Object runApplicationObj = beansWithAnnotation.values().iterator().next();
//获取启动类所在的包名
String pckname = runApplicationObj.getClass().getPackage().getName();
//自定义扫描器,扫描该包名下的带有 @Document 注解的类
ScanAndBeanLoader scanAndBeanLoader = new ScanAndBeanLoader(pckname);
Set beanDefinitionHolders = scanAndBeanLoader.doScanByAnnotation(Document.class.getName());
//把这些类交给解析器去创建索引
for(BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders){
String beanClassName = beanDefinitionHolder.getBeanDefinition().getBeanClassName();
Class> docClass = Class.forName(beanClassName);
IndexOperations indexOps = mongoTemplate.indexOps(docClass);
resolver.resolveIndexFor(docClass).forEach(indexOps::ensureIndex);
}
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
关于自定义配置类和官方写法不一样的问题:
自定义扫描类:在自定义配置类中我尝试使用官方的方法去使用,但是在mappingContext.getPersistentEntities()
获取映射类的时候,获取不到,里面是空的,翻了翻源码,大致看到了两边处理是不一样的(源码比较难啃),所以我们不用mappingContext中获取这个映射类了,我们自定义扫描器,扫描启动类所在的包里面所有带有 @Document 的类,然后交给那个IndexResolver去检查和创建索引
public class ScanAndBeanLoader {
private String pkgPath;
private ScanAndBeanLoader(){}
public ScanAndBeanLoader(String pkgPath){
this.pkgPath = pkgPath;
}
public Set doScanBySuperClass(String superClassName){
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
CustomerClassPathBeanDefinitionScanner customScan = new CustomerClassPathBeanDefinitionScanner(registry , false);
//自定义过滤条件
TypeFilter customFilter = new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, @NonNull MetadataReaderFactory metadataReaderFactory) throws IOException {
//是具体的类,非抽象类 并且 具有 这个注解
return metadataReader.getClassMetadata().isConcrete() && Objects.equals(metadataReader.getClassMetadata().getSuperClassName(), superClassName);
}
};
customScan.addIncludeFilter(customFilter); //添加include
return customScan.doScan(pkgPath);
}
public Set doScanByAnnotation(String annotationClassName){
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
CustomerClassPathBeanDefinitionScanner customScan = new CustomerClassPathBeanDefinitionScanner(registry , false);
//自定义过滤条件
TypeFilter customFilter = new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, @NonNull MetadataReaderFactory metadataReaderFactory) throws IOException {
//是具体的类,非抽象类 并且 具有 这个注解
return metadataReader.getClassMetadata().isConcrete() && metadataReader.getAnnotationMetadata().hasAnnotation(annotationClassName);
}
};
customScan.addIncludeFilter(customFilter); //添加include
return customScan.doScan(pkgPath);
}
}



