Статьи

Ratpacked: применить конфигурацию к конфигурируемому модулю

В Ratpack мы можем использовать модули Guice для организации кода для предоставления объектов в реестр. Ratpack добавляет настраиваемые модули, которые принимают дополнительный объект конфигурации. Значения из объекта конфигурации используются для создания новых объектов, предоставляемых нашему приложению. Используя Groovy DSL, у нас есть несколько способов сделать объект конфигурации доступным для настраиваемого модуля.

Давайте создадим пример настраиваемого модуля и рассмотрим различные способы придания ему объекта конфигурации. Мы создаем модуль  GreetingModule, который предоставляет  Greetingобъект. Конфигурация определяется в классе  GreetingConfig.

// File: src/main/groovy/com/mrhaki/ratpack/GreetingModule.groovy
package com.mrhaki.ratpack

import com.google.inject.Provides
import groovy.transform.CompileStatic
import ratpack.guice.ConfigurableModule

@CompileStatic
class GreetingModule extends ConfigurableModule<GreetingConfig>{
    
    @Override
    protected void configure() {}
    
    /**
     * Method to create a new Greeting object with values
     * from the GreetingConfig configuration object.
     */
    @Provides
    Greeting greeting(final GreetingConfig config) {
        new Greeting(message: "${config.salutation}, ${config.message}")
    }
    
}
// File: src/main/groovy/com/mrhaki/ratpack/GreetingConfig.groovy
package com.mrhaki.ratpack

import groovy.transform.CompileStatic

/**
 * Configuration properties for creating
 * a {@link Greeting} object using the
 * configurable module {@link GreetingModule}.
 */
@CompileStatic
class GreetingConfig {
    String message
    String salutation
}
// File: src/main/groovy/com/mrhaki/ratpack/Greeting.groovy
package com.mrhaki.ratpack

import groovy.transform.CompileStatic

/**
 * Simple class with a greeting message.
 * The {@link GreetingModule} module creates
 * an instance of this class.
 */
@CompileStatic
class Greeting {
    String message
}

У нас есть наш настраиваемый модуль и вспомогательные классы. Теперь мы определяем конфигурацию и модуль в  bindings блоке нашего приложения Ratpack Groovy. Мы используем  ConfigData класс для установки свойств конфигурации, которые мы позже привязываем к GreetingConfig объекту. С помощью  ConfigData мы можем определить свойства конфигурации из разных источников, таких как файлы в формате свойств Yaml, JSON или Java. В нашем примере мы просто определяем их, используя  Map. В первом примере мы используем  module метод с  Closureаргументом для настройки GreetingModule

// File: src/ratpack/Ratpack.groovy
import com.mrhaki.ratpack.Greeting
import com.mrhaki.ratpack.GreetingConfig
import com.mrhaki.ratpack.GreetingModule
import ratpack.config.ConfigData
import ratpack.config.ConfigDataBuilder

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        final ConfigData configData = ConfigData.of { ConfigDataBuilder builder ->
            builder.props(
                    ['greeting.salutation': 'Hi',
                     'greeting.message'   : 'how are you doing?'])
            // We can also use external files, 
            // system properties and environment
            // variables to set configuration properties
            // inside this block.
            builder.build()
        }

        // The module methods allows a Closure argument to
        // set values for the supported configuration class.
        module GreetingModule, { GreetingConfig config ->
            config.salutation = configData.get('/greeting/salutation', String)
            config.message = configData.get('/greeting/message', String)
        }
    }

    handlers {
        // Simple handler using the created Greeting object.
        get { Greeting greeting ->
            render greeting.message
        }
    }
}

В следующем примере мы создаем экземпляр  GreetingConfig использования bindInstance метода. Он  GreetingModule подберет этот экземпляр и будет использовать его автоматически:

// File: src/ratpack/Ratpack.groovy
import com.mrhaki.ratpack.Greeting
import com.mrhaki.ratpack.GreetingConfig
import com.mrhaki.ratpack.GreetingModule
import ratpack.config.ConfigData
import ratpack.config.ConfigDataBuilder

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        final ConfigData configData = ConfigData.of { ConfigDataBuilder builder ->
            builder.props(
                    ['greeting.salutation': 'Hi',
                     'greeting.message'   : 'how are you doing?'])
            // We can also use external files, 
            // system properties and environment
            // variables to set configuration properties
            // inside this block.
            builder.build()
        }

        // First create an instance of the GreetingConfig class. 
        bindInstance GreetingConfig, configData.get('/greeting', GreetingConfig)
        // With the module method we use the GreetingModule and
        // because there is a GreetingConfig instance available 
        // it is used to configure the module.
        module GreetingModule
    }

    handlers {
        // Simple handler using the created Greeting object.
        get { Greeting greeting ->
            render greeting.message
        }
    }
}

Наконец, мы можем использовать  moduleConfig метод. Этот метод принимает объект конфигурации непосредственно в качестве аргумента. Таким образом, мы можем использовать экземпляр в  GreetingConfig качестве аргумента метода. Мы также можем объединить его с  Closure аргументом для переопределения свойств конфигурации:

// File: src/ratpack/Ratpack.groovy
import com.mrhaki.ratpack.Greeting
import com.mrhaki.ratpack.GreetingConfig
import com.mrhaki.ratpack.GreetingModule
import ratpack.config.ConfigData
import ratpack.config.ConfigDataBuilder

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        final ConfigData configData = ConfigData.of { ConfigDataBuilder builder ->
            builder.props(
                    ['greeting.salutation': 'Hi',
                     'greeting.message'   : 'how are you doing?'])
            // We can also use external files, 
            // system properties and environment
            // variables to set configuration properties
            // inside this block.
            builder.build()
        }

        // With the moduleConfig method we can pass an instance
        // of GreetingConfig directly.
        moduleConfig GreetingModule, configData.get('/greeting', GreetingConfig)

        // Or we can even combine it with a Closure argument to override a 
        // configuration property.
        //moduleConfig(
        //        GreetingModule, 
        //        configData.get('/greeting', GreetingConfig)) { GreetingConfig config ->
        //    config.message = 'Ratpack rocks!'
        //}
    }

    handlers {
        // Simple handler using the created Greeting object.
        get { Greeting greeting ->
            render greeting.message
        }
    }
}