如何创建同一服务的两个配置实例?

时间:2013-06-19 23:09:26

标签: grails

我有一个与经纪帐户的API交互的服务。它工作正常,但现在我需要在同一经纪人处与两个不同的账户进行互动。

处理此问题的最佳方法似乎是可以将服务配置为指定目标帐户,然后实例化两个不同的实例,每个帐户一个。

我不确定Grails是否支持这种方式或者如何解决这个问题。

两个问题:

  1. 有更好的方法吗?
  2. 如果没有,我如何实例化和配置两个不同的服务实例?
  3. 其他信息:

    两个答案都接近失误。让我试着澄清一下:

    我不想深入了解细节,但这可能有助于解释我所追求的内容。我正在使用Interactive Brokers交易API,他们不会像其他经纪人那样直接与他们的服务器交谈。您必须通过套接字与IB网关进行通信,这是他们提供的基本上代理其服务器的软件。因此,您的应用程序与IB Gateway进行通信,IB Gateway代表您的应用程序与Interactive Brokers的服务器进行对话。

    问题在于,IB Gateway必须作为其配置的一部分登录到帐户。因此,为了交易两个不同的帐户,您别无选择,只能配置两个不同的IB网关,因为每个网关只能访问配置的帐户。

    因此,我的用于放置交易的Grails代码必须选择正确的IB网关进行交谈。这意味着它需要知道与每个帐户对应的IB网关的IP地址和端口。除了IP地址和端口的此设置之外,与IB网关通信的两个Grails服务之间没有区别。

    我想要的是重用相同的服务类,每个服务类都被实例化为一个单例,只需要有一个不同的IP地址和端口进行通信。

    因此,制作两种不同的服务是不可取的,因为代码在其他方面是相同的。 (如果我添加第三个或第四个IB网关,这将成为相当臭的代码。)

    这个设置应该在应用程序的生命周期中存在,所以我认为范围的变化也不是真正的答案。

    我真的想要两个相同服务的实例,只需要有不同的配置。

    我希望这有助于解释这种情况。你有什么建议?谢谢!

2 个答案:

答案 0 :(得分:2)

如果相同的业务逻辑适用于两个帐户,但考虑到您不能让一个服务类与两个帐户的API通信,那么是的,您可以拥有2个服务类(这些只是2个不同的spring bean) )使用默认的单例范围。

class Account1Service{
}

class Account2Service{
}

如果我有可以共享的共同逻辑,我也会尝试在这种情况下使用继承。但请记住,如果要从抽象类继承服务类,则必须将抽象类放在src/groovy中,即/grails-app/之外,以拒绝依赖注入。在这种情况下,您最终可能会(未经测试,但您可以遵守DRY概念)

// src/groovy
abstract class BrokerageService {
    def populateAccountDetails(Long accountId)
    def checkAccountStatus(Long accountId)
}

//grails-app/services
class Account1Service extends BrokerageService {
    //Implement methods + add logic particular to Account1
    //By default transacitonal
}

class Account2Service extends BrokerageService {
    //Implement methods + add logic particular to Account2
    //By default transacitonal
}

另请注意范围为singleton,您需要特别注意(更好地避免)在Service类中维护全局范围属性。尝试尽可能使无状态。除非情况或业务逻辑要求使用sessionflowrequest等服务级别范围,否则我将始终坚持使用默认的singleton范围。

要回答第二个问题,您不需要实例化任何grails服务类。当使用适当的命名法时,容器会注入适当的服务类(使用Spring IoC)。在上面的示例中,如果您在要使用服务的类中遵循此命名约定,将自动注入服务类:

//camelCase lower initial
def account1Service 
def account2Service

<强>更新
这是对OP提供的附加信息的回应。

参考上面的场景,默认service范围内只能有一个singleton类来完美地处理事情。最好的部分,因为您离开网络而不是真的担心自己的数据库事务,所以可以将服务类设置为非事务性的。但这又取决于需要的情况。以下是服务类的外观。

//grails-app/service
class BrokerageService{

    //Service method to be called from controller or any endpoint
    def callServiceMethod(Long accountId){
        .......
        doSomethingCommonToAllAccounts()
        .........

        def _ibConfig = [:] << lookupIBGatewayConfigForAccount(accountId)
        ........

        //Configure an IB Gateway according to the credentials
        //Call IB Gateway for Account using data got from _ibConfig map
        //Call goes here 
    }

    def doSomethingCommonToAllAccounts(){
        ........
        ........
    }

    def lookupIBGatewayConfigForAccount(accountId){
        def configMap = [:]
        //Here lookup the required IP, account credentials for the provided account
        //If required lookup from database, if you think the list of accounts would grow
        //For example, if account is JPMorgan, get credentials related to JPMorgan

        //put everything in map
        configMap << [ip: "xxx.xx.xx.xxx", port: 80, userName: "Dummy"] //etc

        return configMap
    }
}

服务类的范围是singleton,这意味着堆中只有一个类的实例,这也意味着任何类级属性(除了方法)都是有状态的。在这种情况下,您只处理无状态的方法,并且满足目的。每次交易发生时,您都可以获得所需而无需花钱堆或不创建BrokerageService的新实例。

每笔交易(附有账户)最终将调用该服务,从db(或配置属性,平面文件或属性文件)中查找凭证,然后配置IB网关并与网关通话/通话。 / p>

答案 1 :(得分:1)

Grails服务应该是singletons by default,没有任何状态与它正在做的事情相关联,通常只有一个实例。也就是说,通常你不会在其中包含实例字段。

但是如果你覆盖默认范围,你可以拥有它们。例如,您可以将服务设置为会话范围,添加此静态变量:

static scope = "session"

然后,每个用户会话都有一个实例。

对于您的特定情况,您可能需要查看原型范围,每次需要注入时,它将为您提供新的服务实例。如果您希望它们对相同的数据起作用,您只需要确保在注入后始终使用该实例。

看看the docs about Scoped Services