Set datasource values during run time

佐手、 提交于 2019-12-24 14:40:29

问题


So essentially I'm trying to get my project up and running on AppFog. The datasource information is stored in an enviornment variable, which is essentially JSON. My goal is to take this data and set my datasource config from it.

Here is what I have tried:

Code to set the datasource config which is a method in a POGO. The POGO is instantiated and the method called at the beginning of 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
        }
    }
}

The problem is that grailsApplication is always null. I've tried registering a spring bean in resources.groovy:

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

class ParseDataSource {
    def grailsAPplication
    ...
}

I've also tried getting it via Holders:

    GrailsApplication grailsApplication = Holders.grailsApplication

Either way it is null so I'm not doing something right. Any ideas?


回答1:


I think you are making this overly complex. Overwriting the grails config object while still in the process of building it would cause an order of operations issue that would make the code very fragile.

Simply setting the values directly seems more straightforward:

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.
    }
}

If you wanted to keep parsing in its own class for clarity's sake, make the values properties and read them in the dataSource block rather than trying to put them in the grails config object:

config parsing:

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}"
    }
}

in Datasource.groovy:

def parser = new EnvironmentConfigParser()

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



回答2:


You should be able to access grailsApplication the way you have injected in resources.groovy provided you are injecting the bean parseDataSource somewhere in your application in any artefact.

In your special case you need the bean to be available in datasource.groovy. You were instantiating the POGO which will not help you injecting grailsApplication to the POGO. On the other hand, you cannot actually inject the POGO to datasource.groovy like

def parseDataSource

because it(datasource) is a config object during bootstrap.

The best way remains will be to metaClass the pogo at BootStrap and make grailsApplication available to it. Burt has shown it here exactly that way.

I was also thinking whether BeanPostProcessor can be useful in this case but I am not sure whether config per environment will be achieved. But you can give it a try if it helps in achieving your business need. It generally goes like:

//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')
}


来源:https://stackoverflow.com/questions/17912200/set-datasource-values-during-run-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!