Environment Abstraction

Spring์˜ Environment ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ์ธก๋ฉด์„ ์ถ”์ƒํ™”ํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ™˜๊ฒฝ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค: ํ”„๋กœํŒŒ์ผ(profiles)๊ณผ ํ”„๋กœํผํ‹ฐ(properties์ž…๋‹ˆ๋‹ค.

ํ”„๋กœํŒŒ์ผ์€ ํŠน์ • ์กฐ๊ฑด์—์„œ๋งŒ ํ™œ์„ฑํ™”๋˜๋Š” Bean ์ •์˜์˜ ๋…ผ๋ฆฌ์  ๊ทธ๋ฃน์„ ์˜๋ฏธํ•˜๋ฉฐ, ํ”„๋กœํผํ‹ฐ๋Š” ์—ฌ๋Ÿฌ ์ถœ์ฒ˜์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ์„ค์ • ๊ฐ’๋“ค์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‘ ๊ฐ€์ง€๋ฅผ ํ™œ์šฉํ•˜์—ฌ Spring ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ Bean์„ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Bean Definition Profiles

ํ”„๋กœํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ • ํ™˜๊ฒฝ์— ๋งž๊ฒŒ Bean์„ ๋‹ค๋ฅด๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” JNDI๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์„ค์ •ํ•˜๋Š” ์‹์œผ๋กœ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ Bean์„ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์šด์˜ ํ™˜๊ฒฝ์—์„œ JNDI๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ.

  • ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ํ…Œ์ŠคํŠธ ๋˜๋Š” ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋งŒ ํ™œ์„ฑํ™”ํ•  ๋•Œ.

  • ํŠน์ • ๊ณ ๊ฐ์—๊ฒŒ ๋งž์ถ˜ Bean์„ ๋“ฑ๋กํ•ด์•ผ ํ•  ๋•Œ.

ํ”„๋กœํŒŒ์ผ์„ ์ด์šฉํ•œ Bean ์ •์˜

๋‹ค์Œ์€ ๊ฐ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•  DataSource๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š” ์˜ˆ์ž…๋‹ˆ๋‹ค:

๊ฐœ๋ฐœ ํ™˜๊ฒฝ:

@Configuration
@Profile("development")
public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }
}

์šด์˜ ํ™˜๊ฒฝ:

@Configuration
@Profile("production")
public class JndiDataConfig {

    @Bean(destroyMethod = "") 
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}

@Profile ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํ”„๋กœํŒŒ์ผ์ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น Bean์ด ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. "production" ํ”„๋กœํŒŒ์ผ์ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ JndiDataConfig ํด๋ž˜์Šค๊ฐ€ ๋“ฑ๋ก๋˜๊ณ , "development" ํ”„๋กœํŒŒ์ผ์ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ StandaloneDataConfig ํด๋ž˜์Šค๊ฐ€ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœํŒŒ์ผ ํ‘œํ˜„์‹

@Profile ์• ๋…ธํ…Œ์ด์…˜์€ ๊ฐ„๋‹จํ•œ ํ”„๋กœํŒŒ์ผ ์ด๋ฆ„๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ณต์žกํ•œ ๋…ผ๋ฆฌ์‹์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, "production & us-east"์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋…ผ๋ฆฌ AND๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋…ผ๋ฆฌ OR์€ "production | us-east"๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ! ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ํ”„๋กœํŒŒ์ผ์ด ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ Bean์„ ๋“ฑ๋กํ•˜๋Š” ์กฐ๊ฑด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Profile์„ ์ด์šฉํ•œ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜

@Profile ์• ๋…ธํ…Œ์ด์…˜์€ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, @Profile("production")์„ ๋Œ€์‹ ํ•˜์—ฌ @Production์ด๋ผ๋Š” ์ปค์Šคํ…€ ์• ๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {
}

์ด์ œ @Profile("production") ๋Œ€์‹  @Production์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

XML์—์„œ์˜ ํ”„๋กœํŒŒ์ผ ์ •์˜

XML์—์„œ๋Š” ์š”์†Œ์˜ profile ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœํŒŒ์ผ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” XML์—์„œ ๊ฐ ํ”„๋กœํŒŒ์ผ์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค:

