Bepoz
파즈의 공부 일기
Bepoz
전체 방문자
오늘
어제
  • 분류 전체보기 (232)
    • 공부 기록들 (85)
      • 우테코 (17)
    • Spring (85)
    • Java (43)
    • Infra (17)
    • 책 정리 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Bepoz
공부 기록들/우테코

Spring Configuration 기초 정리

공부 기록들/우테코

Spring Configuration 기초 정리

2021. 5. 2. 20:09

Spring Configuration 기초 정리

@Configuration과 @Bean

class JavaConfigTest {
    @Test
    void javaConfig() {
        ApplicationContext context = new AnnotationConfigApplicationContext(HelloApplication.class);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames));

        AuthService authService = context.getBean(AuthService.class);
        assertThat(authService).isNotNull();
    }
}

public class AuthService {
    public String findMemberName() {
        return "사용자";
    }
}

public class AuthenticationPrincipalArgumentResolver {
    private AuthService authService;

    public AuthenticationPrincipalArgumentResolver(AuthService authService) {
        this.authService = authService;
    }

    public String findMemberName() {
        return authService.findMemberName();
    }

    public AuthService getAuthService() {
        return authService;
    }
}

@Configuration
public class AuthenticationPrincipalConfig {

    // TODO: AuthService 빈을 등록하기
    @Bean
    public AuthService authService() {
        return new AuthService();
    }

    // TODO: AuthenticationPrincipalArgumentResolver를 빈 등록하고 authService에 대한 의존성을 주입하기
    @Bean
    public AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver() {
        return new AuthenticationPrincipalArgumentResolver(authService());
    }
}

@Configuration 내부에는 @Component가 들어있어서 @SpringBootApplication어노테이션 내부의 @ComponentScan을 통해 빈 등록이 가능하다. 처음에 나는 AuthenticationPrincipalConfig 클래스의 메서드들 위에 @Bean을 붙여주지 않은 상태로 테스트를 돌렸었다. 결과는 성공이었다. 성공 후에 어 그러면 @Bean 생략해도 되는거 아니야? 라고 착각했다. 테스트가 통과했던 이유는 무의식적으로 AuthService 클래스 위에 @Service어노테이션을 붙여주었기 때문이었다.

내가 만든 서비스나 레포지토리가 아닌 외부 라이브러리들을 사용하고자 할 때에 해당 라이브러리 클래스에 @Service나 @Repository를 붙일 수 없다. 이 두 어노테이션 또한 @Component가 내부에 들어가 있기에 컴포넌트스캔으로 읽어들여 빈 등록을 할 수가 있는 것이다. 만약 해당 어노테이션이 없는 클래스들을 빈 등록하기 위해서는 @Bean을 통해서 빈 등록을 해야만 한다. 내가 처음에 착각했던 것은 클래스 위에 @Configuration을 붙이면 내부가 다 빈 등록이 되는 것 아닌가? 라고 착각했었다. 해당 어노테이션을 붙이면 정확히는 AuthenticationPrincipalConfig객체가 빈 등록이 된다. 테스트 코드에 이 객체를 찾게끔 하면 테스트과 통과될 것이다. 우리는 Config 라는 클래스를 여러 객체들을 빈 등록 시켜주기 위한 클래스로 사용하게된다. 위의 경우에서는 @Service를 붙이지 않은 AuthService를 AuthenticationPrincipalConfig클래스에서 @Bean을 통해 빈 등록을 해주는 과정인 것이다.

추가적으로 @Configuration은 싱글턴 컨테이너를 보장하는 역할도 해준다.


@PropertySource와 @Value

    @Test
    void key() {
        ApplicationContext context = new AnnotationConfigApplicationContext(PropertySourceConfig.class);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames));

        JwtTokenKeyProvider jwtTokenKeyProvider = context.getBean(JwtTokenKeyProvider.class);
        assertThat(jwtTokenKeyProvider.getSecretKey()).isEqualTo("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.ih1aovtQShabQ7l0cINw4k1fagApg3qLWiB8Kt59Lno");
    }

@Configuration
@PropertySource("classpath:application.properties")
public class PropertySourceConfig {

    private final Environment env;

    public PropertySourceConfig(Environment env) {
        this.env = env;
    }

    // TODO: application.properties의 security-jwt-token-secret-key 값을 활용하여 JwtTokenKeyProvider를 빈으로 등록하기
    @Bean
    public JwtTokenKeyProvider jwtTokenKeyProvider() {
        return new JwtTokenKeyProvider(env.getProperty("security-jwt-token-secret-key"));
    }
}

