[MongoDB] Spring Boot Embedded MongoDB 연결

남영민·2021년 12월 14일
0

AWS의 documentDB의 경우 ec2를 통한 접속이 필요하여, local에는 Embedded MongoDB를 연결하였습니다. MongodbConfig에서는 환경변수 별로 MongoClientSettings가 달라지도록 구성하였습니다.

gradle

implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '3.0.0'

Properties

@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;

}

LocalMongodbConfig

@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();

    }

}

MongodbConfig

@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();
    }

}

Test

@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

profile
성장하는 개발자

0개의 댓글