也许在这里谈论配置对于一个“约定优于配置”的框架来说,这可能比较奇怪,但这些配置通常都是一次性,我们最好还是先了解他们的大概。
由于Grails提供了默认设置,你确实可以在不做任何配置的情况下进行开发和应用。Grails也内嵌了一个Web容器和一个称为HSQLDB的内存数据库,这意味着你甚至都不用安装数据库了。
不过,在将来某些情况下你还是会想要安装一个真正的数据库的,我们将在随后的一些章节进行描述。
1 基本配置
Grails提供了一个名为 grails-app/conf/Config.groovy
的文件用来进行一般性配置。这个文件使用了Groovy的 ConfigSlurper 特性,除了它是由纯正的Groovy实现外,它与Java的properties文件是非常相似的,因此你可以在应用中重用定义的变量或者使用适合的Java类型!
你可以在这里添加你自己的配置,例如:
foo.bar.hello = "world"
配置完成后你就可以在你的应用程序里使用两种方式来访问这些设置了。最常用是通过 GrailsApplication 对象,它可以在控制器或标记库中作为一个变量来使用:
assert "world" == grailsApplication.config.foo.bar.hello
另一种方式是先获得对 ConfigurationHolder 类的引用,然后再通过它获得配置对象的引用:
import org.codehaus.groovy.grails.commons.*
…
def config = ConfigurationHolder.config
assert "world" == config.foo.bar.hello
1.1 内置选项
Grails提供了下列配置选项:
grails.config.locations
- 资源(properties)文件或需要被合并到主配置文件中的附加Grails配置文件的位置grails.enable.native2ascii
- 如果你不需要对Grails的i18n资源(properties)文件进行native2ascii的转换,那么就将该选项设为falsegrails.views.default.codec
- 用于设置GSP文件的默认编码体制——可以设置“none”、“html”或“base64”中的一个(默认值为:“none”)。为了降低XSS攻击的风险可以将改选项设为“html”。grails.views.gsp.encoding
- 用于GSP源代码文件的文件编码(默认为“utf-8”)grails.mime.file.extensions
- 是否使用文件扩展名来表示内容协商中的MIME类型grails.mime.types
- 被支持的用于内容协商中的MIME类型对应表grails.serverURL
- 一个用于描述绝对链接中服务器URL部分的字符串,其中包括了服务器名称。例如:grails.serverURL="http://my.yourportal.com"。具体内容请参考createLink一节。
生成War文件
grails.war.destFile
- 用来设置 war 命令将把生成的WAR文件放置在什么位置grails.war.dependencies
- 一个包含了Ant构建器语法或JAR文件列表的闭包。允许你指定哪些库文件需要被包含在WAR文件中。grails.war.java5.dependencies
- 一个JAR文件列表,这些JAR文件是需要被包含在用于JDK 1.5或以上版本的WAR文件里的。grails.war.copyToWebApp
- 一个包含了Ant构建器语法的闭包,这些语法应该符合Ant的拷贝语法,例如“fileset()”。该功能允许你控制将“web-app”目录中的哪些内容包含到WAR文件中。grails.war.resources
- 一个包含了Ant构建器语法的闭包。允许应用程序在正式生成WAR文件前做一些必要的事情。
要获得使用这些选项的更多信息,可以参考开发一章
1.2 日志
日志基础
Grails使用它的通用配置方式来配置潜在的 Log4j 日志系统。要配置日志你需要修改位于 grails-app/conf
目录下的 Config.groovy
文件。
这个独特的 Config.groovy
文件允许你为 开发(development)
、测试(test)
和生产(production)
环境(environments)分别进行日志的配置。Grails将适当地处理 Config.groovy
文件并配置Log4j。
从1.1版本的Grails开始,提供了一个 Log4j DSL,你可以像如下例子一样来配置Log4j:
log4j = { error 'org.codehaus.groovy.grails.web.servlet', // controllers 'org.codehaus.groovy.grails.web.pages' // GSP
warn 'org.mortbay.log' }
实际上,每个方法都可以转化为一个日志级别,你可以把你想要记录日志的包名作为方法的参数。
以下是一些有用的日志记录器:
org.codehaus.groovy.grails.commons
- 记录核心工件的信息,如类加载等。org.codehaus.groovy.grails.web
- 记录Grails的Web请求处理org.codehaus.groovy.grails.web.mapping
- URL映射的调试org.codehaus.groovy.grails.plugins
- 记录插件活动情况org.springframework
-查看Spring在做什么org.hibernate
- 查看Hibernate在做什么
顶级日志记录器
顶级日志记录器会被所有其他日志记录器继承。你可以使用root方法来配置顶级日志记录器:
root {
error()
additivity = true
}
下边的例子用来配置顶级日志记录器去记录错误级别的信息,它的上方是默认的标准输出目标。你也可以将顶级日志记录器配置为将日志输出到多个已命名的输出目标:
appenders {
file name:'file', file:'/var/logs/mylog.log'
}
root {
debug 'stdout', 'file'
additivity = true
}
这里的顶级日志记录器将日志记录到了两个输出目标——默认的“stdout”输出目标和一个“file”输出目标。
你也可以通过参数方式进入Lorg4J闭包的方式来配置顶级日志记录器:
log4j = { root -> root.level = org.apache.log4j.Level.DEBUG … }
闭包参数“root”是 org.apache.log4j.Logger
的一个实例,因此你可以查阅Log4J的API文档,找出哪些属性和方法对你有用。
自定义输出目标
使用Log4j你可以明确的定义输出目标。下边是默认可用的输出目标:
jdbc
- 用于将日志输出到JDBC连接的输出目标console
- 用于将日志输出到标准输出的输出目标file
- 用于将日志输出到文件的输出目标rollingFile
- 用于将日志输出到滚动文件集的输出目标
例如你可以配置一个滚动文件输出目标:
log4j = {
appenders {
rollingFile name:"myAppender", maxFileSize:1024, fileName:"/tmp/logs/myApp.log"
}
}
每个进入输出目标的参数都会对应到 Appender 类的一个属性。上边的例子设置了RollingFileAppender 类的name
、maxFileSize
和fileName
属性。
如果你愿意通过自己编程来创建输出目标或者你已经有自己的输出目标实现,那么你可以简单地调用 appender
方法以及输出目标实例:
import org.apache.log4j.*
log4j = { appenders { appender new RollingFileAppender(name:"myAppender", maxFileSize:1024, fileName:"/tmp/logs/myApp.log") } }
现在你可以将输出目标的名称作为一个唯一值设置到某个日志级别方法中,这样日志就记录到一个特定的输出目标中。这些在上一节讲述过:
error myAppender:"org.codehaus.groovy.grails.commons"
自定义布局
Log4j DSL默认假设你想要使用 样板布局(PatternLayout) 日志格式。也有如下其他布局可用使用:
xml
- 创建一个XML布局日志文件html
- 创建一个HTML布局日志文件simple
- 创建一个简单的纯文本布局日志文件pattern
- 创建一个样板布局日志文件
你可以使用layout
设置来指定自定义的样板作为一个输出目标:
log4j = { appenders { console name:'customAppender', layout:pattern(conversionPattern: '%c{2} %m%n') } }
这样的设置也可以用于内置的“stdout”输出目标,这样会将日志输出到控制台中:
log4j = { appenders { console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n') } }
完整的堆栈日志跟踪
当发生异常时,会产生大量来自Java和Groovy内部的堆栈日志信息。Grails过滤了那些典型的无关信息,同时聚焦到非Grails/Groovy核心类的信息上。
当这种情况发生时,完整的追踪信息总是会写到 StackTrace
日志记录器。这些日志被记录到一个称为stacktrace.log
的文件中 - 当然你也可以修改 Config.groovy
文件来进行你想要的设置。例如,如果你更喜欢将完整的堆栈记录信息输出到标准输出,可以添加这样一行:
error stdout:"StackTrace"
你也可以将 grails.full.stacktrace
虚拟机属性设置为 true
来完全禁用堆栈跟踪过滤器:
grails -Dgrails.full.stacktrace=true run-app
约定的日志记录方式
所有的应用程序工件都有一个动态添加的 log
属性。这些工件类型包括 domain类、控制器和标记库等。下边是一个使用例子:
def foo = "bar"
log.debug "The value of foo is $foo"
Grails使用 grails.app.<工件类型>.ClassName
来作为日志记录器的命名。下边是一个如何配置日志记录器去记录不同Grails工件的日志的例子:
log4j = {
// 为所有的应用程序工件设置
info "grails.app"
// 为一个特定的控制器设置
debug "grails.app.controller.YourController"
// 为一个特定的domain类设置
debug "grails.app.domain.Book" // 为所有的标记库设置 info "grails.app.tagLib"
}
工件名称(<工件类型>)也是按照约定命名的,一些常见的如下列表:
bootstrap
- 用于系统启动类dataSource
- 用于数据源tagLib
- 用于标记库service
- 用于服务类controller
- 用于控制器domain
- 用于domain实体
2 环境
多环境配置
Grails支持“多环境配置”的概念。grails-app/conf
中的Config.groovy
和DataSource.groovy
两个文件能够使用ConfigSlurper提供的语法来应用“多环境配置”的特性。以下例子是Grails提供的默认 DataSource
里的定义:
dataSource {
pooled = false
driverClassName = "org.hsqldb.jdbcDriver"
username = "sa"
password = ""
}
environments {
development {
dataSource {
dbCreate = "create-drop" // 可选“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" } } }
注意配置文件的开头部分提供的是公共配置,紧接着的 environments
代码块则指定了用于独立环境配置的数据源信息
,包括dbCreate
和url
属性。这样的语法也可以用与Config.groovy
文件。
针对不同环境的打包和运行
Grails的命令行 已经内建了针对特定环境来执行任何命令的能力。格式为:
grails [环境名] [命令名]
另外,已经有三个Grails的预制环境:dev
、prod
和test
分别用于 开发
、生产
和测试
。例如要为 test
环境创建一个WAR包,你可以这样做:
grails test war
如果你有自建的其他环境需要使用,可以通过 grails.env
变量来设置并用于任何命令:
grails -Dgrails.env=UAT run-app
可编程的环境检测
在你的Gant脚本或系统启动类的代码中,你可以使用 Environment 类来检测环境:
import grails.util.Environment
...
switch(Environment.current) { case Environment.DEVELOPMENT: configureForDevelopment() break case Environment.PRODUCTION: configureForProduction() break }
3 数据源
Grails是基于Java技术构建的,因此要在其中安装数据源必然需要一些JDBC(这种技术并不只支持Java数据库连接)的知识。
根本上来说,如果你正在使用的另一种数据库,而不是Grails内嵌的HSQLDB,那么你就需要为它准备一个JDBC驱动。例如使用MySQL数据库,就需要 Connector/J
这个JDBC驱动。通常这些JDBC驱动都是以JAR文件格式发行的。将需要的JAR文件放到项目的 lib
目录下即可。
一旦你把JAR文件放到了正确的位置,你还需要熟悉位于 grails-app/conf/DataSource.groovy
的Grails数据库描述文件。这个文件包含了数据源的定义,其中有下列这些设置:
driverClassName
- JDBC驱动的类名username
- 获得JDBC连接需要使用的用户名password
- 获得JDBC连接需要使用的密码url
- 数据库的JDBC URLdbCreate
- 是否从domain模型自动生成数据库pooled
- 是否使用连接池(默认为true)logSql
- 是否启动SQL日志记录dialect
- 用于表示与数据库通讯时应该使用的Hibernate方言的字符串或类。查看 org.hibernate.dialect 一文以便获得可用的方言。
一个用于MySQL数据库的典型配置可以像这样:
dataSource {
pooled = true
dbCreate = "update"
url = "jdbc:mysql://localhost/yourDB"
driverClassName = "com.mysql.jdbc.Driver"
username = "yourUser"
password = "yourPassword" }
在配置数据源的时候不要在配置项之前包含类型声明或def关键字,否则Groovy会把它们当作本地变量定义并且不对它们进行处理。例如下边的例子就是无效的:
dataSource {
boolean pooled = true // 类型声明导致它被当作是一个本地变量
…
}
3.1 数据源和环境
前边的配置范例假设你想要对所有的环境做一些配置,包括:生产、测试和开发等。
Grails的数据源定义是“环境感知”的,因此你可以针对需要的环境这样配置:
dataSource {
// 这里放置公共设置
}
environments {
production {
dataSource {
url = "jdbc:mysql://liveip.com/liveDb"
}
}
}
3.2 JNDI数据源
许多Java EE容器通常都支持通过 Java命名与目录接口(JNDI)来获取数据源
实例。有时你可能需要通过JNDI去查找一个 数据源
。
Grails支持像下边这样的JNDI数据源定义:
dataSource {
jndiName = "java:comp/env/myDataSource"
}
JNDI的名称格式在不同的容器中会有不同,但是在定义 数据源
的方式上是一致的。
3.3 自定数据库迁移
DataSource
的dbCreate
属性是非常重要的,它会指示Grails在运行期间使用GORM类来自动生成数据库表。选项如下:
create-drop
- 当Grails运行的时候删除并且重新创建数据库。create
- 如果数据库不存在则创建数据库,存在则不做任何修改。删除现有的数据。update
- 如果数据库不存在则创建数据库,存在则对它进行修改更新。
create-drop
和create
都会删除所有存在的数据,因此请小心使用!
In 部署 模式下 dbCreate
默认被设置为“create-drop”:
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
}
在每次应用程序重启时都会自动删除并重建数据库表。显然,这不应该用于生产环境。
尽管目前Grails还不支持Rails风格的开箱迁移特性,但有两个插件可以提供Grails类似的简单能力:
LiquiBase插件和
DbMigrate插件都可以通过
grails list-plugins
命令获得。
4 外部配置
大多数情况下,grails-app/conf
目录下的 Config.groovy
默认配置文件是足够使用了,但可能有某些特殊情况让你想要在主应用程序框架之外维护一个配置文件。例如你使用WAR文件部署了系统,管理员会经常需要修改配置文件来改变系统的特性,但又要避免每次修改都得重新打包生成WAR文件。
为了支持这种外部配置文件的部署方案,你需要在Config.groovy
文件的grails.config.locations
设置中指明你的外部配置文件所在位置:
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
这些不同的位置来加载配置文件(包括Java属性(properties)文件和 ConfigSlurper 配置)。
最终所有的配置文件都被合并到了 GrailsApplication 对象的 config
属性中,就可以通过这个属性来获取配置信息了。
Grails也支持 Spring中定义的属性占位(property place holder)概念和属性重载(property override)配置,更多信息请查看 Grails和Spring一章。
5 版本管理
版本管理基础
Grails已经内置了对版本管理的支持。当首次使用 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