【问题标题】:Set datasource values during run time在运行时设置数据源值
【发布时间】:2013-07-28 13:03:48
【问题描述】:

所以基本上我是在尝试让我的项目在 AppFog 上启动并运行。数据源信息存储在环境变量中,本质上是 JSON。我的目标是获取这些数据并从中设置我的数据源配置。

这是我尝试过的:

设置数据源配置的代码,这是 POGO 中的一种方法。实例化POGO并在DataSource.groovy开头调用方法:

import appfog.ParseDataSource
new ParseDataSource().setConfig()

dataSource {
...
}

class ParseDataSource {

    void setConfig() {
        String env = java.lang.System.getenv("VCAP_SERVICES")
        if (env) {
            def config = JSON.parse(env)
            config = config["mysql-5.1"][0].credentials
            grailsApplication.config.environments.production.dataSource.username = config.username
            grailsApplication.config.environments.production.dataSource.password = config.password
            grailsApplication.config.environments.production.dataSource.url = "jdbc:mysql://" + config.host + ":" + config.port + "/" + config.name
        }
    }
}

问题在于 grailsApplication 始终为空。我尝试在 resources.groovy 中注册一个 spring bean:

beans = {
    parseDataSource(appfog.ParseDataSource) {
        grailsApplication = ref('grailsApplication')
    }
}

class ParseDataSource {
    def grailsAPplication
    ...
}

我也尝试过通过 Holders 获得它:

    GrailsApplication grailsApplication = Holders.grailsApplication

无论哪种方式,它都是空的,所以我没有做正确的事情。有什么想法吗?

【问题讨论】:

  • 使用 new 手动实例化的类不参与 bean 自动装配。

标签: grails datasource appfog


【解决方案1】:

我认为您使这过于复杂。在构建过程中覆盖 grails 配置对象会导致操作顺序问题,从而使代码非常脆弱。

直接设置值似乎更直接:

Datasource.groovy:

def configJson = JSON.parse(java.lang.System.getenv("VCAP_SERVICES"))
def mysqlConfig = configJson["mysql-5.1"][0].credentials

dataSource = {
    production = {
        username = mysqlConfig.username
        // etc.
    }
}

如果为了清楚起见,您想在自己的类中继续解析,请创建 values 属性并在 dataSource 块中读取它们,而不是尝试将它们放在 grails 配置对象中:

配置解析:

class EnvironmentConfigParser {
    String username
    String password
    String url

    EnvironmentConfigParser() {
        def configJson = JSON.parse(java.lang.System.getenv("VCAP_SERVICES"))
        def mysqlConfig = configJson["mysql-5.1"][0].credentials

        username = mysqlConfig.username
        password = mysqlConfig.password
        url = "jdbc:mysql://${mysqlConfig.host}:${mysqlConfig.port}/${mysqlConfig.name}"
    }
}

在 Datasource.groovy 中:

def parser = new EnvironmentConfigParser()

dataSource = {
    production = {
        username = parser.username
        // etc
    }
}

【讨论】:

  • 太棒了..简单而合乎逻辑。一个问题,BeanPostProcessor 在这种情况下有用吗?
  • 可能,但是在实例化 bean 之后,您会更改 bean 的配置,在这种情况下,这似乎很迂回。
  • java.lang.System.getenv 可以缩短为System.getenv。见:groovy.codehaus.org/Differences+from+Java
【解决方案2】:

您应该能够以您在 resources.groovy 中注入的方式访问 grailsApplication,前提是您将 bean parseDataSource 注入到应用程序的任何工件中的某个位置。

在您的特殊情况下,您需要 bean 在 datasource.groovy 中可用。您正在实例化 POGO,这无助于您将 grailsApplication 注入 POGO。另一方面,您实际上不能像

那样将 POGO 注入到datasource.groovy

def parseDataSource

因为它(数据源)是引导期间的配置对象。

剩下的最好方法是metaClass pogoBootStrap 并使其可用grailsApplication。 Burt 的 shown it here 就是这样。

我也在考虑BeanPostProcessor 在这种情况下是否有用,但我不确定是否可以实现每个环境的配置。但是,如果它有助于满足您的业务需求,您可以尝试一下。一般是这样的:

//src/groovy
import org.springframework.beans.factory.config.BeanPostProcessor
class DatasourcePostProcessor implements BeanPostProcessor{
    def parseDataSource
    @Override
    Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean
    }

    @Override
    Object postProcessAfterInitialization(Object bean, String beanName) {
        if(beanName == 'dataSource') {
           //Set values to dataSource bean as required
           parseDataSource.setConfig(bean) 
        }
        return bean
    }
}

//resources.groovy
parseDataSource(ParseDataSource){
    grailsApplication = ref('grailsApplication')
}

datasourcePostProcessor(DatasourcePostProcessor){
    parseDataSource = ref('parseDataSource')
}

【讨论】:

  • 在 Bootstrap 中这样做的问题是此时数据源已经加载,因此更改配置将无效
  • 是的,在定制答案时错过了那篇文章。谢谢你提醒我。:)
猜你喜欢
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 2015-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多