我有一个与经纪帐户的API交互的服务。它工作正常,但现在我需要在同一经纪人处与两个不同的账户进行互动。
处理此问题的最佳方法似乎是可以将服务配置为指定目标帐户,然后实例化两个不同的实例,每个帐户一个。
我不确定Grails是否支持这种方式或者如何解决这个问题。
两个问题:
其他信息:
两个答案都接近失误。让我试着澄清一下:
我不想深入了解细节,但这可能有助于解释我所追求的内容。我正在使用Interactive Brokers交易API,他们不会像其他经纪人那样直接与他们的服务器交谈。您必须通过套接字与IB网关进行通信,这是他们提供的基本上代理其服务器的软件。因此,您的应用程序与IB Gateway进行通信,IB Gateway代表您的应用程序与Interactive Brokers的服务器进行对话。
问题在于,IB Gateway必须作为其配置的一部分登录到帐户。因此,为了交易两个不同的帐户,您别无选择,只能配置两个不同的IB网关,因为每个网关只能访问配置的帐户。
因此,我的用于放置交易的Grails代码必须选择正确的IB网关进行交谈。这意味着它需要知道与每个帐户对应的IB网关的IP地址和端口。除了IP地址和端口的此设置之外,与IB网关通信的两个Grails服务之间没有区别。
我想要的是重用相同的服务类,每个服务类都被实例化为一个单例,只需要有一个不同的IP地址和端口进行通信。
因此,制作两种不同的服务是不可取的,因为代码在其他方面是相同的。 (如果我添加第三个或第四个IB网关,这将成为相当臭的代码。)
这个设置应该在应用程序的生命周期中存在,所以我认为范围的变化也不是真正的答案。
我真的想要两个相同服务的实例,只需要有不同的配置。
我希望这有助于解释这种情况。你有什么建议?谢谢!
答案 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类中维护全局范围属性。尝试尽可能使无状态。除非情况或业务逻辑要求使用session
,flow
或request
等服务级别范围,否则我将始终坚持使用默认的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"
然后,每个用户会话都有一个实例。
对于您的特定情况,您可能需要查看原型范围,每次需要注入时,它将为您提供新的服务实例。如果您希望它们对相同的数据起作用,您只需要确保在注入后始终使用该实例。