Framework/Spring

[Spring] 환경설정은 어떻게 할 수 있을까?

KOOCCI 2022. 8. 10. 22:59

목표 : 스프링에서 Environment 설정을 할 수 있다.


이번에 진행하고자 하는 사항은 Environment 설정이다.

조금 더 구체적으로 Environment Abstraction이며, 그 위치는 다음과 같다.

 

Environment Interface

 

Environment Abstraction이라는 단어들로 알 수 있듯, 환경에 대한 추상화, 즉, Spring에서는 Environment Interface를 제공한다.

 

주로, Environment Interface는 profiles 나 properties 처럼, 프로그램의 환경 변수 그리고, Applcation의 프로필을 관리할 때 사용하게 된다.

 

다음 Environment Interface 문서를 보도록 하자.

 

모든 것들의 Super Interface는 PropertyResolver이며, acceptsProfiles나 getDefaultProfiles 등의 Method로 프로필 정보를 받아올 수 있다.

PropertyResolver 의 경우, getProperty 등으로, 환경 변수를 가져올 수 있다.

Resolver 라는 건 보통 변환기와 같은 의미로 사용된다.
PropertyResolver 역시, 환경변수를 사용하기 좋게 변환하는 역할을 한다고 보면 이해하기 쉽다.

 

Profile

 

Profile의 경우는 보통 서버환경에 따라 설정값을 달리 할 경우가 많다.

dev 환경에서는 Profile에 dev를 설정하고, Testbed, staging 서버에서는 stage 혹은 tb, 그리고 상용 서버에선 prod 로 설정하면서 Properties나 Datasource를 다르게 읽는 경우가 가장 자주 쓰이게 된다.

 

그럼 사용 예시를 한번 보도록 하자.

 

Datasource

Datasource InterfaceDB Connection 관리를 위해 사용한다.

jdbc에서 connection을 단순히 open을 하면, 하나의 Connection 만 연결된다.

그러나, 웹서버에서는 여러 요청에 따라 DB 자원을 사용해야하는데, 하나의 Connection으로는 무리가 따른다.

따라서, DataSource를 통해 Connection을 관리(Connection Pool)한다.

 

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.HSQL)
        .addScript("my-schema.sql")
        .addScript("my-test-data.sql")
        .build();
}

위와 같이 dataSource를 Bean으로 등록했다고 하자.

소스를 보듯, Embedded된 Datasource로, 개발환경에서 사용하는 경우일 것이다.

 

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

이제 application의 DataSource가 상용 서버의 JNDI 디렉토리에 등록되어 있다고 가정하고, 이를 상용 환경에 배포할 수 있는 방법을 고려해야 한다.

 

@Bean(destroyMethod="")

destroyMethod는 Bean이 Application Context에서 종료될 때, 호출되는 메서드이다.

Context ctx = new InitialContext();

Connection Pool에 접근하기 위해서는 JNDI 서비스를 사용해야 하며, JNDI는 서버에서 관리하고 있는 리소스에 대한 정보를 알고 있고, 특정 리소스를 찾아 사용할 수 있도록 객체를 반환한다.

ctx.lookup("java:comp/env/jdbc/datasource");

lookup은 DNS 서버에서 IP를 찾 듯, 리소스를 찾은 후 리소스를 사용할 수 있도록 객체를 반환해주는 메서드다.

찾고자 하는 리소스는 jdbc/datasource이며, WAS인 톰캣에서 리소스를 관리하는 가상의 디렉터리는 "java:comp/env"이라는 뜻이다.

JNDI : JNDI(Java Naming and Directory Interface)는 디렉터리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한 자바 API다. (분산환경에서 자원을 연결해주는 기능)

 

@Profile

그럼 이제, Profile을 통해 어떻게 접근할 수 있을지 보도록 하자.

@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");
    }
}

위처럼 Annotation도 가능하지만, XML역시 가능하다.

<beans profile="development"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xsi:schemaLocation="...">

    <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:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

그리고, 다음과 같이, 어떤 Profile을 Active 시킬지, 설정할 수 있다.

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

그러나 위처럼 하면, 소스를 수정해야 하므로, 보통 properties로 설정을 하며, 다음과 같이 설정하여 구동한다.

# properties 파일일 때 (application-prod.properties)
spring.profiles.active=prod

# yml 파일일 때 (application-prod.xml)
spring:
  profiles:
    active: prod
java -jar -Dspring.profiles.active=prod application.jar

Wrap up

아마 가장 처음에 Spring 프로젝트를 시작할 때 설정하는 부분일 것으로 보인다.

환경 설정은 아주 간단히 작성하였지만, 연동하는 point가 많을 수록 그 양이 상당해지고, 그에 따라 관리해야할 포인트도 많아진다. (특히, 배포 시에 Property 파일을 바꾸는 작업을 할 때는 주의해야한다.)

 

위와 같이, 단순히 환경설정하는 방법만 알고 진행하는 것보다 ,그에 대한 자세한 내용을 알아보았다.