39

我正在创建一个 grails 服务,它将通过 Java 库与第 3 方 REST API 进行交互。Java 库通过 url、用户名和密码需要 REST API 的凭据。

我想将这些凭据存储在 中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

4 回答 4

81

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();
    }
}
于 2011-02-11T21:11:50.897 回答
11

尽管grailsApplication可以注入服务,但我认为服务不应该处理配置,因为它更难测试并且违反了单一责任原则。另一方面,Spring 可以以更健壮的方式处理配置和实例化。Grails在其文档中有专门的部分。

为了使您的示例使用 Spring 工作,您应该将您的服务注册为 beanresources.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 约定优于配置语法来覆盖任何 bean 属性beans.<beanName>.<property>

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

两者都Config.groovy支持resources.groovy不同的环境配置。

于 2014-09-23T15:55:36.283 回答
4

对于无法注入 grailsApplication bean 的上下文(服务不是其中之一,如 Jon Cram 所述),例如位于 src/groovy 中的帮助程序类,您可以使用Holders类访问它:

def MyController {
   def myAction() {
      render grailsApplication == grails.util.Holders.grailsApplication
   }
}
于 2014-06-06T08:00:45.347 回答
0

最好的选择是(来自grails docs):

1 - 使用 Spring@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
    }
}
于 2022-01-11T20:23:59.777 回答