📋 테스트로 배우는 Spring Configuration 강의
2021-05-25글
배경 지식 강의
스프링 컨테이너와 스프링빈
컨테이너
스프링 컨테이너에 빈을 등록하기 위해서는 Configuration이 필요하다.
- XML
- Annotation 기반의 configuration
- java bean configuration
XML로 Configuration 설정하는 예시
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userRepository" class="nextstep.helloworld.core.xmlConfig.UserRepository"/>
<bean id="userService" class="nextstep.helloworld.core.xmlConfig.UserService">
<property name="userRepository" ref="userRepository"/>
</bean>
</beans>
- userRepository와 userService를 빈으로 등록함
ApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
ClassPathXmlApplicationContext
로 해당 XML파일을 로드해온다.getBeanDefinitionNames()
: 등록된 빈이름을 가져온다.
java bean configuration
학습 테스트 코드
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();
}
}
- HelloApplication 클래스를 기반으로 빈 등록을 할 것이다.
AuthenticationPrincipalConfig
// Java-based Configuration을 하기 위한 클래스로 지정하기
@Configuration
public class AuthenticationPrincipalConfig {
// AuthService 빈을 등록하기
@Bean
public AuthService authService() {
return new AuthService();
}
// AuthenticationPrincipalArgumentResolver를 빈 등록하고 authService에 대한 의존성을 주입하기
@Bean
public AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver() {
return new AuthenticationPrincipalArgumentResolver(authService());
}
}
@Configuration
: 메타 데이터를 설정할 수 있는 클래스가 된다.@Bean
과 특정 객체를 반환하는 메서드로 해당 객체를 빈으로 등록할 수 있다.- 빈들의 의존성 또한 직접 맺어줄 수 있다.
@Configuration 클래스도 빈 등록이 되나요?
🙆♀️
@Configuration 클래스의 메서드 순서와 빈 등록 순서는 상관이 없나요?
🙆♀️
@Test
void useSpringBean() {
ApplicationContext context = new AnnotationConfigApplicationContext(HelloApplication.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
System.out.println(Arrays.toString(beanDefinitionNames));
AuthService authService = context.getBean(AuthService.class); // 싱글톤 // new AuthService()이니까
AuthenticationPrincipalArgumentResolver resolver = context.getBean(AuthenticationPrincipalArgumentResolver.class);
assertThat(resolver.getAuthService()).isEqualTo(authService);
}
resolver에 있는 AuthService 객체와 빈으로 등록된 AuthService가 같은 객체인가?
🙆♀️
외부 파일의 값을 이용하기
properties 파일 접근
// Java-based Configuration을 하기 위한 클래스로 지정하기
// application.properties 파일을 활용하기 위한 설정 추가하기
@Configuration
@PropertySource("classpath:application.properties")
public class PropertySourceConfig {
private final Environment env;
public PropertySourceConfig(Environment env) {
this.env = env;
}
// application.properties의 security-jwt-token-secret-key 값을 활용하여 JwtTokenKeyProvider를 빈으로 등록하기
@Bean
public JwtTokenKeyProvider jwtTokenKeyProvider() {
return new JwtTokenKeyProvider("security-jwt-token-secret-key");
}
}
- Environment 라는 필드가 있다.
@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");
}
PropertySourceConfig
클래스로 컨텍스트를 만든다.- 사실 이 properties를 객체로 만들어 접근할 수도 있다.
@Value 주입
// 컴포넌트 스캔을 통한 빈 등록
@Component
public class JwtTokenExpireProvider {
// 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;
}
}
// Java-based Configuration을 하기 위한 클래스로 지정하기
// application.properties 파일을 활용하기 위한 설정 추가하기
// nextstep.helloworld.core.environment 내에 있는 스프링 빈을 스캔하기
@Configuration
@PropertySource("classpath:application.properties")
@ComponentScan("nextstep.helloworld.core.environment")
public class ValueConfig {
}
환경에 따라 properties 설정이 가능한가요?
🙆♀️ 환경에 맞게 deploy하기 - profile
스프링 컨테이너 설정 방법 히스토리
컨테이너 설정을 할 때는 메타정보를 통해 이루어진다.
맨 처음에는 XML기반으로 진행되었다.
이러면 프로덕션 코드와 의존 관계, 빈 등록 정보를 분리할 수 있었다.
이후 어노테이션 기반이 등장하면서 XML과 혼용하여 사용하였다.
등록할 빈들을 어노테이션으로 관리하였다.
Spring 3.0부터는 Java Bean 기반으로 이루어졌다.
XML로 관리하던 내용들을 Bean 등록을 통해 관리하였다.
Auto Configuration?
- jar dependency 기반으로 스프링 애플리케이션을 자동으로 설정해준다.
별다른 설정을 하지 않았는데도, DB 등에 관련한 것들을 마음 껏 쓸 수 있었다.
그 이유는 @SpringBootApplication
에 있는 @EnableAutoConfiguration
덕분이다.
컨텍스트를 로드하면 이정도의 AutoConfiguration들이 등록된다.
ex) jdbcTemplate을 생성해주지 않았는데도 자동으로 주입된다.
빈으로 등록되지 않은 클래스를 사용하면 컴파일 에러가 떠야하는데 나지 않는 이유는?
@ConditionalOnClass
덕분이다.
- DataSource, JdbcTemplate이 로드가 되면 동작한다.
H2ConsoleAutoConfiguration
h2 DB설정을 해주지 않았는데도 h2와 관련된 설정이 자동으로 된다.
이것도 이미 등록되어있기 때문에 가능하다.