Копирование внешней конфигурации по умолчанию при первом запуске веб-приложения Grails

В наших веб-приложениях Grails мы хотели бы использовать внешние файлы конфигурации, чтобы мы могли изменять конфигурацию, не выпуская новую версию. Мы также хотели бы, чтобы эти файлы находились за пределами каталога приложения, чтобы они оставались неизменными во время непрерывной интеграции.

Последнее, что нам нужно сделать, это убедиться, что внешние файлы конфигурации существуют. Если они этого не делают, то мы хотели бы создать их, заполнить их предопределенным содержимым (по умолчанию для производственной среды), а затем использовать их, как если бы они существовали раньше. Это позволяет любому администратору изменять настройки приложения, не зная подробно о доступных опциях.

Для этой цели в web-app/WEB-INF/conf есть несколько файлов, которые можно скопировать во внешнее расположение конфигурации при первом запуске приложения.

Все идет нормально. Но нам нужно сделать это до того, как приложение будет инициализировано, чтобы учесть связанные с производством модификации определений источников данных.

Я могу выполнить операцию копирования и загрузки внутри файла Config.groovy, но на данный момент я не знаю абсолютного местоположения каталога WEB-INF/conf.

Как я могу получить местоположение на этом раннем этапе инициализации? Есть ли другое решение проблемы?


person Newerth    schedule 15.10.2015    source источник


Ответы (2)


Для этого есть лучшая практика.

В общем, никогда не пишите в папку, где развернуто приложение. Вы не имеете над ним контроля. Следующий выпуск удалит все, что вы там написали.

Вместо этого используйте встроенные возможности конфигурации, которые используют настоящие профессионалы (Spring и/или JPA).

JNDI является нормой для поиска ресурсов, таких как базы данных, файлы и URL-адреса.

Операции должны будут настроить JNDI, но они ценят внимание.

Им также необходим начальный набор файлов конфигурации, и они должны быть готовы вносить изменения время от времени по требованию команды разработчиков.

Как всегда, все файлы конфигурации должны находиться в вашем репозитории с исходным кодом.

person eric    schedule 16.10.2015

Наконец-то мне удалось решить эту проблему самостоятельно, используя способность Java находить ресурсы, размещенные в пути к классам.

Я взял файлы .groovy позже, чтобы скопировать их наружу, поместил их в каталог grails-app/conf (который находится в пути к классам) и добавил суффикс к их имени, чтобы они не компилировались при упаковке приложения. Итак, теперь у меня есть *Config.groovy файлов, содержащих настройки по умолчанию (для всех сред), и *Config.groovy.production файлов, содержащих настройки по умолчанию для производственной среды (переопределяющие предварительно скомпилированные значения по умолчанию).

Теперь - Config.groovy начинается так:

grails.config.defaults.locations = [ EmailConfig, AccessConfig, LogConfig, SecurityConfig ]

environments {
    production {
        grails.config.locations = ConfigUtils.getExternalConfigFiles(
            '.production',
            "${userHome}${File.separator}.config${File.separator}${appName}",
            'AccessConfig.groovy',
            'Config.groovy',
            'DataSource.groovy',
            'EmailConfig.groovy',
            'LogConfig.groovy',
            'SecurityConfig.groovy'
        )
    }
}

Затем класс ConfigUtils:

public class ConfigUtils {

    // Log4j may not be initialized yet 
    private static final Logger LOG = Logger.getGlobal()

    public static def getExternalConfigFiles(final String defaultSuffix, final String externalConfigFilesLocation, final String... externalConfigFiles) {

        final def externalConfigFilesDir = new File(externalConfigFilesLocation)

        LOG.info "Loading configuration from ${externalConfigFilesDir}"

        if (!externalConfigFilesDir.exists()) {
            LOG.warning "${externalConfigFilesDir} not found. Creating..."
            try {
                externalConfigFilesDir.mkdirs()
            } catch (e) {
                LOG.severe "Failed to create external configuration storage. Default configuration will be used."
                e.printStackTrace()
                return []
            }
        }

        final def cl = ConfigUtils.class.getClassLoader()
        def result = []

        externalConfigFiles.each {

            final def file = new File(externalConfigFilesDir, it)
            if (file.exists()) {
                result << file.toURI().toURL()
                return
            }

            final def error = false
            final def defaultFileURL = cl.getResource(it + defaultSuffix)
            final def defaultFile

            if (defaultFileURL) {
                defaultFile = new File(defaultFileURL.toURI())
                error = !defaultFile.exists();
            } else {
                error = true
            }

            if (error) {
                LOG.severe "Neither of ${file} or ${defaultFile} exists. Skipping..."
                return
            }

            LOG.warning "${file} does not exist. Copying ${defaultFile} -> ${file}..."

            try {
                FileUtils.copyFile(defaultFile, file)
            } catch (e) {
                LOG.severe "Couldn't copy ${defaultFile} -> ${file}. Skipping..."
                e.printStackTrace()
                return
            }

            result << file.toURI().toURL()
        }

        return result
    }

}
person Newerth    schedule 16.10.2015