๐Ÿ“‹ ํ…Œ์ŠคํŠธ๋กœ ๋ฐฐ์šฐ๋Š” Spring Configuration ๊ฐ•์˜


๋ฐฐ๊ฒฝ ์ง€์‹ ๊ฐ•์˜

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์Šคํ”„๋ง๋นˆ

์ปจํ…Œ์ด๋„ˆ

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋นˆ์„ ๋“ฑ๋กํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” 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์™€ ๊ด€๋ จ๋œ ์„ค์ •์ด ์ž๋™์œผ๋กœ ๋œ๋‹ค.

์ด๊ฒƒ๋„ ์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ•˜๋‹ค.