I have a question:
Why when we annotate method with @Scheduled
and @Transaction
, transaction doesn't work?
I know that the @Scheduled
call my class instead of proxy class that created by Spring, but can't understand this behavior.
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserServiceImpl implements UserService {
@Override
@Scheduled(fixedRateString = "${somestring}",initialDelayString = "${anotherstring}")
@Transactional
public void doSomething() {
}
}
I have two solutions of this problem:
Call proxy from
Scheduled
method.Implement
ConcurrentTaskScheduler
and replace object ofScheduledMethodRunnable
(that is with my class) with object ofScheduledMethodRunnable
with proxy.
But this solutions is very inconvenient.
Can you explaim me why @Scheduled
works like this?
Thank you!
The Question is not private or public, the question is: How is it invoked and which AOP implementation you use!
If you use (default) Spring Proxy AOP, then all AOP functionality provided by Spring (like
@Transational
) will only be taken into account if the call goes through the proxy. -- This is normally the case if the annotated method is invoked from another bean.This has two implications:
@Transactional
Annotation is not taken into account.you can also use the aspectJ mode, instead of the Spring Proxies, that will overcome the problem. And the AspectJ Transactional Aspects are woven even into private methods (checked for Spring 3.0).
refer: http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/aop.html#aop-proxying
It happens because to process both annotations MAGIC is used.
I suppose there are several things happens:
UserServiceImpl
is created.@Scheduled
annotation is processed and reference to bean is stored to invoke it at appropriate time.@Transactional
annotation is processed. It create proxy which store reference to original bean. Original bean is replaced to proxy in application context.If step 2 and 3 passed in different order then you had no problem.
I don't know how to control order in which annotation is processed. I don't even sure it is possible at all.
There is basically two solution.
@Transaction
. Default way is to create proxy object, but it is possible to instructSpring
to instrument current class.Example:
I'm personally recommend second approach.