我正在使用带有Spring-Data MongoDB的Spring-Data来使用@CompoundIndexes注释来映射实体类,其中我指定了具有名称及其定义的索引。在我的生产环境中,我决定需要根据实际数据更改索引的某些属性。现在,每次我的应用程序启动时,都无法加载,因为无法在注释结果中创建与规范匹配的索引,并且在初始化过程中抛出该异常(如下所示)。
是否有配置弹簧数据和mongodb以便记录这些异常,但不会导致容器启动失败?
Exception while creating index
! com.mongodb.MongoCommandException: Command failed with error 86: 'Trying to create an index with same name event_source_link_type_at_id_IDX with different key spec **** vs existing spec *****' on server 127.0.0.1:27017. The full response is { "ok" : 0.0, "errmsg" : "Trying to create an index with same name event_source_link_type_at_id_IDX with different key spec **** vs existing spec *****", "code" : 86 }
! at com.mongodb.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:115) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.connection.CommandProtocol.execute(CommandProtocol.java:114) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:159) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:286) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.java:173) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:215) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:198) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:170) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.CreateIndexesOperation$1.call(CreateIndexesOperation.java:116) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.CreateIndexesOperation$1.call(CreateIndexesOperation.java:111) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:230) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:221) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.CreateIndexesOperation.execute(CreateIndexesOperation.java:111) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.operation.CreateIndexesOperation.execute(CreateIndexesOperation.java:66) ~[mongodb-driver-core-3.2.2.jar:na]
! at com.mongodb.Mongo.execute(Mongo.java:781) ~[mongodb-driver-3.2.2.jar:na]
! at com.mongodb.Mongo$2.execute(Mongo.java:764) ~[mongodb-driver-3.2.2.jar:na]
! at com.mongodb.DBCollection.createIndex(DBCollection.java:1541) ~[mongodb-driver-3.2.2.jar:na]
! at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.createIndex(MongoPersistentEntityIndexCreator.java:142) [spring-data-mongodb-1.8.4.RELEASE.jar:na]
答案 0 :(得分:1)
事实证明这并不像我想象的那么容易,但可以通过一些额外的课程完成。
首先,您需要覆盖创建索引的类,并覆盖创建索引的方法,捕获匹配的异常并仅记录它们。
不幸的是它受到包保护,因此您需要在与我们扩展的类相同的包中创建一个类。
package org.springframework.data.mongodb.core.index;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
public class ExceptionIgnoringIndexCreator extends MongoPersistentEntityIndexCreator {
//assuming SLF4J as your logger otherwise, put your logger here
private static final Logger LOG = LoggerFactory.getLogger(ExceptionIgnoringIndexCreator.class);
public ExceptionIgnoringIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) {
super(mappingContext, mongoDbFactory);
}
@Override
void createIndex(MongoPersistentEntityIndexResolver.IndexDefinitionHolder indexDefinition) {
try {
super.createIndex(indexDefinition);
} catch (final RuntimeException exp) {
final RuntimeException trans = translate(exp);
if (trans != null) {
throw trans;
} else {
LOG.warn("Exception while creating index", exp);
}
}
}
protected RuntimeException translate(final RuntimeException exp) {
if (exp == null || exp.getMessage().contains("Cannot create index")) {
return null;
}
return exp;
}
}
索引创建由MongoMappingContext使用ApplicationEventPublisherInterface发布的事件触发。 我们需要一个类,我们可以懒惰地将另一个ApplicationEventPublisher设置为委托,接口的两个方法将委托他们的调用。
public class DelegatingPublisher implements ApplicationEventPublisher {
private ApplicationEventPublisher delegate;
@Override
public void publishEvent(ApplicationEvent event) {
delegate.publishEvent(event);
}
@Override
public void publishEvent(Object event) {
delegate.publishEvent(event);
}
public void setDelegate(ApplicationEventPublisher delegate) {
this.delegate = delegate;
}
}
通常使用扩展AbstractMongoConfig的类配置spring数据mongoDB并覆盖“mongo()”方法。
负责发布初始化索引的消息的组件是从“mongoMappingContext()”返回的消息,因此您需要覆盖该方法并扩展默认的MongoMappingContext,覆盖设置事件发布者并传递新的方法的方法。委托出版商代替。
@Configuration
@EnableMongoRepositories("com.my.company")
public class MyMongoConfig extends AbstractMongoConfiguration {
...
@Override
@Bean
public MongoMappingContext mongoMappingContext() throws ClassNotFoundException {
final DelegatingPublisher dep = new DelegatingPublisher();
final MongoMappingContext mappingContext = new MongoMappingContext() {
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
super.setApplicationEventPublisher(dep);
}
};
mappingContext.setInitialEntitySet(getInitialEntitySet());
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
try {
final MongoPersistentEntityIndexCreator indexCreator = new ExceptionIgnoringIndexCreator(mappingContext, mongoDbFactory());
dep.setDelegate(new MongoMappingEventPublisher(indexCreator));
return mappingContext;
} catch (Exception exp) {
throw new RuntimeException(exp);
}
}
...
}
如果使用基于XML的配置,则还需要一个类和指定的配置
public class EventDelegatingMongoMappingContext extends MongoMappingContext {
private ApplicationEventPublisher publisher;
public EventDelegatingMongoMappingContext(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
super.setApplicationEventPublisher(publisher);
}
}
<mongo:db-factory id="mongoDbFactory"
host="localhost"
port="27017"
dbname="database"
username="mycompany"
password="secret"/>
<bean id="delegatingPublisher" class="com.my.company.DelegatingPublisher">
<property name="delegate" ref="mappingEventPublisher" />
</bean>
<!-- Must be named 'mongoMappingContext' to be recognized up -->
<bean id="mongoMappingContext" class="com.my.company.EventDelegatingMongoMappingContext">
<constructor-arg>
<bean ref="delegatingPublisher" />
</constructor-arg>
</bean>
<bean id="mongoIndexCreator" class="org.springframework.data.mongodb.core.index.ExceptionIgnoringIndexCreator">
<constructor-arg>
<bean ref="mongoMappingContext"/>
</constructor-arg>
<constructor-arg>
<bean ref="mongoDbFactory"/>
</constructor-arg>
</bean>
<bean id="mappingEventPublisher" class="org.springframework.data.mongodb.core.index.MongoMappingEventPublisher">
<constructor-arg>
<bean ref="mongoIndexCreator"/>
</constructor-arg>
</bean>