There is a kind of circular dependency in circular dependency , It's self injection : Depend on yourself .
stay Spring Self calling transaction failure , How did you solve it ? Some small partners suggest that they can inject themselves to solve the transaction failure .
The specific usage is as follows :
@Slf4j @Service public class OrderBizServiceImpl implements OrderBizService { // Inject yourself @Autowired private OrderBizService orderBizService; @Override public void callBack() throws Exception { // A series of logic // Transaction operation is needed to update order and user amount orderBizService.updateOrderStatusAndUserBalance(); } @Override @Transactional(rollbackFor = Exception.class) public void updateOrderStatusAndUserBalance() throws Exception { // Inside is transaction logic } }
Did you find something amazing , The transaction is in effect .
In fact, I put myself in here , It's actually a proxy object injected , Mediation , It is also the transaction of the proxy object of the call , So the transaction takes effect .
Spring Transaction failure reason : Transactions can only be applied to public It works in a way ; Transactions need to be called from outside ,Spring Self calls will fail ; Suggested transaction notes @Transactional It is usually added to the implementation class .
Find out @Transactional Annotations can be self injected to solve the problem of transaction invalidation , In some development , It's natural to think of @Async Can asynchrony also self inject to solve the problem of loop dependence .
NO, NO, NO……
The facts tell us that it's impossible !
Start with mistakes :
Throw the exception part doCreateBean
Start pushing up exposedObject == bean There's something wrong with this one .
That is to say, when it's asynchronous , Again, the data obtained from the L2 cache is not the same as the initial one .
Object earlySingletonReference = getSingleton(beanName, false);
Get it again from the L2 cache Bean
This time, we found that it was different, so we reported an error .
Let's start. Debug, According to the logic of circular dependency , Execute to populateBean
when , Attribute assignment , Find yourself dependent , At this point, you create yourself .
perform singleton.getObject Method
getEarlyBeanReference
getBeanPostProcessors()
And at this point getEarlyBeanReference First judge InfrastructureAdvisorAutoProxyCreator
true call wrapIfNecessary Determine whether to generate a proxy object , There is no proxy object generated here .
And then start performing asynchronous AsyncAnnotationBeanPostProcessor
Judgment for false. So there is no asynchronous generation of proxy object logic .
So keep looking down
It's normal at this point
Enter into initializeBean The logic of , There's a part called applyBeanPostProcessorsAfterInitialization
Aspect partner search , So post the code keywords .IDEA Use
⌘ + Shift + F
Search for .
applyBeanPostProcessorsAfterInitialization
Loop execution post processor :
It's found that the execution is complete AsyncAnnotationBeanPostProcessor This PostProcessor after , The object has been changed . This results in the second level cache and the current Bean Different .
That's why @Async Self calling cannot , Because the proxy modifies the object in the later initialization phase .
getEarlyBeanReference
getBeanPostProcessors()
First judge InfrastructureAdvisorAutoProxyCreator true Generate a proxy object .
Generate proxy objects
The processor of the transaction PersistenceExceptionTranslationPostProcessor It's not implemented .
continue Debug Focus on applyBeanPostProcessorsAfterInitialization
end of execution , Find out Bean No change .
exposedObject == bean
by false , To throw an exception .Self injection
As you can see, there are two places in the diagram where BeanPostProcessor :
There are other places where the post processor is executing , such as applyBeanPostProcessorsBeforeInitialization , It's just that we focus on these two things .
In both cases, it is possible to generate proxy objects , @Transactional Is in getEarlyBeanReference Proxy object generated at , So I'll judge later Bean Whether it is changed or not true, and @Async The proxy object is generated asynchronously later , So the judgment doesn't pass .
thus , Analysis complete , The error of , Welcome to correct
- <End /> -
This article is from WeChat official account. - Programmer Xiaohang (gh_liuzhihang) , author : Liu Zhihang
The source and reprint of the original text are detailed in the text , If there is any infringement , Please contact the yunjia_community@tencent.com Delete .
Original publication time : 2021-02-02
Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .