개인적으로 spring cloud config server를 github repository와 연동해서 사용하고 있었다.
평상시 크게 불편함을 느끼지 못했는데 config server의 설정을 변경할 일이 있을 경우 손쉽게 값을 변경하기 어려워 테스트 하기 불편하여 jdbc로 변경하려고 한다.
Spring Cloud Config Server backend 구성
spring cloud config server는 다양한 backend를 구성할 수 있도록 autoconfiguration을 지원하고 있다.
EnvironmentRepositoryConfiguration에서 다양한 backend 구성 환경에 대한 설정을 제공하고 있는데 대략 다음과 같다.
이 중에 원하는 환경으로 구성하면 된다.
EnvironmentRepositoryConfiguration에는 위에 보이는 FactoryConfig 외에도 각 backend에 대한 *RepositoryConfiguration이 EnvironmentRepositoryConfiguration와 동등한 위치로 선언이 되어 있다.
(Class와 동등 위치의 outline을 보는 방법을 찾지 못해서 스샷이 없음)
예를 들어 JdbcRepositoryConfiguration은 다음과 같이 선언되어 있다.
@Configuration(proxyBeanMethods = false)
@Profile("jdbc")
@ConditionalOnClass(JdbcTemplate.class)
@ConditionalOnProperty(value = "spring.cloud.config.server.jdbc.enabled", matchIfMissing = true)
class JdbcRepositoryConfiguration {
@Bean
@ConditionalOnBean(JdbcTemplate.class)
public JdbcEnvironmentRepository jdbcEnvironmentRepository(JdbcEnvironmentRepositoryFactory factory,
JdbcEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
내가 사용하고자 하는 backend에 대해 관련 의존성을 추가하고 관련 profile을 활성화하면 되는 형태이다.
jdbc backend 구성
Spring Cloud Config Server documentation에는 JDBC backend에 대한 설명이 정말 짧게 안내되어 있다.
https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#_jdbc_backend
JDBC Backend
Spring Cloud Config Server supports JDBC (relational database) as a backend for configuration properties. You can enable this feature by adding spring-jdbc to the classpath and using the jdbc profile or by adding a bean of type JdbcEnvironmentRepository. If you include the right dependencies on the classpath (see the user guide for more details on that), Spring Boot configures a data source.
You can disable autoconfiguration for JdbcEnvironmentRepository by setting the spring.cloud.config.server.jdbc.enabled property to false.
The database needs to have a table called PROPERTIES with columns called APPLICATION, PROFILE, and LABEL (with the usual Environment meaning), plus KEY and VALUE for the key and value pairs in Properties style. All fields are of type String in Java, so you can make them VARCHAR of whatever length you need. Property values behave in the same way as they would if they came from Spring Boot properties files named {application}-{profile}.properties, including all the encryption and decryption, which will be applied as post-processing steps (that is, not in the repository implementation directly).
이 내용이 전부인데 간단하게 설명하면 다음과 같은 작업이 필요하다.
- spring-jdbc maven dependency 추가
- db에 테이블 생성
설정된 테이블에는 APPLICATION, PROFILE, LABEL, KEY , VALUE 값이 있어야 한다. - 실행 시 spring profile에 jdbc 추가
설정하기
Maven Repository 설정
다음과 같이 jdbc dependency를 추가한다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
DB table 생성
spring cloud config server의 jdbc 관련 properties 설정은 JdbcEnvironmentProperties로 제공된다.
기본 호출 query가 다음과 같이 설정되어 있다.
@ConfigurationProperties("spring.cloud.config.server.jdbc")
public class JdbcEnvironmentProperties implements EnvironmentRepositoryProperties {
private static final String DEFAULT_SQL = "SELECT \"KEY\", \"VALUE\" from PROPERTIES"
+ " where APPLICATION=? and PROFILE=? and LABEL=?";
//... 이하 생략
}
table을 입맛에 맞게 따로 생성하고 sql을 지정하여 사용할 수도 있고
별도 spring.cloud.config.server.jdbc.sql property 설정 없이 위 DEFAULT_SQL 쿼리를 사용한다면 해당 값으로 table을 만들어도 된다.
CREATE TABLE `PROPERTIES` (
`APPLICATION` VARCHAR(50) NOT NULL DEFAULT 'application',
`PROFILE` VARCHAR(50) NOT NULL DEFAULT 'default',
`LABEL` VARCHAR(50) NOT NULL DEFAULT 'master',
`KEY` VARCHAR(256) NOT NULL,
`VALUE` VARCHAR(1024) NOT NULL,
INDEX `UIX_PROPERTIES` (`APPLICATION`, `PROFILE`, `LABEL`, `KEY`) USING BTREE
);
데이터 저장 시 지켜야 할 규칙
query를 처리하는 JdbcEnvironmentRepository의 실행 부분을 살펴보면 다음과 같이 처리가 되어 있다.
@Override
public Environment findOne(String application, String profile, String label) {
String config = application;
if (StringUtils.isEmpty(label)) {
label = "master";
}
if (StringUtils.isEmpty(profile)) {
profile = "default";
}
if (!profile.startsWith("default")) {
profile = "default," + profile;
}
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
Environment environment = new Environment(application, profiles, label, null, null);
if (!config.startsWith("application")) {
config = "application," + config;
}
List<String> applications = new ArrayList<>(
new LinkedHashSet<>(Arrays.asList(StringUtils.commaDelimitedListToStringArray(config))));
List<String> envs = new ArrayList<>(new LinkedHashSet<>(Arrays.asList(profiles)));
Collections.reverse(applications);
Collections.reverse(envs);
for (String app : applications) {
for (String env : envs) {
// ... 이하 생략
}
}
}
- application은 조회 시 'application' 값도 같이 조회한다.
따라서 여러 application이 공통으로 사용할 값은 'application'으로 저장하면 된다. - profile은 조회 시 'default' 값도 같이 조회한다.
따라서 profile에 상관없이 사용하는 값은 모두 'default'로 저장하면 된다. - label은 지정하지 않을 경우 'master'로 조회하므로 기본 저장 시 'master'로 저장해야 한다.
예를 들어 application=bluesky-project, profile=localdev로 조회하면 다음의 4개의 쿼리 결과를 propertySource로 반영해서 응답한다.
SELECT `KEY`, `VALUE` from PROPERTIES where APPLICATION='bluesky-project' and PROFILE='localdev' and LABEL='master'
SELECT `KEY`, `VALUE` from PROPERTIES where APPLICATION='bluesky-project' and PROFILE='default' and LABEL='master'
SELECT `KEY`, `VALUE` from PROPERTIES where APPLICATION='application' and PROFILE='localdev' and LABEL='master'
SELECT `KEY`, `VALUE` from PROPERTIES where APPLICATION='application' and PROFILE='default' and LABEL='master'
properties 설정
spring jdbc의 properties를 설정한다.
spring.datasource.url=jdbc:mariadb://localhost:3306/<database>
spring.datasource.username=<유저네임>
spring.datasource.password=<비밀번호>
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
실행
해당 서버를 실행할 때 다음 profile로 실행한다.
-Dspring.profiles.active=jdbc
테스트하면서 발견한 문제점
내 경우 mariadb에서 조회를 하였는데 기본 제공되는 쿼리 실행 시 문제가 발생했다.
기본 제공되는 쿼리를 실행하면 아래와 같이 실행하는데
SELECT "KEY", "VALUE" from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?
이 결과가 다음과 같았다.
mariadb에서 조회할 때 "KEY"가 아닌 `KEY` 와 같은 형태로 사용해야 했다.
따라서 아래와 같이 sql을 선언해서 사용했다.
spring.cloud.config.server.jdbc.sql=SELECT \`KEY\`, \`VALUE\` from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?
'Study > Java' 카테고리의 다른 글
Selenium 사용해보기 (0) | 2022.11.26 |
---|---|
JDK 17부터 Locale language old ISO code 사용 비활성으로 기본 설정 변경 (0) | 2022.11.23 |
JDK 19 New Features (0) | 2022.09.21 |
Spring Boot GraphQL 사용해보기 (0) | 2022.09.02 |
Spring Rest Docs로 OpenAPI (Swagger) 문서를 만들어 Swagger UI로 호출하여 보기 (0) | 2022.06.17 |
@Validated annotation을 controller가 아닌 service, component layer에서 사용하기 (0) | 2022.06.08 |
[troubleshooting] eclipse (STS) 에서 refactor rename이 동작하지 않는 현상 (0) | 2022.06.08 |
Spring Boot project STS에서 열어보기 (0) | 2022.05.26 |
Spring Boot 2.7 Release Notes (0) | 2022.05.20 |
maven project에서 junit 5, assertJ 사용하기 (1) | 2022.04.25 |