본문 바로가기
팀 프로젝트/최종 프로젝트

ConfigurationProperties로 민감정보 관리하기

by pon9 2025. 2. 11.

문제가 되는 상황

TOKEN_TIME처럼 민감한 정보들이 하드코딩되어있다.

설정 파일에서 관리해 줄 필요가 있었고, 모든 설정을 일일이 @Value 어노테이션으로 불러오면 코드가 복잡해질 것이다.

이런 불편함을 해소해 주는 어노테이션이 @ConfigurationProperties이다.

 

 

ConfigurationProperties

스프링의 @ConfigurationProperties는 외부 설정 파일(application.properties나 application.yml)에 정의된 설정 값을

타입 안정성이 있는 자바 빈인 POJO에 바인딩 해주는 어노테이션이다.

단순히 문자열로 읽어오는 게 아니라, 정수, 불리언, 리스트 등 다양한 타입으로 변환해서 자바 객체에 담아준다.

복잡한 설정 값을 계층적으로 매핑할 수 있어서, prefix를 이용해 설정 그룹을 분리할 수 있다.

이렇게 등록하면  "security" 로 시작하는 모든 설정이 이 클래스에 바인딩된다.

 

 

사용법

위의 사진과 같이 POJO클래스에 어노테이션을 붙이고,

메인 application에 @EnableConfigurationProperties어노테이션을 사용해 해당 클래스들을 빈으로 등록해준다.

각각의 POJO에 @Component 어노테이션을 붙이는 방법도 있는데, properties와 관련 있는 클래스들을 명시적으로 작성해두려고 해당 방식을 사용했다.

@Getter
@Setter
@Validated
@ConfigurationProperties(prefix = "jwt")
public class JwtSecurityProperties {

    private Secret secret = new Secret();
    private Token token = new Token();

    @Getter
    @Setter
    @NotBlank
    public static class Secret {
        private String key;
    }

    @Getter
    @Setter
    @NotNull
    public static class Token {
        private String prefix;
        private long expiration;
    }
}

POJO클래스 코드다. 해당 클래스의 경우 jwt.secret.key, jwt.token.prefix, jwt.token.expiration 총 3개의 설정이 바인딩된다.

@Validated 어노테이션을 이용하면 잘못된 설정 값이 어플리케이션에 들어오는 경우 조기 진단이 가능하다.

@Component
@Getter
@Setter
@ConfigurationProperties(prefix = "loadbalancer")
public class LoadBalancerConfigProperties {

    private List<String> servers;
    private List<Integer> weights;
    private int maxResponseTime;
    private int weightUpdatePeriod;

    @PostConstruct
    public void validate() {
        if (servers == null || weights == null || servers.size() != weights.size()) {
            throw new IllegalArgumentException("servers와 weights의 크기가 일치하지 않습니다.");
        }
        if (weightUpdatePeriod <= 0) {
            throw new IllegalArgumentException("weightUpdatePeriod는 0보다 커야 합니다.");
        }
    }
}

또는 이렇게 @PostConstruct를 이용하여 검증을 수행할 수도 있다.

 

@Setter는, 스프링이 이걸 통해 필드 접근해서 값을 주입하므로 필요하지만,

@ConstructorBinding과 생성자를 함께 사용하면 값이 생성자 인자에 주입되어서 immutable 객체를 만들 수 있다.

 

 

Immutable 객체란?

한번 생성된 후 내부 상태를 변경할 수 없는 객체를 뜻한다. 객체 생성 시에 모든 값이 정해지고 그 이후에는 그 값을 바꿀 수 없다.

setter가 없거나, 모든 필드가 final로 선언되어 있어 한번 초기화되면 더이상 수정할 수 없다는 뜻이다.

 

장점:

1. Thread-safe함:  객체가 불변하니까 여러 스레드에서 동시에 접근해도 상태가 바뀌지 않아서 동기화에 대한 걱정이 줄어든다.

2. 예측 가능성: 한번 값이 설정되면 변하지 않으니, 코드의 동작을 예측하기 쉬워진다.

3. 안정성: 값이 변경되지 않기 때문에, 사이드 이펙트가 없어서 유지보수하기 편하다.

 

하지만 현재 setter로 설정해놓은 이유는, 설정값에 @setter를 사용할 상황이 아니기 때문이다. 굳이 그 자체로 immutable한 객체를 생성자를 만드는 수고스러움을 들여서 immutable하게 만들 필요가 없다 느껴졌다.

'팀 프로젝트 > 최종 프로젝트' 카테고리의 다른 글

Java 자료구조와 Collection Framework  (0) 2025.02.12