1. 개요
Spring Data MongoDB를 사용하여 MongoClient 를 생성하여 데이터베이스에 대한 작업을 수행할 수 있습니다. 그러나 경우에 따라 애플리케이션에서 여러 데이터베이스를 사용해야 할 수도 있습니다.
이 사용방법(예제)에서는 MongoDB에 대한 여러 연결을 만듭니다. 또한 이 시나리오를 모방하기 위해 몇 가지 Spring Boot 테스트를 추가할 것입니다.
2. Spring Data MongoDB를 사용한 다중 데이터베이스 애플리케이션
MongoDB 를 사용할 때 데이터에 액세스하기 위해 MongoTemplate 을 생성합니다 . 따라서 다양한 데이터베이스에 연결하기 위해 여러 템플릿을 만들 수 있습니다.
그러나 Spring이 고유한 bean을 찾지 못하기 때문에 NoUniqueBeanDefinitionException 을 얻을 수 있습니다 .
이를 염두에 두고 Spring Boot 구성을 빌드하는 방법을 살펴보겠습니다.
2.1. 의존성 설정
pom.xml 에 의존성을 추가하여 시작하겠습니다 . 먼저 스프링 부트 스타터 가 필요합니다 .
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath />
</parent>
그런 다음 웹 스타터 및 데이터 MongoDB 에 대한 의존성이 필요합니다 .
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
마찬가지로 Gradle을 사용하는 경우 build.gradle 에 다음을 추가합니다.
plugins {
id 'org.springframework.boot' version '2.6.4'
}
compile 'org.springframework.boot:spring-boot-starter-data-mongodb'
compile 'org.springframework.boot:spring-boot-starter-web'
대안으로 Spring Initializer 를 사용할 수 있습니다 .
2.2. 모델
먼저 모델을 추가해 보겠습니다. 서로 다른 두 데이터베이스에서 사용할 두 개의 문서를 만듭니다.
예를 들어 사용자 문서를 만듭니다.
@Document(collection = "user")
public class User {
@MongoId
private ObjectId id;
private String name;
private String surname;
private String email;
private int age;
// getters and setters
}
그런 다음 계정 문서 도 추가해 보겠습니다 .
@Document(collection = "account")
public class Account {
@MongoId
private ObjectId id;
private String userEmail;
private String nickName;
private String accountDomain;
private String password;
// getters and setters
}
2.3. 저장소
그런 다음 일부 Spring Data 메서드를 사용하여 각 모델 클래스에 대한 리포지토리를 만듭니다.
먼저 UserRepository 를 추가해 보겠습니다 .
@Repository
public interface UserRepository extends MongoRepository<User, String> {
User findByEmail(String email);
}
다음으로 AccountRepository 를 추가합니다 .
@Repository
public interface AccountRepository extends MongoRepository<Account, String> {
Account findByAccountDomain(String account);
}
2.4. 연결 속성
사용 중인 여러 데이터베이스의 속성을 정의해 보겠습니다.
mongodb.primary.host=localhost
mongodb.primary.database=db1
mongodb.primary.authenticationDatabase=admin
mongodb.primary.username=user1
mongodb.primary.password=password
mongodb.primary.port=27017
mongodb.secondary.host=localhost
mongodb.secondary.database=db2
mongodb.secondary.authenticationDatabase=admin
mongodb.secondary.username=user2
mongodb.secondary.password=password
mongodb.secondary.port=27017
인증에 사용할 특정 DB에 대한 속성이 있다는 점은 주목할 가치가 있습니다.
2.5. 기본 구성
이제 구성이 필요합니다. 우리는 각 데이터베이스에 대해 하나씩 만들 것입니다.
UserRepository 에 사용 중인 기본 클래스 정의를 살펴보겠습니다 .
@Configuration
@EnableMongoRepositories(basePackageClasses = UserRepository.class, mongoTemplateRef = "primaryMongoTemplate")
@EnableConfigurationProperties
public class PrimaryConfig {
// beans
}
시연을 위해 모든 빈과 어노테이션을 분석해 보겠습니다.
먼저 MongoProperties 를 사용하여 속성을 검색하고 설정합니다 . 이 방법으로 모든 속성을 빈에 직접 매핑합니다.
@Bean(name = "primaryProperties")
@ConfigurationProperties(prefix = "mongodb.primary")
@Primary
public MongoProperties primaryProperties() {
return new MongoProperties();
}
여러 사용자에게 액세스 권한을 부여하기 위해 MongoCredential 과 함께 MongoDB 인증 메커니즘 을 사용합니다 . 인증 데이터베이스( 이 경우 admin )를 추가하여 자격 증명 개체를 구성합니다.
@Bean(name = "primaryMongoClient")
public MongoClient mongoClient(@Qualifier("primaryProperties") MongoProperties mongoProperties) {
MongoCredential credential = MongoCredential
.createCredential(mongoProperties.getUsername(), mongoProperties.getAuthenticationDatabase(), mongoProperties.getPassword());
return MongoClients.create(MongoClientSettings.builder()
.applyToClusterSettings(builder -> builder
.hosts(singletonList(new ServerAddress(mongoProperties.getHost(), mongoProperties.getPort()))))
.credential(credential)
.build());
}
최신 릴리스에서 제안한 대로 연결 문자열에서 MongoTemplate 을 만드는 대신 SimpleMongoClientDatabaseFactory 를 사용하고 있습니다.
@Primary
@Bean(name = "primaryMongoDBFactory")
public MongoDatabaseFactory mongoDatabaseFactory(
@Qualifier("primaryMongoClient") MongoClient mongoClient,
@Qualifier("primaryProperties") MongoProperties mongoProperties) {
return new SimpleMongoClientDatabaseFactory(mongoClient, mongoProperties.getDatabase());
}
더 많은 데이터베이스 구성을 추가할 것이므로 여기에서 빈이 @Primary 여야 합니다 . 그렇지 않으면 앞서 논의한 고유성 제약 조건에 빠지게 됩니다.
여러 EntityManager 를 매핑할 때 JPA에서도 동일한 작업을 수행합니다 . 마찬가지로 @EnableMongoRepositories에 Mongotemplate 에 대한 참조가 필요합니다 .
@EnableMongoRepositories(basePackageClasses = UserRepository.class, mongoTemplateRef = "primaryMongoTemplate")
2.6. 보조 구성
마지막으로 재확인을 위해 두 번째 데이터베이스 구성을 살펴보겠습니다.
@Configuration
@EnableMongoRepositories(basePackageClasses = AccountRepository.class, mongoTemplateRef = "secondaryMongoTemplate")
@EnableConfigurationProperties
public class SecondaryConfig {
@Bean(name = "secondaryProperties")
@ConfigurationProperties(prefix = "mongodb.secondary")
public MongoProperties secondaryProperties() {
return new MongoProperties();
}
@Bean(name = "secondaryMongoClient")
public MongoClient mongoClient(@Qualifier("secondaryProperties") MongoProperties mongoProperties) {
MongoCredential credential = MongoCredential
.createCredential(mongoProperties.getUsername(), mongoProperties.getAuthenticationDatabase(), mongoProperties.getPassword());
return MongoClients.create(MongoClientSettings.builder()
.applyToClusterSettings(builder -> builder
.hosts(singletonList(new ServerAddress(mongoProperties.getHost(), mongodProperties.getPort()))))
.credential(credential)
.build());
}
@Bean(name = "secondaryMongoDBFactory")
public MongoDatabaseFactory mongoDatabaseFactory(
@Qualifier("secondaryMongoClient") MongoClient mongoClient,
@Qualifier("secondaryProperties") MongoProperties mongoProperties) {
return new SimpleMongoClientDatabaseFactory(mongoClient, mongoProperties.getDatabase());
}
@Bean(name = "secondaryMongoTemplate")
public MongoTemplate mongoTemplate(@Qualifier("secondaryMongoDBFactory") MongoDatabaseFactory mongoDatabaseFactory) {
return new MongoTemplate(mongoDatabaseFactory);
}
}
이 경우 AccountRepository 또는 동일한 패키지에 속하는 모든 클래스 를 참조합니다 .
3. 테스트
MongoDB 인스턴스에 대해 애플리케이션을 테스트합니다. Docker와 함께 MongoDB를 사용할 수 있습니다 .
3.1. MongoDB 컨테이너 시작
Docker Compose 를 사용하여 MongoDB 컨테이너를 실행해 보겠습니다 . YAML 템플릿을 살펴보겠습니다.
services:
mongo:
hostname: localhost
container_name: 'mongo'
image: 'mongo:latest'
expose:
- 27017
ports:
- 27017:27017
environment:
- MONGO_INITDB_DATABASE=admin
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=admin
volumes:
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
인증을 받으려면 루트 사용자로 초기화해야 합니다. 더 많은 사용자로 데이터베이스를 채우기 위해 JavaScript 초기화 파일에 바인드 마운트 를 추가하고 있습니다.
db.createUser(
{
user: "user1",
pwd: "password",
roles: [ { role: "readWrite", db: "db1" } ]
}
)
db.createUser(
{
user: "user2",
pwd: "password",
roles: [ { role: "readWrite", db: "db2" } ]
}
)
컨테이너를 실행해 보겠습니다.
docker-compose up -d
컨테이너가 시작되면 mongo-init.js 파일에 대한 볼륨을 생성하고 컨테이너의 진입점에 복사합니다.
3.2. 스프링 부트 테스트
몇 가지 기본 Spring Boot 테스트 에서 모두 함께 래핑해 보겠습니다 .
@SpringBootTest(classes = { SpringBootMultipeDbApplication.class })
@TestPropertySource("/multipledb/multidb.properties")
public class MultipleDbUnitTest {
// set up
@Test
void whenFindUserByEmail_thenNameOk() {
assertEquals("name", userRepository.findByEmail("user@gmail.com")
.getName());
}
@Test
void whenFindAccountByDomain_thenNickNameOk() {
assertEquals("nickname", accountRepository.findByAccountDomain("account@jira.baeldung.com")
.getNickName());
}
}
주로 데이터베이스에 대한 연결을 설정하고 인증을 받기를 원합니다. 그렇지 않으면 데이터베이스가 채워지지 않았거나 MongoDb 인스턴스가 시작되지 않았을 수 있습니다.
이러한 경우 DB 컨테이너의 로그를 볼 수 있습니다. 예를 들면 다음과 같습니다.
docker logs 30725c8635d4
초기 JavaScript는 컨테이너가 처음 실행될 때만 실행된다는 점은 주목할 가치가 있습니다. 따라서 다른 스크립트로 실행해야 하는 경우 볼륨을 삭제해야 할 수 있습니다.
docker-compose down -v
4. 결론
이 기사에서는 Spring Data MongoDB로 다중 연결을 생성하는 방법을 살펴보았습니다. 인증을 받기 위해 자격 증명을 추가하는 방법을 살펴보았습니다. 가장 중요한 것은 구성을 생성하는 방법을 보았으며 그 중 하나는 기본 빈과 함께 구성되어야 합니다. 마지막으로 Docker 및 Spring Boot 테스트를 사용하여 실행 중인 MongoDB 인스턴스에 대한 몇 가지 테스트 사례를 추가했습니다.
항상 그렇듯이 기사의 전체 코드는 GitHub 에서 사용할 수 있습니다 .