행복한 아빠

[Grails1.0 사용자 가이드] 3. Configuration 본문

Grails

[Grails1.0 사용자 가이드] 3. Configuration

행복한아빠 2008. 2. 28. 17:57


3. Configuration

프레임워크에서 지금 논의할 주제인 "약속(convention)에 의한 configuration"을 말하는 것이 이상할 수 있다. 그러나 전형적으로 Grails에는 하나의 configuration이 있으니 이것을 제외하고 있야기 하는 것이 최선이다.

Grails의 기본 셋팅만으로도 아무 configuration 조정없이 application 개발이 실제 가능하다. Grails는 메모리에서 동작하는 HSQLDB를 내장하고 있어 데이터베이스 셋업이 필요없다.

어쨌든 어느 순간 실 데이터베이스 설정이 필요할 것이고 다음 장에서 어떻게 하는지 설명할 것이다.

3.1 기본 Configuration
Grails이 제공하는 전반적인 configuration 파일은 grails-app/conf/Config.groovy이다. 이 파일은 자바 properties와 매우 비슷한 Groovy의 ConfigSlurper를 사용하는데 다른점은 이 파일의 변수를 재사용할 수 있으며 적당한 자바 type을 사용하는 순수 Groovy 파일인 점이다.

여기에 아래 예와 같이 당신 자신의 configuration을 추가할 수 있다.

foo.bar.hello = "world"

그 후 두 가지 방법중 하나로 애플리케이션에서 이 설정에 접근할 수 있다. 가장 일반적인 것은 GrailsApplication 객체로 접근하는 것이고 이것은 컨트롤러와 tag 라이브러리에서 사용할 수 있다.

assert "world" == grailsApplication.config.foo.bar.hello

다른 방법은 configuration 객체 레퍼런스를 가지고 있는 ConfigurationHolder를 이용하는 것이다.

import org.codehaus.groovy.grails.commons.*

def config = ConfigurationHolder.config
assert "world" == config.foo.bar.hello


3.1.1 내장 옵션들
또한 Grils는 다음의 configuration 옵션들을 제공한다.

  • grails.config.locations: properties 파일들의 위치 또는 메인 configuration과 합쳐질 추가 Grails Config 파일들
  • grails.enable.native2ascii: Grails의 국제화(i18n) 프로퍼티 파일에 native2ascii 변환을 사용할 필요가 없을 경우 false로 설정한다.
  • grails.views.default.codec: GSP의 인코딩 방법을 설정 - 'none', 'html', 'base64' 중 하나 (기본: 'none'). XSS 공격의 위험을 줄일려면 'html'로 설정한다.
  • grails.views.gsp.encoding: GSP 소스 파일의 파일 인코딩을 설정한다. (기본: utf-8)
  • grails.war.destFile: war 명령어가 생성하는 WAR 파일의 위치를 설정한다.
  • grails.mime.file.extensions: Content Negotiation에서 mimi 타입 결정하기 위해 파일 확장자를 쓸지 말지
  • grails.mime.types - Content Negotiation에서 사용할 지원하는 mime 타입의 맵


3.1.2 로깅
로깅 기본
Grails는 log4j 로그 시스템을 사용하며 log4j 구성을 위해 Grails 공통의 common 메커니즘을 사용한다. loggin 구성을 위해 grails-app/conf/ 디렉토리의 Config.groovy를 수정한다. 이 하나의 Config.groovy 파일에서 개발, 테스트, 운영(production) 환경의 분리된 로그 구성을 설정하도록 한다. Grails는 Config.groovy 파일을 처리하여 web-app/WEB-INF/classes 디렉토리에 적당한 log4.properties 파일을 생성한다.

다음은 Grails에서의 전형적인 Log4j 구성이다.

