Grails配置-启动类配置,数据源配置,连接Mysql数据库

Grails配置

1. 启动类配置

Grails应用程序启动类Application.groovy位于grails-app/init目录。
Application.groovy类继承了启动 Grails 应用程序配置的基类grails.boot.config.GrailsAutoConfiguration,并有静态void Main方法,这意味着它可以作为常规应用程序启动。
默认的Application.groovy启动类代码

package helloworldgrails4

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration

import groovy.transform.CompileStatic

@CompileStatic
class Application extends GrailsAutoConfiguration {
    static void main(String[] args) {
        GrailsApp.run(Application, args)
    }
}

看看他继承的grails.boot.config.GrailsAutoConfiguration类有哪些配置

package grails.boot.config

import 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.PathMatchingResourcePatternResolver

import 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
            // 如果可能,修补 AopConfigUtils
            Field field = AopConfigUtils.class.getDeclaredField(APC_PRIORITY_LIST_FIELD)
            if(field != null) {
                field.setAccessible(true)
                Object obj = field.get(null)
                List<Class<?>> list = (List<Class<?>>) obj
                list.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后处理器
     */
    @Bean
    GrailsApplicationPostProcessor 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().package
        thisPackage ? [ 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 的闭包
	*/
    @Override
    Closure doWithSpring() { null }

	/**
	* 在org.springframework.context.ApplicationContext在插件可以添加动态方法的阶段刷新后调用。 子类应该覆
	*/
    @Override
    void doWithDynamicMethods() {
        // no-op
    }

	/**
	* 一旦org.springframework.context.ApplicationContext被刷新并且在 {#doWithDynamicMethods()} 被调用后调用
	*/
    @Override
    void doWithApplicationContext() {
        // no-op
    }

	/**
	* 当应用程序配置更改时调用
	* 参数:事件
	*/
    @Override
    void onConfigChange(Map<String, Object> event) {
        // no-op
    }

	/**
	* 调用一次所有先前的初始化钩子: doWithSpring() 、 doWithDynamicMethods()和doWithApplicationContext()
	*/
    @Override
    void onStartup(Map<String, Object> event) {
        // no-op
    }

	/**
	* 当org.springframework.context.ApplicationContext关闭时调用
	*/
    @Override
    void onShutdown(Map<String, Object> event) {
        // no-op
    }

    GrailsApplication getGrailsApplication() {
        applicationContext.getBean(GrailsApplication)
    }

    Config getConfig() {
        grailsApplication.config
    }

}


Application.groovy启动类中可以做哪些事情

1. 启动Grails应用程序

启动Grails应用程序

2. 自定义包扫描路径

默认情况下,Grails将扫描控制器,领域类等的所有已知源目录,但是如果希望扫描其他JAR文件中的包,则可以通过覆盖应用程序类的packageNames()方法来实现:

class Application extends GrailsAutoConfiguration {
    @Override
    Collection<String> packageNames() {
        super.packageNames() + ['my.additional.package']
    }
    
    ...
}
3. 注册bean

应用程序类也可以用作注册Spring Bean对象,只需定义有bean注解的方法,返回的对象作为bean对象,方法的名称用作bean名称。

class Application extends GrailsAutoConfiguration {
    @Bean
    MyType 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 的闭包
	*/
    @Override
    Closure doWithSpring() {
        {->
        	// 要注册的 bean
            mySpringBean(MyType)
        }
    }

    ...
}

2. 环境配置

Grails支持多环境配置。 grails-app / conf目录中的application.yml可以使用yaml语法进行多环境配置。

2.1 默认的多环境配置

例如application.yml默认的多环境配置:

# 配置数据库链接通用属性
dataSource:
    pooled: true
    jmxExport: true
    driverClassName: org.h2.Driver
    username: sa
    password: ''
    
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:
            # 生产环境配置为none
            dbCreate: none
            # 模式使用H2文件数据库
            url: jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
            # 配置数据源的其他信息
            properties:
                jmxEnabled: true
                initialSize: 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: true
    jmxExport: true
    driverClassName: org.h2.Driver
    username: sa
    password: ''

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=utf8
            username: root
            password: 123456
    test:
        dataSource:
	...
	
3. 创建数据库grails4_hello

CREATE DATABASE grails4_hello;

4. 启动项目测试数据库连接

因为数据库配置使用dbCreate: create-drop启动项目后,查看数据库中已经自动创建了book表。
mysql自动创建book表
打开浏览器访问http://localhost:8080/book/create添加一条书籍记录
添加一个书籍记录
添加后查看数据库中,已经成功插入一条记录
成功添加一条记录
到这里Grails已经成功连接到mysql数据库了,这里只添加了一些简单的配置像,还有其他更多的配置项也比较重要。

5. 配置参数说明

grails-app/conf/application.yml中可以做下面这些配置:

配置项说明
driverClassNameJDBC 驱动程序的类名。例如Mysql:driverClassName: com.mysql.jdbc.Driver
usernameJDBC 连接的用户名
passwordJDBC 连接的密码
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 = true
    dbCreate = "update"
    url = "jdbc:mysql://localhost:3306/my_database"
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    username = "username"
    password = "password"
    type = "com.zaxxer.hikari.HikariDataSource"
    properties {
       jmxEnabled = true
       initialSize = 5
       maxActive = 50
       minIdle = 5
       maxIdle = 25
       maxWait = 10000
       maxAge = 10 * 60000
       timeBetweenEvictionRunsMillis = 5000
       minEvictableIdleTimeMillis = 60000
       validationQuery = "SELECT 1"
       validationQueryTimeout = 3
       validationInterval = 15000
       testOnBorrow = true
       testWhileIdle = true
       testOnReturn = false
       jdbcInterceptors = "ConnectionState;StatementCache(max=200)"
       defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED
    }
}