๊ฐœ๋ฐœ ํ™˜๊ฒฝ:

<beans profile="development"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc">
    <jdbc:embedded-database id="dataSource">
        <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
        <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
    </jdbc:embedded-database>
</beans>

์šด์˜ ํ™˜๊ฒฝ:

<beans profile="production"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:jee="http://www.springframework.org/schema/jee">
    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

์ด๋ ‡๊ฒŒ XML์—์„œ๋„ profile ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ™˜๊ฒฝ์— ๋งž๋Š” Bean์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœํŒŒ์ผ ํ™œ์„ฑํ™”

ํ”„๋กœํŒŒ์ผ์„ ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด ํ”„๋กœ๊ทธ๋žจ ์ฝ”๋“œ์—์„œ Environment API๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์‹œ์Šคํ…œ ์†์„ฑ์„ ํ†ตํ•ด ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ํ”„๋กœ๊ทธ๋žจ ์ฝ”๋“œ์—์„œ ํ”„๋กœํŒŒ์ผ์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();

๋˜๋Š” ์‹œ์Šคํ…œ ์†์„ฑ์„ ํ†ตํ•ด ํ”„๋กœํŒŒ์ผ์„ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

-Dspring.profiles.active="development"

๋””ํดํŠธ ํ”„๋กœํŒŒ์ผ

ํŠน์ • ํ”„๋กœํŒŒ์ผ์ด ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•  ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. "default"๋ผ๋Š” ์ด๋ฆ„์˜ ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ์ด ์žˆ์œผ๋ฉฐ, ์ด ํ”„๋กœํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ Bean ๊ตฌ์„ฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ์€ ํ™œ์„ฑํ™”๋œ ๋‹ค๋ฅธ ํ”„๋กœํŒŒ์ผ์ด ์—†์„ ๋•Œ๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

@Configuration
@Profile("default")
public class DefaultDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .build();
    }
}

PropertySource ์ถ”์ƒํ™”

Spring์˜ Environment๋Š” ๋‹ค์–‘ํ•œ PropertySource ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์ถœ์ฒ˜์—์„œ ์„ค์ • ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ Spring์˜ StandardEnvironment๋Š” JVM ์‹œ์Šคํ…œ ์†์„ฑ๊ณผ ์‹œ์Šคํ…œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsMyProperty = env.containsProperty("my-property");
System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);

@PropertySource ์‚ฌ์šฉ

@PropertySource ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋กœํผํ‹ฐ ํŒŒ์ผ์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, app.properties ํŒŒ์ผ์—์„œ testbean.name=myTestBean์ด๋ผ๋Š” ํ‚ค-๊ฐ’ ์Œ์„ ์ •์˜ํ•œ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

@Configuration
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {

    @Autowired
    Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("testbean.name"));
        return testBean;
    }
}

PropertySource์˜ ์ˆœ์„œ์™€ ์šฐ์„ ์ˆœ์œ„

Spring์€ ๋‹ค์–‘ํ•œ PropertySource๋ฅผ ๊ณ„์ธต์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹œ์Šคํ…œ ์†์„ฑ์ด ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ณด๋‹ค ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ง์ ‘ PropertySource๋ฅผ ์ •์˜ํ•˜์—ฌ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());

ํ”Œ๋ ˆ์ด์Šคํ™€๋” ํ•ด์„

ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋Š” ${property} ํ˜•์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” JVM ์‹œ์Šคํ…œ ์†์„ฑ์ด๋‚˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Spring์˜ Environment๋ฅผ ํ†ตํ•ด ์ •์˜๋œ ๋ชจ๋“  PropertySource์—์„œ ํ•ด์„๋ฉ๋‹ˆ๋‹ค.

<beans>
    <import resource="com/bank/service/${customer}-config.xml"/>
</beans>

์œ„ ์˜ˆ์‹œ์—์„œ๋Š” customer ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฐ’์œผ๋กœ ๋Œ€์ฒด๋˜๋ฉฐ, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Last updated

Was this helpful?