将 Grails 应用程序配置注入到服务中

发布于 2024-10-17 07:30:53 字数 1277 浏览 7 评论 0原文

我正在创建一个 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. 在服务上提供某种形式的构造函数,允许在实例化时将凭据传递给服务?

将凭据注入到服务中是理想的选择。这怎么可能做到呢?

I'm creating a grails service that will interact with a 3rd party REST API via a Java library. The Java library requires credentials for the REST API by means of a url, username and password.

I'd like to store these credentials in configuration/Config.groovy, make them available to a service and ensure that credentials are available to the service before it requires them.

I appreciate that grailsApplication.config is available to controllers and that through a method of a service the relevant config values can be provided to the service, such as this:

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();
    }
}

I feel this approach is slightly flawed as it depends on a controller calling setCredentials(). Having the credentials made available to the service automagically would be more robust.

Is either of these two options viable (I currently not familiar enough with grails):

  1. Inject grailsApplication.config.apiCredentials into the service in the controller when the service is created?

  2. Provide some form of contructor on the service that allows the credentials to be passed in to the service at instantiation time?

Having the credentials injected into the service is ideal. How could this be done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

源来凯始玺欢你 2024-10-24 07:30:53

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();
    }
}

The grailsApplication object is available within services, allowing this:

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();
    }
}
风为裳 2024-10-24 07:30:53

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

要使您的示例使用 Spring 工作,您应该在 resources.groovy 中将您的服务注册为 bean

// 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..:

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

Both Config.groovy并且resources.groovy支持不同的环境配置。

Even though grailsApplication can be injected in services, I think services should not have to deal with configuration because it's harder to test and breaks the Single Responsibility principle. Spring, on the other side, can handle configuration and instantiation in a more robust way. Grails have a dedicated section in its docs.

To make your example work using Spring, you should register your service as a bean in resources.groovy

// Resources.groovy
import com.example.ExampleApiClient

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

Then you will be able to inject the dependency into your service

class ExampleService {
    def exampleApiClient

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

In addition, in your Config.groovyfile, you can override any bean property using the Grails convention over configuration syntax: beans.<beanName>.<property>:

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

Both Config.groovy and resources.groovy supports different environment configuration.

廻憶裏菂餘溫 2024-10-24 07:30:53

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

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

For contexts where you can't inject the grailsApplication bean (service is not one of those, as described by Jon Cram), for example a helper class located in src/groovy, you can access it using the Holders class:

def MyController {
   def myAction() {
      render grailsApplication == grails.util.Holders.grailsApplication
   }
}
最丧也最甜 2024-10-24 07:30:53

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

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
    }
}

The best options are (as from grails docs):

1 - Using Spring @Value annotation

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 - Having your class implement 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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文