Внедрить конфигурацию приложения 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):
впрыскивать
grailsApplication.config.apiCredentials
в службу в контроллере, когда служба создается?Предоставить некоторую форму конструктора в службе, которая позволяет передавать учетные данные в службу во время создания экземпляра?
Внедрение учетных данных в сервис идеально. Как это можно сделать?
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
}
}