@Profile
solution
You definitely have to try Spring 3.1 @Profile
:
@Autowire
private MyService communicator;
//...
@Service
@Profile("prd")
class MyServiceImpl //...
@Service
@Profile("qa")
class MyServiceStub //...
Now depending on which profile is enabled, either DefaultMyService
will be initialized or MyServiceStub
.
You can choose between profile in various ways:
Spring AOP (explicit around every method)
In this example the aspect wraps around every single MyService
method separately and returns stubbed value:
@Aspect
@Service
public class StubAspect {
@Around("execution(public * com.blogspot.nurkiewicz.MyService.foo(..))")
public Object aroundFoo(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
return //stub foo() result
}
return pjp.proceed();
}
@Around("execution(public * com.blogspot.nurkiewicz.MyService.bar(..))")
public Object aroundBar(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
return //stub bar() result
}
return pjp.proceed();
}
private boolean stubMode() {
//whatever condition you want here
return true;
}
}
The code is pretty straightforward, unfortunately the return values are buried inside the aspect and you need a separate @Around
for every target method. Finally, there is no place for MyServiceStub
.
Spring AOP (automatically around all methods)
@Aspect
@Service
public class StubAspect {
private MyServiceStub stub = //obtain stub somehow
@Around("execution(public * com.blogspot.nurkiewicz.MyService.*(..))")
public Object aroundFoo(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
MethodSignature signature = (MethodSignature)pjp.getSignature();
Method method = signature.getMethod();
return method.invoke(stub, pjp.getArgs());
}
return pjp.proceed();
}
private boolean stubMode() {
//whatever condition you want here
return true;
}
}
This approach is more implicit as it automatically wraps every target method, including new methods added in the future. The idea is simple: if stubMode()
is off, run the standard method (pjp.proceed()
). If it is on - run the exact same method with exact same parameters - but on a different object (stub in this case).
This solution is much better as it involves less manual work (at the price of using raw reflection).
Note that if both MyService
implementations are Spring beans (even when one is annotated with @Primary
), you might run into weird troubles. But it should be a good start.
See also: