在Controller上使用@Transactional注解导致的接口404

背景

@Transactional对Controller的某个方法进行修饰时,该Controller下的所有接口都无法访问,出现大量404

分析和问题分解

1、@Transactional的原理是创建代理

2、Controller并无实现任何接口

3、代理类直接生成非原类型的对象,这会导致注解信息的丢失?如果符合该场景,Controller的扫描应该发生在代理创建之后

问题解决记录

1)在SpringBoot启动后,拿到ApplicationContext,通过Object getBean(String name) throws BeansException获取对应名称的bean,查看类型:com.sun.Proxy$xxxx,很明显是jdk代理生成的匿名子类

2)查找@Transactional注解的处理逻辑

AbstractAutoProxyCreator是继承了SmartInstantiationAwareBeanPostProcessor接口的,也就是说在每个Bean创建之后都会经过该bean进行处理,对于匹配的bean将会创建使用BeanFactoryTransactionAttributeSourceAdvisor的代理

3)那么如何匹配@Transactional

可以将注意力聚焦在AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean方法上,其实本质上的判断是使用AopUtils#canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)方法进行判断的,该方法是使用Advisor中的MethodMatcher对targetClass下的所有方法进行匹配的,任意一个匹配都将会对该类创建代理对象。

4)Controller扫描的时机?

Controller扫描的核心逻辑在AbstractHandlerMethodMapping,该类实现了InitializingBean接口的void afterPropertiesSet() throws Exception方法,该方法的调用时机是,在所有属性依赖被注入之后,Controller的扫描在该方法中定义。

Spring会扫描ApplicationContext中所有Bean定义,通过判断获取bean的类型,判断@Controller@RequestMapping注解来确定是否为一个Controller

5)AbstractBeanFactorypublic Class<?> getType(String name) throws NoSuchBeanDefinitionException方法返回的Bean的类型探讨

如果当前存在对应名称的单例bean,会直接返回单例对象的类型

如果Controller没有使用org.springframework.context.annotation.Scope注解,Controller就是一个单例Bean,很明显,当Spring启动时,ApplicationContext会初始化所有非懒加载的单例bean。这时,代理对象已经创建,导致public Class<?> getType(String name) throws NoSuchBeanDefinitionException方法取的代理对象的类型Proxy$xx

但如果Controller使用了org.springframework.context.annotation.Scope注解,将Controller的scope变为非单例('application’是一个最接近单例的选择),我们就可以避免获取到代理对象的类型,获取到Controller的真实类型。

6)为什么使用AspectJ代理的Controller能被扫描?@Transactional注解的却不行?
因为项目中用到了ShiroShiro注册了一个DefaultBeanFactoryPointcutAdvisor,当使用AspectJ时,又会注册一个AnnotationAwareAspectJAutoProxyCreator,当使用@Transactional时,DefaultBeanFactoryPointcutAdvisorAnnotationAwareAspectJAutoProxyCreator都会从BeanFactoryAdvisorRetrievalHelper中获取Advisor——都能取到与@Transactional匹配的BeanFactoryTransactionAttributeSourceAdvisor,所以导致@Transactional的类会进行两次代理,而Aspect由于使用了切面,只能匹配到AnnotationAwareAspectJAutoProxyCreator中为切面注册的Advisor,而无法满足DefaultBeanFactoryPointcutAdvisor的条件,这种现象跟DefaultBeanFactoryPointcutAdvisorAnnotationAwareAspectJAutoProxyCreator的顺序无关

拓展

在日常开发中,我们通常在XXXServiceImpl中使用事务,在注入bean时,使用的是对应的接口XXXService,但是,如果我们使用XXXServiceImpl时,就会出现Bean Not Found的异常,这里需要额外注意。

在Controller上使用@Aspect切面不会导致Controller的类型丢失

原因:因为Controller往往没有使用接口,这时使用的CGLiB创建的代理,CGLIB创建代理时会实现原来的类型??????

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
@Transactional注解controller使用是可以的。通常情况下,@Transactional注解主要用于service层的方法上,用于实现事务管理。但是在一些需要在controller层进行事务管理的场景下,也可以将@Transactional注解controller方法上。然而,需要注意的是,如果在controller方法上上@Transactional注解,可能导致整个controller的方法报404错误。为了解决这个问题,可以注入PlatformTransactionManager并在需要事务管理的方法中手动进行事务管理。这样可以在controller使用@Transactional注解。但是需要注意的是,尽量将@Transactional注解放在service层的最外层方法上,而不是在controller使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBootController到底能不能使用@Transactional注解?](https://blog.csdn.net/m0_48203500/article/details/124164863)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [关于Springbootcontroller@Transactional注解导致整个类无法访问的问题解决。](https://blog.csdn.net/ljiew123/article/details/105121072)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [controller层到底能不能用@Transactional注解?](https://blog.csdn.net/qq_43417581/article/details/126126906)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子的木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值