AWS의 documentDB의 경우 ec2를 통한 접속이 필요하여, local에는 Embedded MongoDB를 연결하였습니다. MongodbConfig에서는 환경변수 별로 MongoClientSettings가 달라지도록 구성하였습니다.
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '3.0.0'
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongodbProperties {
// Mongodb Connection 주소
private String host;
// Mongodb Connection 포트
private int port;
// Mongodb DB명
private String database;
// Mongodb user명
private String user;
// Mongodb pw
private String password;
}
@Slf4j
@Configuration
@Profile({"local"})
@RequiredArgsConstructor()
@EnableAutoConfiguration(exclude={EmbeddedMongoAutoConfiguration.class})
public class LocalMongodbConfig {
private final MongodbProperties mongodbProperties;
@Bean
public void connectEmbeddedMongodb() throws IOException {
MongodExecutable mongodExecutable = null;
log.info("======= Local MongoDB Setting=======");
MongodConfig mongodConfig = MongodConfig
.builder()
.version(Version.Main.PRODUCTION)
.net(new Net(mongodbProperties.getHost(), mongodbProperties.getPort(), Network.localhostIsIPv6()))
.build();
MongodStarter starter = MongodStarter.getDefaultInstance();
mongodExecutable = starter.prepare(mongodConfig);
mongodExecutable.start();
}
}
@Slf4j
@Configuration
@RequiredArgsConstructor
public class MongodbConfig extends AbstractMongoClientConfiguration {
private final MongodbProperties mongodbProperties;
@Override
public String getDatabaseName() {
return mongodbProperties.getDatabase();
}
/**
* MongoDB로 쿼리를 날리기 위한 mongo client를 생성합니다.
*
* @param
* @return
*/
@SneakyThrows
@Override
@Bean
public MongoClient mongoClient() {
log.info("Creating Mongodb Client Configuration");
MongoClientSettings mongoClientSettings = this.getMongodbBuilder().applyConnectionString(new ConnectionString(this.getConnectionString())).build();
return MongoClients.create(mongoClientSettings);
}
/**
* MongoDB 연결 url을 생성합니다.
*
* @param
* @return
*/
private String getConnectionString() {
String profile = System.getProperty("spring.profiles.active");
log.info("active profile for url : {}",profile);
String userInfo = "";
String conParam = "";
if (profile == "dev" || profile == "prod") {
userInfo = mongodbProperties.getUser()
.concat(":").concat(mongodbProperties.getPassword()).concat("@");
conParam = "?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false";
}
String mongoUrl = String.format(
"mongodb://%s%s:%s/%s%s",
userInfo,
mongodbProperties.getHost(),
mongodbProperties.getPort(),
mongodbProperties.getDatabase(),
conParam
);
log.info("mongo url : {}", mongoUrl);
return mongoUrl;
}
/**
* mongo client 생성을 위한 builder를 생성합니다.
* DocumentDB의 경우 TLS로 인해 pem, ssl 등의 보안 설정이 필요합니다.
*
* @param
* @return
*/
private MongoClientSettings.Builder getMongodbBuilder() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, KeyManagementException {
String profile = System.getProperty("spring.profiles.active");
log.info("active profile for builder : {}", profile);
if (profile.equals("dev") || profile.equals("prod")) {
String endOfCertificateDelimiter = "-----END CERTIFICATE-----";
File resource = new ClassPathResource("certs/rds-combined-ca-bundle.pem").getFile();
String pemContents = new String(Files.readAllBytes(resource.toPath()));
List<String> allCertificates = Arrays.stream(pemContents
.split(endOfCertificateDelimiter))
.filter(line -> !line.isBlank())
.map(line -> line + endOfCertificateDelimiter)
.collect(Collectors.toUnmodifiableList());
CertificateFactory certificateFactory = CertificateFactory.getInstance("x.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
// This allows us to use an in-memory key-store
keyStore.load(null);
MongoClientSettings.Builder builder = MongoClientSettings.builder();
for (int i = 0; i < allCertificates.size(); i++) {
String certString = allCertificates.get(i);
Certificate caCert = certificateFactory.generateCertificate(new ByteArrayInputStream(certString.getBytes()));
keyStore.setCertificateEntry(String.format("AWS-certificate-%s", i), caCert);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
builder.applyToSslSettings(ssl -> {
ssl.enabled(true).context(sslContext);
});
}
return builder;
}
return MongoClientSettings.builder();
}
}
@SpringBootTest(classes = {DefaultServiceImpl.class, MyBatisConfig.class, NoSqlQuery.class, MongodbConfig.class, MongodbProperties.class, MetadataMapper.class})
@EnableConfigurationProperties
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MetadataServiceTest {
@Autowired
DefaultServiceImpl defaultServiceImpl;
@Autowired
MetadataMapper metadataMapper;
@Test
@Order(3)
@DisplayName("columnsInfo mongoDB 삽입 후 비교 테스트")
public void insertAndCompareDefaulttest() throws Exception {
TableInfo tableInfo = new TableInfo();
tableInfo.setAccountId("mongo");
tableInfo.setSchemaName("monkey");
tableInfo.setDataSource("rd");
CrudLog metadataCrudLog = new CrudLog();
DefaultColumnsInfo defaultColumnsInfo = defaultServiceImpl.loadDefaultColumnInfo(tableInfo);
defaultServiceImpl.insertDefaultColumnsInfo(defaultColumnsInfo, metadataCrudLog);
assertThat(defaultServiceImpl.isComparePrimaryColumns(tableInfo)).isEqualTo(true);
}
}
참고
Embedded Mongodb : https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#reference
Spring Boot Connection to AWS documentDB : https://stackoverflow.com/questions/54230901/attaching-aws-documentdb-to-spring-boot-application