2016-11-12 12 views
0

Я использую Spring-Data с Spring-Data MongoDB для сопоставления класса сущности с помощью аннотации @CompoundIndexes, в которой я указываю индексы с именами и их определениями. В моей рабочей среде я решил изменить некоторые атрибуты индекса на основе фактических данных. Теперь каждый раз, когда мое приложение запускается, оно не загружается, потому что не удалось создать индекс, соответствующий спецификации в результатах аннотации, и это исключение возникает в процессе инициализации (как показано ниже).Исключение при создании индекса - данные Spring 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; 
    } 
} 

Создание индекса инициируется событием, опубликованной 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; 
     } 

} 

Обычно вы настраиваете пружины MongoDB данных, используя класс, который расширяет AbstractMongoConfig и подменяет «Монго()» метод.

Компонент, ответственный за публикацию сообщения, инициализирующего индексы, является тем, который был возвращен из «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>