2016-11-12 60 views
0

我使用Spring-Data和Spring-Data MongoDB來使用@CompoundIndexes註釋來映射實體類,在該註解中我使用了名稱及其定義來指定索引。在我的生產環境中,我決定需要根據實際數據更改索引的某些屬性。現在,每次我的應用程序啓動時,都無法加載,因爲未能創建與註釋結果中的規範相匹配的索引,並且在初始化過程中拋出異常(如下所示)。創建索引時出現異常 - Spring Data MongoDB

是否有配置彈簧數據和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

原來,這並不像我想的那麼容易,但可以用一些額外的類來完成。

首先,您需要覆蓋創建索引的類並覆蓋創建索引的方法,捕獲匹配的並僅記錄它們的例外。

不幸的是它是軟件包保護的,因此您需要在我們擴展的類的相同包中創建一個類。

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; 
    } 
} 

索引創建通過使用ApplicationEventPublisherInterface由MongoMappingContext公佈的一個事件觸發。 我們需要一個類,我們可以懶惰地設置另一個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並覆蓋「蒙戈()」方法的類配置彈簧數據MongoDB的。

負責發佈初始化索引的消息的組件是從「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>