ABOUT ME

-

Graduate of Computer Engineering at Inha University

https://github.com/juwon0605

devprofessionalism@gmail.com
  • properties 불변 객체로 주입하기
    프로젝트/잡스캐너 2022. 9. 8. 21:23

     

    로그인시 발급하는 JWT를 생성할 때 secret 값과 expiry 값, 소셜 로그인할 때 url, client-id, client-secret 값 등을 application.yml에 설정하고 클래스에서는 @Value를 통해 주입했다.

    auth:
      client:
        kakao:
          token-url: https://kauth.kakao.com/oauth/token
          redirect-url: https://dev.jobscanner.app/oauth/callback/kakao
          client-id: 
          client-secret:
        google:
          token-url: https://oauth2.googleapis.com/token
          redirect-url: https://dev.jobscanner.app/oauth/callback/google
          client-id: 
          client-secret:
        github:
          token-url: https://github.com/login/oauth/access_token
          redirect-url: https://dev.jobscanner.app/oauth/callback/github
          client-id:
          client-secret:
      jwt:
        app-token-secret:
        refresh-token-secret:
        app-token-expiry:
        refresh-token-expiry:
    	@Value("${auth.jwt.app-token-expiry}")
    	private String appTokenExpiry;
    	@Value("${auth.jwt.refresh-token-expiry}")
    	private String refreshTokenExpiry;
    
    	private final Key appKey;
    	private final Key refreshKey;
    	private static final String AUTHORITIES_KEY = "role";
    
    	public AuthTokenProvider(
    		@Value("${auth.jwt.app-token-secret}") String appSecretKey,
    		@Value("${auth.jwt.refresh-token-secret}") String refreshSecretKey) {
    
    		this.appKey = Keys.hmacShaKeyFor(appSecretKey.getBytes());
    		this.refreshKey = Keys.hmacShaKeyFor(refreshSecretKey.getBytes());
    	}
    	@Value("${auth.client.kakao.token-url}")
    	private String tokenUrl;
    	@Value("${auth.client.kakao.redirect-url}")
    	private String redirectUrl;
    	@Value("${auth.client.kakao.client-id}")
    	private String clientId; // JavaScript 키
    	@Value("${auth.client.kakao.client-secret}")
    	private String clientSecret;

    하지만 @Value를 통해 주입하는 방법은 클래스가 생성된 이후에 Setter를 통해 주입해서 값을 주입 받은 객체를 final한 객체로 생성할 수 없다. 프로그램 관점에서 언제든지 값을 변경할 수 있는 변수는 에러와 버그를 만들어내는 주된 원인이다. 그래서 가능한 불변 객체를 생성하는 것이 좋다. 그런 이유에서 함수형 프로그래밍에서는 변수 변경을 아예 허용하지 않고 자바8 람다에서 변수를 변경할 수 없다.

    따라서 @Value를 통해 값을 주입하는 방법 말고 값을 불변 객체로 주입할 수 있는 방법을 찾아보고 적용했다.  바로 @ConstructorBinding을 사용하여 final 필드에 값을 주입하는 것이다. @ConfigurationProperties(prefix = )와@ConstructorBinding을 통해 .yml과 값을 매칭하고 @EnableConfigurationProperties 사용해 Spring Bean으로 등록하고 @Configuration해주는 것이다.

     

    @ConfigurationProperties(prefix = )와 @ConstructorBinding을 통해 .yml과 값을 매칭한다.

    @ConstructorBinding
    @ConfigurationProperties(prefix = "auth")
    public record AuthProperties(
    	Client client,
    	Jwt jwt
    ) {
    
    	public record Client(
    		Kakao kakao,
    		Google google,
    		Github github
    	) {
    		public record Kakao(
    			String tokenUrl,
    			String redirectUrl,
    			String clientId,
    			String clientSecret
    		) {
    		}
    
    		public record Google(
    			String tokenUrl,
    			String redirectUrl,
    			String clientId,
    			String clientSecret
    		) {
    		}
    
    		public record Github(
    			String tokenUrl,
    			String redirectUrl,
    			String clientId,
    			String clientSecret
    		) {
    		}
    	}
    
    	public record Jwt(
    		String appTokenSecret,
    		String refreshTokenSecret,
    		String appTokenExpiry,
    		String refreshTokenExpiry
    	) {
    	}
    }


    @EnableConfigurationProperties를 Spring Bean으로 등록하고 @Configruation한다.

    @Configuration
    @EnableConfigurationProperties(value = {AuthProperties.class})
    public class PropertiesConfig {
    }


    이렇게 설정하면 properties 값을 객체 생성시에 주입해서 불변 객체로 값을 주입할 수 있다.

    	private final String tokenUrl;
    	private final String redirectUrl;
    	private final String clientId;
    	private final String clientSecret;
    
    	public KakaoTokenValidator(AuthProperties authProperties) {
    		AuthProperties.Client.Kakao kakaoClient = authProperties.client().kakao();
    		this.tokenUrl = kakaoClient.tokenUrl();
    		this.redirectUrl = kakaoClient.redirectUrl();
    		this.clientId = kakaoClient.clientId();
    		this.clientSecret = kakaoClient.clientSecret();
    	}

     

    Setter로 주입하는 @Value 대신 불변 객체로 값을 주입할 수 있는 @ConstructorBinding을 사용하자!

     

    참고
    https://tecoble.techcourse.co.kr/post/2020-09-29-spring-properties-binding/

    댓글

Designed by Tistory.