At the moment (spring-retry version < 2.0.1), by default the order is undefined as both advices for @Retryable and @Transactional annotations have order = Ordered.LOWEST_PRECEDENCE.
It happens that RetryConfiguration advice implements IntroductionAdvisor interface. There is also method org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply that adds into list all found advisors, but it does it using 2 consecutive loops: at first it adds all advisors that implement IntroductionAdvisor interface and then all other avisors (this is why RetryConfiguration advisor always happen to be before BeanFactoryTransactionAttributeSourceAdvisor in this list). Then org.springframework.core.annotation.AnnotationAwareOrderComparator.sort method is called, but because both advisors have the same order, the method keeps the order of advisors in the list.
So, basically, the reason why @Retryable advisor is applied before @Transactional advisor at the moment is just "by accident", or "implementation detail". It could be changed any moment by changing implementation of AopUtils.findAdvisorsThatCanApply method or AnnotationAwareOrderComparator etc. So, it's better to not rely on this implementation detail in your code. :)
Starting from spring-retry version 2.0.1 (not released yet) there is new order attribute of @EnableRetry annotation that is equal to Ordered.LOWEST_PRECEDENCE - 1 by default to make sure @Retryable advice will always be ordered before @Transactional advice (when @Transactional advice order is default).
The order attribute could also be set to any other value, according to your needs, e.g. Ordered.LOWEST_PRECEDENCE - 4.
@EnableRetry(order = Ordered.LOWEST_PRECEDENCE - 4)
@Configuration
public class MyAppConfiguration {}
With this configuration (and starting from spring-retry 2.0.1 - by default) the order of applying advices will be as this:
@Retryable
@Transactional
Your method body
End of @Transactional
End of @Retryable