View Full Version : References between services
tliebscher
05-03-2007, 03:59 PM
We're migratiting our CRM Tool to spring atm and we've encountered an issue to which we haven't been able to find a descent solution yet.
We have several domain objects like an Incident, a Problem and a Change. They are implemented as PONOs with a DAO for each handling the persistence. Now we have Services that contain the business logic like a ChangeServices that has methods like getChanges() ...
Now the issue ist, that all the Domain objects may be related and when you save one, changes may have to happen in others too. For example when saving a Change the related problems have to be notified and they notify their related Incidents and flags are set there.
So what I did in the first run was the following:
UI calls ChangeService.SaveChange()
ChangeService.SaveChange() calls ProblemService.notifyProblemChangeSaved()
ProblemService.notifyProblemChangeSaved() calls IncidentService.NotifyIncidentChangeSaved()
In this scenario the ChangeService needs a reference on the ProblemService and that one on the IncidentService. Now we have a different workflow which goes exactly the other way round and that's where we get stuck. Spring doesn't allow references in both directions because then instantiating would cause an endless loop.
Now my solution atm is to add an additional layer, in this case the ChangeWorkflow, which has the references to all other Services.
UI calls now ChangeWorkflow.SaveChange()
ChangeWorkflow.SaveChange() calls ChangeService.SaveChange() which now only does the most basic stuff like initiating some values if necessary.
then ChangeWorkflow.SaveChange() calls ProblemService.notifyProblemChangeSaved() and at last IncidentService.NotifyIncidentChangeSaved()
There are two things I don't like about this solution. Firstly it's not very object-oriented, since I think ProblemService should know whether to inform IncidentService or not. And secondly when another Workflow for example in Incident needs to save a Change I may have to reimplement some of the stuff I implemented in ChangeWorkflow.SaveChange().
I don't know if I could make my problem clear, since I'm not a native english speaker, but I would really appreciate any help on this topic. Many thanks ahead.
RolandSchmitt
05-09-2007, 11:17 AM
Hi there, I have the same problem: I need two services having reference of each other.
Is there any solution yet?
Hi.
I use this code:
<object id="Service1" type="Test.Service1, Test">
<property name="Service2" ref="Service2" />
</object>
<object id="Service2" type="Test.Service2, Test">
<property name="Service1" ref="Service1" />
</object>
and
namespace Test
{
class Service2
{
private Service1 service1;
public Service1 Service1
{
set
{
service1 = value;
}
}
}
}
namespace Test
{
class Service1
{
private Service2 service2;
public Service2 Service2
{
set
{
service2 = value;
}
}
}
}
It works.
Did I understand you correctly?
Best regards.
Bruno Baia
05-10-2007, 04:58 PM
Hi.
I use this code:
<object id="Service1" type="Test.Service1, Test">
<property name="Service2" ref="Service2" />
</object>
<object id="Service2" type="Test.Service2, Test">
<property name="Service1" ref="Service1" />
</object>
and
namespace Test
{
class Service2
{
private Service1 service1;
public Service1 Service1
{
set
{
service1 = value;
}
}
}
}
namespace Test
{
class Service1
{
private Service2 service2;
public Service2 Service2
{
set
{
service2 = value;
}
}
}
}
It works.
Did I understand you correctly?
Best regards.
Since you don't make circular references with contructor arguments value, it will works.
This will not work for obvious reasons :
<object id="Service1" type="Test.Service1, Test">
<constructor-args name="Service2" ref="Service2" />
</object>
<object id="Service2" type="Test.Service2, Test">
<constructor-args name="Service1" ref="Service1" />
</object>
- Bruno
Bruno Baia
05-10-2007, 05:01 PM
I forgot,
<object id="Service1" type="Test.Service1, Test">
<property name="Service2" ref="Service2" />
</object>
<object id="Service2" type="Test.Service2, Test">
<property name="Service1" ref="Service1" />
</object>
This example does not work in a Web application (when using Spring.Web and the WebApplicationContext).
This is a known bug I got in my todo list ( Jira Issue (http://opensource.atlassian.com/projects/spring/browse/SPRNET-504) ).
- Bruno
Bruno Baia
05-11-2007, 02:22 PM
Actually it works, what does not work is referencing non singletons objects
<object id="Service1" type="Test.Service1, Test" singleton="false">
<property name="Service2" ref="Service2" />
</object>
<object id="Service2" type="Test.Service2, Test" singleton="false">
<property name="Service1" ref="Service1" />
</object>
This happens when using Pages which are always prototypes (singleton="false").
This post (http://forum.springframework.net/showthread.php?t=2062) shows you an example.
- Bruno
tliebscher
05-14-2007, 03:44 PM
Well, you see me astonished! It seems I was relying on wrong information from my colleagues, because it really seems to work. Our Services are singletons, so although we are in a Web Application it actually seems to work fine as my first tests showed.
I suppose my co-workers ran into that problem before it got fixed and also I am sure I've had this problem to, I assume I must have been trying to avoid it from the beginning, because they warned me.
Well I'll do some deeper testing but it really looks good atm. Thanks a lot!
tliebscher
05-14-2007, 04:16 PM
Ok, I take it back. Yes, it does work, but only as long as you don't wrap the services with transaction proxies.
So while this works:
<object id="changeManager" type="FirstAnswer.Service.DefaultImplementation.ChangeMa nager, FirstAnswer.Core">
<property name="RequestForChangeManager" ref="requestForChangeManager"/>
</object>
<object id="requestForChangeManager" type="FirstAnswer.Service.DefaultImplementation.RequestF orChangeManager, FirstAnswer.Core">
<property name="ChangeManager" ref="changeManager"/>
</object>
<object type="~/Change/RequestForChangeList.aspx">
<property name="RequestForChangeManager" ref="requestForChangeManager" />
</object>
This doesn't work:
<object id="changeManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="Target" ref="changeManagerTarget"/>
<property name="ProxyInterfaces" value="FirstAnswer.Service.IChangeManager"/>
<property name="InterceptorNames" value="transactionInterceptor"/>
</object>
<object id="changeManagerTarget" type="FirstAnswer.Service.DefaultImplementation.ChangeMa nager, FirstAnswer.Core">
<property name="RequestForChangeManager" ref="requestForChangeManager"/>
</object>
<object id="requestForChangeManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="Target" ref="requestForChangeManagerTarget"/>
<property name="ProxyInterfaces" value="FirstAnswer.Service.IRequestForChangeManager"/>
<property name="InterceptorNames" value="transactionInterceptor"/>
</object>
<object id="requestForChangeManagerTarget" type="FirstAnswer.Service.DefaultImplementation.RequestF orChangeManager, FirstAnswer.Core">
<property name="ChangeManager" ref="changeManager"/>
</object>
<object type="~/Change/RequestForChangeList.aspx">
<property name="RequestForChangeManager" ref="requestForChangeManager" />
</object>
It throws the following error:
AopConfigException: Cannot create IAopProxy with no advisors and no target source]
Spring.Aop.Framework.DefaultAopProxyFactory.Create AopProxy(AdvisedSupport advisedSupport) +209
Spring.Aop.Framework.AdvisedSupport.CreateAopProxy () +121
Spring.Aop.Framework.ProxyFactoryObject.GetSinglet onInstance() +62
Spring.Aop.Framework.ProxyFactoryObject.GetObject( ) +58
Spring.Objects.Factory.Support.AbstractObjectFacto ry.GetObjectForSharedInstance(String name, Object instance) +349
[ObjectCreationException: Error thrown by a dependency of object 'changeManager' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]' : IFactoryObject threw exception on object creation.
while resolving 'Target' to 'changeManagerTarget' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]'
while resolving 'RequestForChangeManager' to 'requestForChangeManager' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]'
while resolving 'Target' to 'requestForChangeManagerTarget' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]'
while resolving 'ChangeManager' to '' ]
...
Bruno Baia
05-15-2007, 05:23 PM
Hi,
Can you try using ProxyFactoryObject.TargetName property instead of Target property ?
<object id="changeManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="TargetName" value="changeManagerTarget"/>
...
<object id="requestForChangeManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="TargetName" value="requestForChangeManagerTarget"/>
...
- Bruno
tliebscher
05-16-2007, 03:18 PM
Unfortunately it didn't help. The exception is still the same, except it now says TargetName instead of Target ;-)
[AopConfigException: Cannot create IAopProxy with no advisors and no target source]
Spring.Aop.Framework.DefaultAopProxyFactory.Create AopProxy(AdvisedSupport advisedSupport) +209
Spring.Aop.Framework.AdvisedSupport.CreateAopProxy () +121
Spring.Aop.Framework.ProxyFactoryObject.GetSinglet onInstance() +62
Spring.Aop.Framework.ProxyFactoryObject.GetObject( ) +58
Spring.Objects.Factory.Support.AbstractObjectFacto ry.GetObjectForSharedInstance(String name, Object instance) +349
[ObjectCreationException: Error thrown by a dependency of object 'changeManager' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]' : IFactoryObject threw exception on object creation.
while resolving 'TargetName' to 'changeManagerTarget' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]'
while resolving 'RequestForChangeManager' to 'requestForChangeManager' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]'
while resolving 'TargetName' to 'requestForChangeManagerTarget' defined in 'file [D:\WebRoot\1stAnswerR3.1\FirstAnswer.Web\springser vice.xml]'
while resolving 'ChangeManager' to '' ]
Bruno Baia
05-16-2007, 04:35 PM
Hi,
It seems you let ref="changeManagerTarget".
When using TargetName property, you need to specify a string with the object id name, not the object itself with a reference : value="changeManagerTarget".
- Bruno
tliebscher
05-21-2007, 10:51 AM
Hi,
of course you were absolutely right, and now it's even working :-) Thanks a lot, this is really a great deal of help for us!
BR
Torsten Liebscher
vBulletin® v3.7.3, Copyright ©2000-2009, Jelsoft Enterprises Ltd.