文章目录
- Grails配置
- 1. 启动类配置
- Application.groovy启动类中可以做哪些事情
- 1. 启动Grails应用程序
- 2. 自定义包扫描路径
- 3. 注册bean
- 4. 应用程序生命周期管理
- 2. 环境配置
- 2.1 默认的多环境配置
- 2.2 预设的环境
- 2.3 打包和运行使用不同的环境
- 2.4 在代码启动过程中判断当前环境
- 2.5 在代码中运行过程中判断当前环境
- 3. 数据源配置
- 配置Mysql数据源
- 1. 添加mysql驱动程序依赖项
- 2. 修改application.yml中的数据库连接信息
- 3. 创建数据库grails4_hello
- 4. 启动项目测试数据库连接
- 5. 配置参数说明
- 6. 默认了开启数据库控制台
- 7. 是否需要手动关闭H2数据库控制台?
- 多数据源配置
- 4. 小结
Grails配置
1. 启动类配置
Grails应用程序启动类Application.groovy
位于grails-app/init
目录。
Application.groovy
类继承了启动 Grails 应用程序配置的基类grails.boot.config.GrailsAutoConfiguration
,并有静态void Main方法,这意味着它可以作为常规应用程序启动。
默认的Application.groovy
启动类代码
package helloworldgrails4import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfigurationimport groovy.transform.CompileStatic@CompileStatic
class Application extends GrailsAutoConfiguration {static void main(String[] args) {GrailsApp.run(Application, args)}
}
看看他继承的grails.boot.config.GrailsAutoConfiguration
类有哪些配置
package grails.boot.configimport grails.config.Config
import grails.core.GrailsApplication
import grails.boot.config.tools.ClassPathScanner
import grails.core.GrailsApplicationClass
import groovy.transform.CompileStatic
import org.grails.compiler.injection.AbstractGrailsArtefactTransformer
import org.grails.spring.aop.autoproxy.GroovyAwareAspectJAwareAdvisorAutoProxyCreator
import org.springframework.aop.config.AopConfigUtils
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.context.annotation.Bean
import org.springframework.core.io.support.PathMatchingResourcePatternResolverimport java.lang.reflect.Field/*** A base class for configurations that bootstrap a Grails application* 引导 Grails 应用程序的配置的基类** @since 3.0* @author Graeme Rocher**/
@CompileStatic
// WARNING: Never add logging to the source of this class, early initialization causes problems
// 警告:永远不要在这个类的源代码中添加日志,过早的初始化会导致问题
class GrailsAutoConfiguration implements GrailsApplicationClass, ApplicationContextAware {private static final String APC_PRIORITY_LIST_FIELD = "APC_PRIORITY_LIST"static {try {// patch AopConfigUtils if possible// 如果可能,修补 AopConfigUtilsField field = AopConfigUtils.class.getDeclaredField(APC_PRIORITY_LIST_FIELD)if(field != null) {field.setAccessible(true)Object obj = field.get(null)List<Class<?>> list = (List<Class<?>>) objlist.add(GroovyAwareAspectJAwareAdvisorAutoProxyCreator.class)}} catch (Throwable e) {// ignore}}ApplicationContext applicationContext/*** @return A post processor that uses the {@link grails.plugins.GrailsPluginManager} to configure the {@link org.springframework.context.ApplicationContext}* 使用grails.plugins.GrailsPluginManager配置ApplicationContext后处理器*/@BeanGrailsApplicationPostProcessor grailsApplicationPostProcessor() {return new GrailsApplicationPostProcessor( this, applicationContext, classes() as Class[])}/*** @return The classes that constitute the Grails application* 构成 Grails 应用程序的类*/Collection<Class> classes() {Collection<Class> classes = new HashSet()ClassPathScanner scanner = new ClassPathScanner()if(limitScanningToApplication()) {classes.addAll scanner.scan(getClass(), packageNames())}else {classes.addAll scanner.scan(new PathMatchingResourcePatternResolver(applicationContext), packageNames())}ClassLoader classLoader = getClass().getClassLoader()for(cls in AbstractGrailsArtefactTransformer.transformedClassNames) {try {classes << classLoader.loadClass(cls)} catch (ClassNotFoundException cnfe) {// ignore}}return classes}/*** Whether classpath scanning should be limited to the application and not dependent JAR files. Users can override this method to enable more broad scanning* at the cost of startup time.* 类路径扫描是否应仅限于应用程序而不是依赖的 JAR 文件。 用户可以覆盖此方法,以启动时间为代价启用更广泛的扫描。** @return True if scanning should be limited to the application and should not include dependant JAR files* 返回:如果扫描应仅限于应用程序且不应包括相关的 JAR 文件,则为 True*/protected boolean limitScanningToApplication() {return true}/*** @return The packages to scan* 返回:要扫描的包*/Collection<Package> packages() {def thisPackage = getClass().packagethisPackage ? [ thisPackage ] : new ArrayList<Package>()}/*** @return The package names to scan. Delegates to {@link #packages()} by default* 返回:要扫描的包名称。 默认情况下委托给packages()*/Collection<String> packageNames() {packages().collect { Package p -> p.name }}/*** 返回:一个定义要被 Spring 注册的 bean 的闭包*/@OverrideClosure doWithSpring() { null }/*** 在org.springframework.context.ApplicationContext在插件可以添加动态方法的阶段刷新后调用。 子类应该覆*/@Overridevoid doWithDynamicMethods() {// no-op}/*** 一旦org.springframework.context.ApplicationContext被刷新并且在 {#doWithDynamicMethods()} 被调用后调用*/@Overridevoid doWithApplicationContext() {// no-op}/*** 当应用程序配置更改时调用* 参数:事件*/@Overridevoid onConfigChange(Map<String, Object> event) {// no-op}/*** 调用一次所有先前的初始化钩子: doWithSpring() 、 doWithDynamicMethods()和doWithApplicationContext()*/@Overridevoid onStartup(Map<String, Object> event) {// no-op}/*** 当org.springframework.context.ApplicationContext关闭时调用*/@Overridevoid onShutdown(Map<String, Object> event) {// no-op}GrailsApplication getGrailsApplication() {applicationContext.getBean(GrailsApplication)}Config getConfig() {grailsApplication.config}}
Application.groovy启动类中可以做哪些事情
1. 启动Grails应用程序
2. 自定义包扫描路径
默认情况下,Grails将扫描控制器,领域类等的所有已知源目录,但是如果希望扫描其他JAR文件中的包,则可以通过覆盖应用程序类的packageNames()
方法来实现:
class Application extends GrailsAutoConfiguration {@OverrideCollection<String> packageNames() {super.packageNames() + ['my.additional.package']}...
}
3. 注册bean
应用程序类也可以用作注册Spring Bean对象,只需定义有bean注解的方法,返回的对象作为bean对象,方法的名称用作bean名称。
class Application extends GrailsAutoConfiguration {@BeanMyType myBean() {return new MyType()}...
}
4. 应用程序生命周期管理
Application.groovy
类继承了启动 Grails 应用程序配置的基类grails.boot.config.GrailsAutoConfiguration
,而grails.boot.config.GrailsAutoConfiguration
又实现了grails.core.GrailsApplicationLifeCycle
接口。这个接口提供了Grails应用程序的生命周期钩子方法,所有插件都实现了这个接口,我们可以通过重写这些钩子方法来扩展一些功能。
class Application extends GrailsAutoConfiguration {/*** 返回:一个定义要被 Spring 注册的 bean 的闭包*/@OverrideClosure doWithSpring() {{->// 要注册的 beanmySpringBean(MyType)}}...
}
2. 环境配置
Grails支持多环境配置。 grails-app / conf目录中的application.yml可以使用yaml语法进行多环境配置。
2.1 默认的多环境配置
例如application.yml默认的多环境配置:
# 配置数据库链接通用属性
dataSource:pooled: truejmxExport: truedriverClassName: org.h2.Driverusername: sapassword: ''environments:# 开发环境数据源配置,在上面通用数据源配置上进行扩展development:dataSource:# 开发环境使用create-drop,服务每次启动时创建数据库和表,服务器停止时删除数据库和表dbCreate: create-drop# 模式使用H2内存数据库,也可以配置成文件数据库,H2数据库默认用户名sa,密码空。还可以在conf/application.yml中开启控制台界面url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE# 测试环境数据源配置,在上面通用数据源配置上进行扩展test:dataSource:# 测试环境使用update,每次启动会更新表结构,服务停止不会删除数据库和表dbCreate: update# 模式使用H2内存数据库url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE# 生产环境数据源配置,在上面通用数据源配置上进行扩展production:dataSource:# 生产环境配置为nonedbCreate: none# 模式使用H2文件数据库url: jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE# 配置数据源的其他信息properties:jmxEnabled: trueinitialSize: 5...
注意上面使用了dataSource提供了公共配置信息,然后在每个环境配置中又配置了dataSource,这样可以使用公共的配置,然后再添加各自的特殊环境配置。
2.2 预设的环境
Grails预设了3个环境:
dev:开发环境
prod:生产环境
test:测试环境
2.3 打包和运行使用不同的环境
使用测试环境打包
grails test war
使用grails.env
环境变量配置环境
grails -Dgrails.env=test run-app
2.4 在代码启动过程中判断当前环境
grails-app/init/BootStrap.groovy
文件可以在项目启动时做一些初始化配置,针对不同的环境设置不同的配置。
例如:
def init = { ServletContext ctx ->environments {production {// 开发环境设置一个env的属性信息ctx.setAttribute("env", "prod")}development {// 开发环境启动项目时初始化一条book记录new Book(title: "《Grails教程》").save()}}// 任何环境下启动项目,都设置一个作者年龄的属性配置信息ctx.setAttribute("book.author.age", 18)
}
2.5 在代码中运行过程中判断当前环境
在代码中使用 Environment 类检测环境。
import grails.util.Environment...
switch (Environment.current) {// 当前是开发环境case Environment.DEVELOPMENT:// 做一些开发环境的特殊处理configureForDevelopment()break// 当前是生产环境 case Environment.PRODUCTION:// 做一些生成环境的特殊处理configureForProduction()break
}
3. 数据源配置
在上面的conf/application.yml
多环境配置中,我们已经看到了数据源相关的配置,一般情况下都是这两者相互结合使用的。
Grails使用H2作为默认数据库,如果要使用其他数据库,需要添加对应的JDBC驱动程序,因为Grails是基于java构建的。
配置Mysql数据源
1. 添加mysql驱动程序依赖项
Grails使用Gradle构建项目,需要在build.gradle的dependencies中添加
runtime 'mysql:mysql-connector-java:5.1.39'
根据自己使用的mysql版本,选择对应的驱动包版本。
2. 修改application.yml中的数据库连接信息
这里只修改开发环境中的数据库连接信息,其他环境不做修改。
# 配置数据库链接通用属性
dataSource:pooled: truejmxExport: truedriverClassName: org.h2.Driverusername: sapassword: ''environments:# 开发环境数据源配置,在上面通用数据源配置上进行扩展development:dataSource:# 开发环境使用create-drop,服务每次启动时创建数据库和表,服务器停止时删除数据库和表dbCreate: create-drop# 使用 mysql 驱动driverClassName: com.mysql.jdbc.Driver# 使用 mysql 数据库连接,加上 useUnicode 和 characterEncoding 参数防止中文乱码url: jdbc:mysql://localhost:3306/grails4_hello?useUnicode=true&characterEncoding=utf8username: rootpassword: 123456test:dataSource:...
3. 创建数据库grails4_hello
CREATE DATABASE grails4_hello
;
4. 启动项目测试数据库连接
因为数据库配置使用dbCreate: create-drop
启动项目后,查看数据库中已经自动创建了book表。
打开浏览器访问http://localhost:8080/book/create
添加一条书籍记录
添加后查看数据库中,已经成功插入一条记录
到这里Grails已经成功连接到mysql数据库了,这里只添加了一些简单的配置像,还有其他更多的配置项也比较重要。
5. 配置参数说明
grails-app/conf/application.yml
中可以做下面这些配置:
配置项 | 说明 |
---|---|
driverClassName | JDBC 驱动程序的类名。例如Mysql:driverClassName: com.mysql.jdbc.Driver |
username | JDBC 连接的用户名 |
password | JDBC 连接的密码 |
url | 数据库的 JDBC 连接 |
dbCreate | 是否从域模型自动生成数据库 - ‘create-drop’、‘create’、‘update’、‘validate’ 或 ‘none’ 之一 |
pooled | 是否使用连接池(默认为 true) |
logSql | 启用 SQL 日志记录到标准输出 |
formatSql | 格式化记录的 SQL |
dialect | 方言 - 表示用于与数据库通信的Hibernate方言的字符串或类。有关可用方言,请参阅org.hibernate.dialect包。 |
readOnly | 如果true使数据源只读,这会导致连接池在每个连接上调用setReadOnly(True) |
transactional | 事务性 - 如果false将DataSource的TransactionManage Bean留出在链接的BE1PC事务管理器实现之外。这仅适用于其他数据源。 |
persistenceInterceptor | 默认数据源是自动连接到持久性拦截器,除非这设置为true,否则其他数据源不会自动连接,用于多数据源。 |
properties | 在DataSource Bean上设置的额外属性。请参阅Tomcat池文档。还有一个javadoc格式的属性文件。 |
jmxExport | 如果为false,则将禁用所有数据源的JMX MBean的注册。默认情况下,JMX MBeans为jmxEnabled = True的数据源添加了数据库。 |
type | 连接池类型,如果要强制Grails在有多个可用时使用它。 |
dbCreate参数说明
Hibernate可以自动创建领域类所需的数据库表。可以通过dbCreate属性来控制何时以及如何创建这些表。
参数配置说明:
create
:删除现有架构并在启动时创建架构,删除现有表,索引等。create-drop
:与创建相同,但也会在应用程序退出时删除表。update
:创建缺少的表和索引,不删除任何表或数据。注意,这不能处理表或者属性的更改,例如领域类属性重命名,会添加新列,但不会删除旧列和数据。validate
:对数据库没有更改。将配置与现有数据库架构进行比较并报告警告。none
:什么都不做
当应用程序的架构相对稳定,建议将dbCreate设置设置为“none”。
下面是Mysql 金典配置示例,使用的是groovy脚本配置,重点关注参数的配置,只需要将{
改成:
号就变成yml配置了:
dataSource {pooled = truedbCreate = "update"url = "jdbc:mysql://localhost:3306/my_database"driverClassName = "com.mysql.jdbc.Driver"dialect = org.hibernate.dialect.MySQL5InnoDBDialectusername = "username"password = "password"type = "com.zaxxer.hikari.HikariDataSource"properties {jmxEnabled = trueinitialSize = 5maxActive = 50minIdle = 5maxIdle = 25maxWait = 10000maxAge = 10 * 60000timeBetweenEvictionRunsMillis = 5000minEvictableIdleTimeMillis = 60000validationQuery = "SELECT 1"validationQueryTimeout = 3validationInterval = 15000testOnBorrow = truetestWhileIdle = truetestOnReturn = falsejdbcInterceptors = "ConnectionState;StatementCache(max=200)"defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED}
}
使用额外属性的高级配置示例
dataSource {pooled = truedbCreate = "update"url = "jdbc:mysql://localhost:3306/my_database"driverClassName = "com.mysql.jdbc.Driver"dialect = org.hibernate.dialect.MySQL5InnoDBDialectusername = "username"password = "password"type = "com.zaxxer.hikari.HikariDataSource"properties {// Tomcat JDBC Pool 文档// http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#Common_Attributes// https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/tomcat/jdbc/pool/PoolConfiguration.htmljmxEnabled = trueinitialSize = 5maxActive = 50minIdle = 5maxIdle = 25maxWait = 10000maxAge = 10 * 60000timeBetweenEvictionRunsMillis = 5000minEvictableIdleTimeMillis = 60000validationQuery = "SELECT 1"validationQueryTimeout = 3validationInterval = 15000testOnBorrow = truetestWhileIdle = truetestOnReturn = falseignoreExceptionOnPreLoad = true// http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#JDBC_interceptorsjdbcInterceptors = "ConnectionState;StatementCache(max=200)"defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED // safe default// controls for leaked connectionsabandonWhenPercentageFull = 100 // settings are active only when pool is fullremoveAbandonedTimeout = 120removeAbandoned = true// use JMX console to change this setting at runtimelogAbandoned = false // causes stacktrace recording overhead, use only for debugging// JDBC driver properties// Mysql as exampledbProperties {// Mysql specific driver properties// http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html// let Tomcat JDBC Pool handle reconnectingautoReconnect=false// truncation behaviourjdbcCompliantTruncation=false// mysql 0-date conversionzeroDateTimeBehavior='convertToNull'// Tomcat JDBC Pool's StatementCache is used instead, so disable mysql driver's cachecachePrepStmts=falsecacheCallableStmts=false// Tomcat JDBC Pool's StatementFinalizer keeps trackdontTrackOpenResources=true// performance optimization: reduce number of SQLExceptions thrown in mysql driver codeholdResultsOpenOverStatementClose=true// enable MySQL query cache - using server prep stmts will disable query cachinguseServerPrepStmts=false// metadata cachingcacheServerConfiguration=truecacheResultSetMetadata=truemetadataCacheSize=100// timeouts for TCP/IPconnectTimeout=15000socketTimeout=120000// timer tuning (disable)maintainTimeStats=falseenableQueryTimeouts=false// misc tuningnoDatetimeStringSync=true}}
}
6. 默认了开启数据库控制台
Grails默认使用H2数据库,也开启了H2数据库控制台,可以使用web界面连接数据库,管理数据库,特别是针对内存数据库非常方便。
浏览器输入http://localhost:8080/h2-console
访问web界面数据库控制台。
登录成功后,我们可以执行sql命令
可以在grails-app/conf/application.yml
中配置spring.h2.console.enabled=false
来关闭H2控制台。
7. 是否需要手动关闭H2数据库控制台?
H2数据库控制台开启需要3个前提条件:
- 应用程序是基于
Servlet
的Web应用 - classpath中包含
com.h2database:h2
- 使用了
spring-boot-devtools
插件
查看build.gradle
的dependencies
,发现使用了spring-boot-devtools依赖:
developmentOnly("org.springframework.boot:spring-boot-devtools")
这个依赖表示只在开发环境中添加依赖,当项目打包时不包含这个插件,就不能满足上面的3个条件了,所以打包后的生产环境无法访问http://localhost:8088/h2-console
,不需要手动关闭H2数据库控制台。
更多H2配置参考Spring Boot H2控制台文档
多数据源配置
默认情况下,所有领域类使用一个数据源和单个数据库。
也可以将领域类数据库保存在两个或多个数据源中。
一般情况下使用不到,暂不做讲解。
4. 小结
本章主要介绍了以下知识点:
- 在哪里注册bean。
- 在代码中如何判断当前项目的运行环境(开发环境、生产环境、测试环境)。
- 如何配置多环境数据源。
- 如何连接Mysql数据库。
- 如何使用H2数据库控制台管理数据库。