使用额外属性的高级配置示例

dataSource {
    pooled = true
    dbCreate = "update"
    url = "jdbc:mysql://localhost:3306/my_database"
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    username = "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.html
       jmxEnabled = true
       initialSize = 5
       maxActive = 50
       minIdle = 5
       maxIdle = 25
       maxWait = 10000
       maxAge = 10 * 60000
       timeBetweenEvictionRunsMillis = 5000
       minEvictableIdleTimeMillis = 60000
       validationQuery = "SELECT 1"
       validationQueryTimeout = 3
       validationInterval = 15000
       testOnBorrow = true
       testWhileIdle = true
       testOnReturn = false
       ignoreExceptionOnPreLoad = true
       // http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#JDBC_interceptors
       jdbcInterceptors = "ConnectionState;StatementCache(max=200)"
       defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED // safe default
       // controls for leaked connections
       abandonWhenPercentageFull = 100 // settings are active only when pool is full
       removeAbandonedTimeout = 120
       removeAbandoned = true
       // use JMX console to change this setting at runtime
       logAbandoned = false // causes stacktrace recording overhead, use only for debugging
       // JDBC driver properties
       // Mysql as example
       dbProperties {
           // Mysql specific driver properties
           // http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html
           // let Tomcat JDBC Pool handle reconnecting
           autoReconnect=false
           // truncation behaviour
           jdbcCompliantTruncation=false
           // mysql 0-date conversion
           zeroDateTimeBehavior='convertToNull'
           // Tomcat JDBC Pool's StatementCache is used instead, so disable mysql driver's cache
           cachePrepStmts=false
           cacheCallableStmts=false
           // Tomcat JDBC Pool's StatementFinalizer keeps track
           dontTrackOpenResources=true
           // performance optimization: reduce number of SQLExceptions thrown in mysql driver code
           holdResultsOpenOverStatementClose=true
           // enable MySQL query cache - using server prep stmts will disable query caching
           useServerPrepStmts=false
           // metadata caching
           cacheServerConfiguration=true
           cacheResultSetMetadata=true
           metadataCacheSize=100
           // timeouts for TCP/IP
           connectTimeout=15000
           socketTimeout=120000
           // timer tuning (disable)
           maintainTimeStats=false
           enableQueryTimeouts=false
           // misc tuning
           noDatetimeStringSync=true
       }
    }
}
6. 默认了开启数据库控制台

Grails默认使用H2数据库,也开启了H2数据库控制台,可以使用web界面连接数据库,管理数据库,特别是针对内存数据库非常方便。
浏览器输入http://localhost:8080/h2-console访问web界面数据库控制台。
H2控制台登陆页面
登录成功后,我们可以执行sql命令
H2控制台执行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.gradledependencies,发现使用了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数据库控制台管理数据库。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值