1

我使用的是Spring-Boot项目和MongoRepository而不是MongoTemplate。如何使用MongoRepository动态设置主机名

当使用MongoTemplate,一个可以动态使用MongoConnectionPool像这样设置主机名:

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

如何实现使用MongoRepository同样的效果?

我知道,我可以通过在application.properties文件中指定

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

指定的主机名和端口。

但是我使用GenericContainer通过Docker容器启动一个mongo实例来运行我的单元测试。容器将动态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

覆盖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();
  • 将@Configuration MongoTestConfiguration添加到重新定义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); 

} 
}