Внедрить конфигурацию приложения Grails в сервис

Я создаю сервис grails, который будет взаимодействовать со сторонним REST API через библиотеку Java. Для библиотеки Java требуются учетные данные для API REST посредством URL-адреса, имени пользователя и пароля.

Я хотел бы сохранить эти учетные данные в configuration/Config.groovyсделайте их доступными для службы и убедитесь, что учетные данные доступны службе, прежде чем они потребуются.

я ценю это grailsApplication.config доступен для контроллеров и что с помощью метода службы соответствующие значения конфигурации могут быть предоставлены службе, например:

package example

class ExampleController {

    def exampleService

    def index = { }

    def process = {
        exampleService.setCredentials(grailsApplication.config.apiCredentials)
        exampleService.relevantMethod()
    }
}


package example

import com.example.ExampleApiClient;

class ExampleService {

    def credentials

    def setCredentials(credentials) {
        this.credentials = credentials
    }

    def relevantMethod() {

        def client = new ExampleApiClient(
            credentials.baseUrl,
            credentials.username,
            credentials.password
        )

        return client.action();
    }
}

Я чувствую, что этот подход слегка ошибочен, так как зависит от вызова контроллера setCredentials(), Наличие учетных данных, автоматически предоставляемых службе, было бы более надежным.

Является ли любой из этих двух вариантов жизнеспособным (я в настоящее время недостаточно знаком с Grails):

  1. впрыскивать grailsApplication.config.apiCredentials в службу в контроллере, когда служба создается?

  2. Предоставить некоторую форму конструктора в службе, которая позволяет передавать учетные данные в службу во время создания экземпляра?

Внедрение учетных данных в сервис идеально. Как это можно сделать?

4 ответа

Решение

grailsApplication Объект доступен внутри сервисов, что позволяет:

package example

import com.example.ExampleApiClient;

class ExampleService {

    def grailsApplication

    def relevantMethod() {

        def client = new ExampleApiClient(
            grailsApplication.config.apiCredentials.baseUrl
            grailsApplication.config.apiCredentials.username,
            grailsApplication.config.apiCredentials.password
        )

        return client.action();
    }
}

Даже если grailsApplication Я думаю, что сервисы не должны иметь дело с конфигурацией, потому что это сложнее в тестировании и нарушает принцип единой ответственности. Spring, с другой стороны, может обрабатывать конфигурацию и реализацию более надежным способом. У Грааля есть специальный раздел в его документах.

Чтобы ваш пример работал с использованием Spring, вы должны зарегистрировать свой сервис в качестве компонента в resources.groovy

// Resources.groovy
import com.example.ExampleApiClient

beans {
    // Defines your bean, with constructor params
    exampleApiClient ExampleApiClient, 'baseUrl', 'username', 'password'
}

Тогда вы сможете внедрить зависимость в ваш сервис

class ExampleService {
    def exampleApiClient

    def relevantMethod(){
        exampleApiClient.action()
    }
}

Кроме того, в вашем Config.groovyфайл, вы можете переопределить любое свойство компонента, используя соглашение Grails по синтаксису конфигурации: beans.<beanName>.<property>:

// Config.groovy
...
beans.exampleApiClient.baseUrl = 'http://example.org'

И то и другое Config.groovy а также resources.groovy поддерживает различные конфигурации среды.

Для контекстов, где вы не можете внедрить bean-компонент grailsApplication (служба не входит в число тех, что описаны Jon Cram), например, вспомогательный класс, расположенный в src/groovy, вы можете получить к нему доступ с помощью класса Holders:

def MyController {
   def myAction() {
      render grailsApplication == grails.util.Holders.grailsApplication
   }
}

Лучшие варианты (как из документов Grails):

1 - Использование весны @Valueаннотация

      import org.springframework.beans.factory.annotation.Value

class WidgetService {

    int area

    @Value('${widget.width}')
    int width

    def someServiceMethod() {
        // this method may use the width property...
    }
}

2 - Реализация вашего класса GrailsConfigurationAware

      import grails.config.Config
import grails.core.support.GrailsConfigurationAware

class WidgetService implements GrailsConfigurationAware {

    int area

    def someServiceMethod() {
        // this method may use the area property...
    }

    @Override
    void setConfiguration(Config co) {
        int width = co.getProperty('widget.width', Integer, 10)
        int height = co.getProperty('widget.height', Integer, 10)
        area = width * height
    }
}
Другие вопросы по тегам