1

Я использую проект Spring-Boot и MongoRepository вместо MongoTemplate.Как динамически установить имя хоста с помощью MongoRepository

При использовании MongoTemplate, можно динамически установить имя хоста с помощью MongoConnectionPool так:

@Autowired 
MongoConnectionPool mongoConn 
.... 
mongoConn.setHostname("127.23.45.89"); 
mongoConn.setPort(27017); 

Как достичь того же эффекта с помощью MongoRepository?

Я знаю, что я могу указано имя хоста и номер порта, указав

spring.data.mongodb.host=hostname1 
spring.data.mongodb.port=27017 

в application.properties файле.

Однако я использую GenericContainer, чтобы развернуть экземпляр mongo через контейнер Docker для запуска моего модульного теста. Контейнер динамически назначил IP-адрес и порт экземпляру mongo, и поэтому мне нужно иметь возможность динамически устанавливать имя хоста и порт для MongoRepository во время выполнения.

Вот как я настраиваю свой модульный тест.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = MongoConfiguration.class) 
public class HierarchiesServiceImplTests { 
private static final Logger log = LoggerFactory.getLogger(HierarchiesServiceImplTests.class); 

@Autowired 
private HierarchiesService hierarchiesService; 

@Autowired 
private HierarchyRepository hierarchyRepo; 

@BeforeClass 
public void setUp() { 
    MockitoAnnotations.initMocks(this); 

    startMongo(); 
} 

/** 
* Starts a Mongo docker container, and configures the repository factory to use this instance. 
*/ 
private void startMongo() { 
    GenericContainer mongo = new GenericContainer("mongo:3") 
      .withExposedPorts(27017); 
    mongo.start(); 

    String containerIpAddress = mongo.getContainerIpAddress(); 
    int mappedPort = mongo.getMappedPort(27017); 

    //TODO: set the hostname and port here so that the MongoRepository use this mongo instance instead of the default localhost. 

    log.info("Container mongo:3 listening on {}:{}", containerIpAddress, mappedPort); 
} 

Это то, что у меня в MongoConfiguration.class

@Configuration 
@EnableMongoRepositories 
@ComponentScan({"com.is.hierarchies.service"}) 
public class MongoConfiguration { 

} 
+0

@Alex, спасибо за предложение. Тег «весна» заменен на «весеннюю загрузку» – Antwan

+0

Я добавил еще один ответ, который, я считаю, в большей степени соответствует тому, что вы искали – alexbt

ответ

0

Override MongoTemplate Фасоль с вами

Вы можете определить дополнительный @Configuration класс в этом тесте, просто переопределить MongoTemplate.

MongoRepository использует MongoTemplate для выполнения своих операций, поэтому, определив @Bean MongoTemplate, мы сможем установить данные о соединении по вашему выбору. И это то, что будет использовать Repository.

Полный код:

RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = MongoConfiguration.class) 
public class HierarchiesServiceImplTests { 
private static final Logger log = LoggerFactory.getLogger(HierarchiesServiceImplTests.class); 

private static String containerIpAddress; 
private static int mappedPort; 

@Autowired 
private HierarchiesService hierarchiesService; 

@Autowired 
private HierarchyRepository hierarchyRepo; 

/** 
* Starts a Mongo docker container, and configures the repository factory to use this instance. 
*/ 
private void startMongo() { 
    GenericContainer mongo = new GenericContainer("mongo:3").withExposedPorts(27017); 
    mongo.start(); 

    containerIpAddress = mongo.getContainerIpAddress(); 
    mappedPort = mongo.getMappedPort(27017); 

    log.info("Container mongo:3 listening on {}:{}", containerIpAddress, mappedPort); 
} 

@Configuration 
public static class MongoTestConfiguration {  
    @Bean 
    @Primary 
    public MongoTemplate mongoTemplate() throws DataAccessException, Exception{ 
     return createMongoOperations(containerIpAddress, mappedPort, "mydb", "user", "pwd"); 
    } 

    private MongoTemplate createMongoOperations(String hostname, int port, String dbName, String user, String pwd) throws DataAccessException, Exception { 
     MongoCredential mongoCredentials = MongoCredential.createScramSha1Credential(user, dbName, pwd.toCharArray()); 
     MongoClient mongoClient = new MongoClient(new ServerAddress(hostname, port), Arrays.asList(mongoCredentials)); 
     Mongo mongo = new SimpleMongoDbFactory(mongoClient, dbName).getDb().getMongo(); 
     return new MongoTemplate(mongo, dbName); 
    } 
} 

@BeforeClass 
public static void setUp() { 
    MockitoAnnotations.initMocks(this); 

    startMongo(); 
} 

Что я сделал:

  • добавить static в метод установки
  • преобразования IP в статическом поле: containerIpAddress = mongo.getContainerIpAddress();
  • add @Configuration MongoTestConfiguration to redefine MongoTemplate
+0

спасибо за ваше предложение. Я стараюсь, и он работает, как ожидалось. – Antwan

0

Контейнер динамически назначается IP-адрес и порт к экземпляру Монго и, таким образом, мне нужно, чтобы иметь возможность динамически установить имя хоста и порт для MongoRepository во время выполнения.

Вы также можете переопределить свойства в момент запуска:

$ java -jar YourApp.jar --spring.data.mongodb.host=hostnamexyz --spring.data.mongodb.port=123 

или

$ java -Dspring.data.mongodb.host=hostnamexyz -Dspring.data.mongodb.port=123 -jar YourApp.jar 

Или через Докер:

$ docker run -e spring.data.mongodb.host=hostnamexyz -e spring.data.mongodb.port=123 -p 8080:8080 -i -t yourdocker:latest 

Я только проверил команду Докер с одним -e param, но я не понимаю, почему мы не можем предоставить более одного!

+0

Хорошая дедукция @Alex. Я действительно использую весенний ботинок. Ваше решение подразумевает, что мне нужно будет узнать имя хоста и порт экземпляра mongo до запуска. Я запускаю свой модульный тест с помощью '@RunWith (SpringJUnit4ClassRunner.class)' – Antwan

+0

Это ответы не помогают при работе в модульном тесте. Я предоставил вам еще один ответ, где вы переопределяете MongoTemplate Bean своим собственным, позволяя вам установить имя хоста/порт. – alexbt

+0

Спасибо, Алекс, я обозначил ваше решение как «Принято» – Antwan

0

@Alex дал мне идею сделать более чистое решение. Вместо того, чтобы модифицировать MongoTemplate в моем тестовом наборе, я переношу этот код в MongoConfiguration.java.

Вот как я в итоге решил проблему.

в моем MongoConfiguration.class я сделал следующие изменения:

@Configuration 
@EnableMongoRepositories 
@ComponentScan({"com.is.hierarchies.service"}) 
public class MongoConfiguration extends AbstractMongoConfiguration { 

String containerIpAddress; 
Integer mappedPort; 

@Override 
public Mongo mongo() throws Exception { 
    startMongo(); 
    return new Mongo(containerIpAddress,mappedPort); 
} 

@Override 
public String getDatabaseName() { 
    return "hierarchies_db"; 
} 

/** 
* Starts a Mongo docker container, and configures the repository factory to use this instance. 
*/ 
private void startMongo() { 
    GenericContainer mongo = new GenericContainer("mongo:3") 
      .withExposedPorts(27017); 
    mongo.start(); 

    containerIpAddress = mongo.getContainerIpAddress(); 
    mappedPort = mongo.getMappedPort(27017); 

} 
}