@Component
public class JwtTokenExpireProvider {
    // TODO: application.properties의 security-jwt-token-expire-length 값을 활용하여 validityInMilliseconds값 초기화 하기
    private long validityInMilliseconds;

    public JwtTokenExpireProvider(@Value("${security-jwt-token-expire-length}")long validityInMilliseconds) {
        this.validityInMilliseconds = validityInMilliseconds;
    }

    public long getValidityInMilliseconds() {
        return validityInMilliseconds;
    }
}

//application.properties
security-jwt-token-secret-key= eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.ih1aovtQShabQ7l0cINw4k1fagApg3qLWiB8Kt59Lno
security-jwt-token-expire-length= 3600000

@Value("${...}")을 통해 application.properties의 값을 가져올 수 있다.
만약 해당 값이 없는 경우에는 IllegalArgumentException이 발생하기 때문에, @Value("${keyValue:defaultValue}")와 같이 디폴트 값을 설정해 줄 수가 있다. 세미콜론 앞에는 공백이 있어서는 안된다. 만약 있게된다면 디폴트 값이 들어가게 될 것이다.
@Value는 properties의 값을 가져올 뿐만 아니라 @Value{"bepoz"} String name 다음과 같은 방법으로 값을 바로 주입해주는 방법으로 또한 사용할 수가 있다. Map과 List 형식 또한 가져와서 주입해줄 수가 있다.

@Value 말고 @PropertySource를 이용해서 값을 가져오는 방법도 있다. 위의 코드에 나와있는 것처럼 @PropertySource("classpath:Application.properities")와 같이 경로를 작성하고 Environment를 주입받아 getProperty메서드를 이용해서 속성 값을 가져올 수가 있다.

@PropertySource는 yml 파일은 지원하지 않기 때문에 별도의 추가적인 클래스를 만들어서 설정해주어야 한다.

public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
        Properties propertiesFromYaml = loadYamlIntoProperties(resource);
        String sourceName = name != null ? name : resource.getResource().getFilename();
        return new PropertiesPropertySource(sourceName, propertiesFromYaml);
    }

    private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
        try {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return factory.getObject();
        } catch (IllegalStateException e) {
            // for ignoreResourceNotFound
            Throwable cause = e.getCause();
            if (cause instanceof FileNotFoundException)
                throw (FileNotFoundException) e.getCause();
            throw e;
        }
    }
}

@PropertySource(value = "classpath:application.yml", factory = YamlPropertySourceFactory.class)

위와 같이 말이다.

@ExtendWith(SpringExtension.class)
@TestPropertySource("classpath:application.yml")
public class PropertySourceTest {

    @Autowired
    Environment env;

    @Test
    @DisplayName("asdf")
    public void asdf() {
        String sec = env.getProperty("security-jwt-token-expire-length");
        System.out.println(sec);
        assertThat(sec).isEqualTo("3600000");
    }
}

@TestPropertySource의 경우에는 yml 파일을 읽어들일 수 있는 것을 확인하였다.
test 패키지 안의 resources 패키지를 먼저 확인하고 그 이후에 프로덕션 resources 패키지를 확인하고 있었다.


Reference

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-using-propertysource

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-value-annotations

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-java-basic-concepts

https://vsh123.github.io/spring%20boot/spring-boot-yml/

'공부 기록들 > 우테코' 카테고리의 다른 글

Spring Auth 기초 정리  (0) 2021.04.27
Spring MVC Config 기초 정리  (0) 2021.04.25
Spring CORE 기초 정리  (0) 2021.04.23
Spring JDBC 기초 사용법 정리  (0) 2021.04.22
Spring MVC 기초 정리  (0) 2021.04.15
    '공부 기록들/우테코' 카테고리의 다른 글
    • Spring Auth 기초 정리
    • Spring MVC Config 기초 정리
    • Spring CORE 기초 정리
    • Spring JDBC 기초 사용법 정리
    Bepoz
    Bepoz
    https://github.com/Be-poz/TIL

    티스토리툴바

    단축키

    내 블로그

    내 블로그 - 관리자 홈 전환
    Q
    Q
    새 글 쓰기
    W
    W

    블로그 게시글

    글 수정 (권한 있는 경우)
    E
    E
    댓글 영역으로 이동
    C
    C

    모든 영역

    이 페이지의 URL 복사
    S
    S
    맨 위로 이동
    T
    T
    티스토리 홈 이동
    H
    H
    단축키 안내
    Shift + /
    ⇧ + /

    * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.