log4j {
    appender.stdout = "org.apache.log4j.ConsoleAppender"
 appender.'stdout.layout'="org.apache.log4j.PatternLayout"
    rootLogger="error,stdout"
    logger {
        grails="info,stdout"
        org {
            grails.spring="info,stdout"
            codehaus.groovy.grails.web="info,stdout"
            codehaus.groovy.grails.commons="info,stdout"
            …
        }
}

만일 표준 Log4j properties 파일 스타일로 구성하는 것을 좋아한다면 대신 Groovy의 멑티라인 스트링을 사용할 수 있다.

log4j = '''
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# ...remaining configuration
'''

아래 유용한 logger를 포함한다.

  • org.codehaus.groovy.grails.commons: 클래스 로딩등과 같은 핵심 정보
  • org.codehaus.groovy.grails.web: Grails 웹 요청 프로세싱
  • org.codehaus.groovy.grails.web.mapping: URL 매핑 디버깅
  • org.codehaus.groovy.grails.plugins: 플러그인 활동정보를 로깅
  • org.springframework: Spring이 하는 일을 본다. - See what Spring is doing
  • org.hibernate: hibernate가 하는 일을 본다.

Full stacktraces
예외가 발생했을때 자바와 Groovy 내부에서 발생한 stacktrace 도배로 끔찍할 수 있다. Grails는 보통 관련없는 세부사항을 걸러내거나 핵심이 아닌 Grails/Groovy 클래스 패키지의 추적을 제한한다.

예외 발생시 full trace를 항상 StackTrace 로거에 쓴다. 이 로그는 stacktrace.log에 남는다. Config.groovy에서 원하는 파일위치로 바꿀 수 있다. 예를 들어 full stack trace를 표준출력으로 돌리고 싶다면 다음의 라인을

StackTrace="error,errors"

다음과 같이 변경한다.

StackTrace="error,stdout"

VM 프로퍼티에 grails.full.stacktrace를 ture로 설정함으로써 stacktrace 필터링을 완전히 제거할 수 있다.

grails -Dgrails.full.stacktrace=true run-app

약속(convention)에 의한 로깅
모든 애플리케이션 소스(artefact)는 동적으로 추가된 log 프로퍼티를 가지고 있다. 도메인 클래스, 컨트롤러, tag 라이브러리 등 모두 포함된다. 아래는 log의 사용예이다.

def foo = "bar"
log.debug "The value of foo is $foo"

로그는 grails.app.소스타입.ClassName 형식의 약속에 의해 명명된다. 아래는 서로 다른 소스타입의 로그 구성에 대한 예제이다.

# 모든 애플리케이션 소스에 대한 레벨 설정
log4j.logger.grails.app="info, stdout"
# 특정 컨트롤러 설정
log4j.logger.grails.app.controller.YourController="debug, stdout"
# 특정 도메인 클래스 설정
log4j.logger.grails.app.domain.Book="debug, stdout"
# 특정 tag 라이브러리 설정
log4j.logger.grails.app.tagLib.FancyAjax="debug, stdout"
# 모든 tag 라이브러리 설정
log4j.logger.grails.app.tagLib="info, stdout"

소스이름은 약속에 따라 결정된다. 아래는 공통적인 것들이다.

  • bootstrap - 부트스트랩 클래스들을 위한 것
  • dataSource - 데이터소스들을 위한 것
  • tagLib - tag 라이브러리들을 위한 것
  • service - 서비스 클래스들을 위한 것
  • controller - 컨트롤러들을 위한 것
  • domain - 도메인 클래스들을 위한 것


3.2 환경
환경별 Configuration
Grails는 환경별 configuration 개념을 지원한다. grails-app/conf 디렉토리의 Config.groovy와 DataSource.groovy 두 파일로 ConfigSlurper의 문법을 이용하여 환경별 configuration의 장점을 이용할 수 있다.
Grails에서 제공하는 다음의 기본 DataSource 정의 예제를 살펴보자.

dataSource {
    pooled = false                         
    driverClassName = "org.hsqldb.jdbcDriver"
    username = "sa"
    password = ""    
}
environments {
    development {
        dataSource {
            dbCreate = "create-drop" // one of 'create', 'createeate-drop','update'
            url = "jdbc:hsqldb:mem:devDB"
        }
    }  
    test {
        dataSource {
            dbCreate = "update"
            url = "jdbc:hsqldb:mem:testDb"
        }
    }  
    production {
        dataSource {
            dbCreate = "update"
            url = "jdbc:hsqldb:file:prodDb;shutdown=true"
        }
    }
}

최상위에서 공통 configuration을 어떻게 제공하고 환경 블럭이 DataSource의 dbCreate와 url 속성을 환경별로 어떻게 지정하는지 주목한다. 이 문법은 Config.groovy에서도 사용한다.

환경별로 패키징하기와 실행하기
Grails의 모든 명령어는 특정 환경의 상황에서 실행할 수 있는 기능이 있다. 포맷은 아래와 같다.

grails [환경] [명령어]

덧붙여 Grails가 인식하는 미리 설정된 3개의 환경(dev, prod, test)이 있다. dev는 개발환경, prod는 운영(production)환경, test는 테스트환경을 위한 것이다. 예를 들어 테스트환경을 위한 WAR를 생성하기 위해서는 다음과 같이 할 수 있다.

grails test war

자신에게 필요한 미리 설정된 것 외의 다른 환경을 지정하기 위해서는 명령어에 grails.env 변수를 전달한다. (모든 명령어 공통)
grails -Dgrails.env=UAT run-app

프로그램에서 환경 알아내기
Gant 스크립트나 부트스트랩 클래스와 같은 코드에서 GrailsUtil 클래스를 이용하여 환경을 알아낼 수 있다.

import grails.util.GrailsUtil...switch(GrailsUtil.environment) {
   case "development":
      configureForDevelopment()
   break
   case "production":
      configureForProduction()
   break
}


3.3 데이터소스
Grails가 자바 기술을 기반으로 하기에 데이터소스를 설정하기 위해서는 JDBC에 대해 좀 알아야 한다.

HSQLDB대신 다른 데이터베이스를 사용하기 위해서는 반드시 JDBC 드라이버가 필요하다. 예를 들어 MySQL를 위해서는 Connector/J가 필요하다.

드라이버는 일반적으로 JAR 압축 형태로 제공된다. JAR 파일을 프로젝트의 lib 디렉토리에 넣는다.

JAR를 lib에 넣었다면 grails-app/conf/DataSource.groovy에 있는 Grails의 DataSource desciptor에 익숙해질 필요가 있다. 이 파일은 다음 설정을 포함한 데이터소스 설정을 가지고 있다.

  • driverClassName: JDBC 드라이버 클래스 이름
  • username: JDBC 연결에 사용할 username
  • password: JDBC 연결에 사용할 비밀번호
  • url: 데이터베이스의 JDBC URL
  • dbCreate: 도메인 모델로 데이터베이스를 자동 생성할 지 여부
  • pooled: connection pool을 사용할 지 여부 (기본값은 true)
  • logSql: SQL 로깅 활성화
  • dialect: 데이터베이스와 연동하기 위해 사용하는 Hibernate daialect를 표현하는 문자열이나 클래스

MySQL을 위한 전형적인 configuration은 다음과 같다

dataSource {
 pooled = true
 dbCreate = "update"
 url = "jdbc:mysql://localhost/yourDB"
 driverClassName = "com.mysql.jdbc.Driver"
 username = "yourUser"
 password = "yourPassword"
}


 

사용자 삽입 이미지
데이터소스 설정시 어떤 configuration 설정에도 타입이나 def 키워드를 포함하지 않는다. 타입이나 def 키워드는 Groovy가 지역 변수 정의로 취급하고 제대로 처리하지 않는다. 다음과 같은 예제는 유효하지 않다.

dataSource {
 boolean pooled = true // 타입정의는 지역 변수가 된다.
 …
}


3.3.1 데이터소스와 환경
이전의 예제 configuration은 개발, 테스트, 배포 등 모든 환경을 동일하게 하는 것으로 간주하고 있다.

Grails 데이터소스 정의는 "환경을 감지"(environment aware)다음과 같이 할 수 있다.

dataSource {
 // 공통 설정은 여기에
}                    
environments {
  production {
     dataSource {
          url = "jdbc:mysql://liveip.com/liveDb"    
     }  
  }
}


3.3.2 JNDI 데이터소스
보통 많은 자바 Enterprise Edition 컨테이너들이 Java Naming and Directory Interface(JNDI)를 통해 데이터소스를 제공하고 있다. 어떤 때는 JNDI를 통한 데이터소스 look-up이 필요할 것이다.

Grails 다음과 같이 JNDI 데이터소스 정의를 할 수 있도록 지원한다.

dataSource {
    jndiName = "java:comp/env/myDataSource"
}

JNDI 이름 포맷은 컨테이너에 따라 다양하다. 그러나 데이터소스 정의하는 방법은 동일하다.

3.3.3 자동 데이터베이스 이주(Migration)
데이터소스 정의의 dbCreate 속성은 Grails가 실행시간에 GORM 클래스로부터 데이터베이스 테이블을 자동으로 생성하는 것을 지시하기에 매우 중요하다. 그 옵션들은 다음과 같다.

  • create-drop: Grail가 실행될 때 데이터베이스를 drop하고 다시 생성
  • create: 데이터베이스가 없으면 생성, 수정하지는 않는다. 이미 있던 데이터는 삭제한다.
  • update: 데이터베이스가 없으면 생성 있으면 수정
사용자 삽입 이미지
create-drop과 create 둘은 기존의 데이터를 삭제한다. 따라서 주의해서 사용한다.

개발모드에서는 dbCreate가 기본으로 "create-drop"으로 설정되어있다.

dataSource {
 dbCreate = "create-drop" // one of 'create', 'create-drop','update'
}

이 설정은 애플리케이션이 재실행될때마다 매번 데이터베이스 테이블을 drop하고 다시 생성한다. 물론 이것은 운영(production)에서 원하는 설정이 아닐 것이다.

사용자 삽입 이미지
비록 현재 Grails가 그외로 Rails 스타일의 migration을 지원하지 않더라도 비슷한 기능을 지원하는 두개의 플러그인이 있다. LiquiBase 플로그인과 DBMigrate 플래그인 둘 다 grails list-plugins 명령으로 볼 수 있다.


3.4 외부 Configuration
대부분의 경우 기본 configuration 파일인 grails-app/conf의 Config.groovy로도 훌륭하다. 그러나 주요 애플리케이션 구조에 있지 않은 configuration 파일을 유지할 필요가 있을 경우가 있다. 예를들면 만일 어떤 관리도구를 WAR로 배포할 때 configuration 변경 때문에 다시 패키징하는 것을 피하기 위하여 configuration을 WAR밖으로 내놓고 싶을 것이다.

위와 같은 배포 시나리오를 지원하기 위해 configuration을 밖으로 내놓을(externalize) 수 있다. 이렇게 하기 위해서는 Config.groovy의 grails.config.locations 설정을 추가하는 방법으로 Grails에 configuration 파일의 위치를 가르킬 필요가 있다.

grails.config.locations = [ "classpath:${appName}-config.properties",
                            "classpath:${appName}-config.groovy",
                            "file:${userHome}/.grails/${appName}-config.properties",
                            "file:${userHome}/.grails/${appName}-config.groovy"]

위의 예제에서 서로 다른 classpath와 USER_HOME의 파일 위치에서 configuration 파일(자바 프로퍼티 파일과 ConfigSlurper 둘 다)을 로딩한다.

결국은 모든 configuration 파일은 GrailsApplication 객체의 config 프로퍼틸로 합쳐지고 따라서 이 객체로 configuration 값들을 획득할 수 있다.

사용자 삽입 이미지
또한 Grails는 Spring에서 정의하는 프로퍼티 place holder와 프로퍼티 재정의 configurer 개념을 지원한다. 이것들의 더 자세한 정보는 Grails과 Spring 장에 있다.


3.5 버전 붙이기(Versioning)
버전 붙이기 기본
Grials는 애플리케이션 versioning 기능을 내장하고 있다. create-app 명령어로 처음 애플리케이션을 생성할 때 애플리케이션 버전은 0.1로 설정된다. 이 버전은 프로젝트 루트디렉토리의 application.properties라는 메타데이터 파일에 저장한다.

애플리케이션 버전을 변경하기 위해서는 set-version 명령어를 실행할 수 있다.

grails set-version 0.2

이 버전은 다양한 명령어에서 사용할 수 있는데 war 명령어의 경우 WAR 파일을 생성하고 마지막에 애플리케이션 버전을 붙인다.

실행시간에 버전 알아내기
애플리케이션 메타데이터 지원을 위한 Grails의 GrailsApplication 클래스를 이용하여 애플리케이션 버전을 알아낼 수 있다. 예를 들어 컨트롤러에는 이것을 이용할 수 있도록 grailsApplication 변수가 기본으로 포함되어 있다.

def version = grailsApplication.metadata['app.version']

Grails의 버전을 알아내기 위해서는 다음과 같이 할 수 있거나

def grailsVersion = grailsApplication.metadata['app.grails.version']

GrailsUtil 클래스를 이용하기도 한다.

import grails.util.*
def grailsVersion = GrailsUtil.grailsVersion


3.6 배포
빠른 배포
Grails 애플리케이션을 항상 운영(production) 환경에서 WAS 파일로 배포한다. Grails 애플리케이션을 절대 run-app 명령으로 배포하지 않는다. 이 명령어는 개발하는 동안 configuration을 자동으로 다시 읽으므로 매우 비용이 높고 규모를 확장하기 어렵다.

여하튼 Grails 애플리케이션을 run-war 명령어로 빠르고 쉬운 방법으로 배포할 수 있다. 다음과 같이 한다.

grails prod run-war

또는 다음과 같이 80 포트로 배포한다.

grails -Dserver.port=80 prod run-war

위 두 예제는 WAR 파일을 만들고 운영(production) 환경으로 Jetty를 이용하여 WAR를 실행한다.

WAR 배포
이전에 설명한 WAR 배포를 위한 war 명령어는 다양한 Java EE 컨테이너(현재 지원 목록을 보라)에 배포할 수 있는 WAR 파일을 생성하는 기능을 제공한다.

일단 WAR파일을 만들었으면 다음 절차는 일반적으로 특정 디렉토리에 WAR 파일을 넣는 일이다. 컨테이너가 hot deployment를 지원한다면 WAR는 자동으로 reload될 것이고 그렇지 않으면 컨테이너를 재실행한다.

Apache Tomcat을 예를 들면 WAR 파일을 TOMCAT_HOME/webapps 디렉토리에 넣고 컨테이너를 재실행한다.

다른 컨테이너들은(특히 상용) 실행 중인 컨테이너에 WAR 파일을 업로드하고 배포하는 웹 인터페이스를 제공하기도 한다. 이런 경우 해당 컨테이너 문서를 참고하고 그 단계를 따라한다.

WAR 생성 절차 변경
WAR 생성 절차를 변경하고 싶은 경우 몇 가지 방법이 있다. 단지 WAR 결과를 다른 디렉토리 위치에 생성할 경우 명령어에 그 위치를 지정할 수 있다.

grails war /my/container/path

위 방법 대신 Config.groovy 파일에 grails.war.destFile 옵션을 이용하여 설정할 수도 있다.

grails.war.destFile=/my/container/path

WAR 생성 시 Grails에 포함된 파일 의존관계(dependencies)를 조정하고 싶을 경우(예를 들어 사용하는 컨테이너가 공유 라이브러리 기능을 가지고 있을 경우) grails.war.dependencies config 옵션을 사용하며 여기에서 어떤 Ant fileset도 지정할 수 있다.

grails.war.dependencies = {
 fileset(dir:"/my/libs", includes:"*.jar")
}

보다 유연하게 grails.war.resources 옵션을 사용할 수 있는데 이 옵션은 빌드될 WAR 파일안의 디렉토리에 넣기도 한다.

grails.war.resources = { warLocation ->
 copy(todir:"$warLocation/WEB-INF") {
  fileset(dir:"/my/configs", includes:"*.xml")
 }
}


---
원문: 3. Configuration
 

0 Comments
댓글쓰기 폼