持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
问题由来
在使用AOP实现多数据源事务的过程中发现使用Autowired注解注入的ScDeptService为null,报空指针异常。
首先排除项目配置问题,接口都能正常使用,只是加了@MyTransactional这个自定义的注解后就出现了问题。
代码如下:(剧透一下,最后问题解决只改了一个单词就好了 ^_^)
//1.controller代码
@Autowired
private ScDeptService deptService;
//MyTransactional 自定义的注解
@RequestMapping("test")
@MyTransactional(transactionManagers={"transactionManager","mongoTransactionManager"})
private void test(){
Map<String, Object> map = new HashMap<>(2);
map.put("id","00004351cfd34bd9bc8a0304fbbf1f99");
ScDept dept = deptService.find(map);
dept.setUpdateTime(LocalDateTime.now());
deptService.delete(dept);
}
//2.自定义了一个切面类
@Component
@Aspect
public class MultiDataSourceTransactionAspect {
@Pointcut("@annotation(com.njusc.entity.annotation.MyTransactional)")
public void pointcut() {
}
@Before("pointcut() && @annotation(transactional)")
public void before(MyTransactional transactional) {
//逻辑代码.....
}
}
问题解决
通过百度发现也有许多小可爱出现了类似情况:在使用springAOP实现操作日志时导致Autowired注入失败。
最终验证了他们的解决方法得到答案:接口方法为private修饰的,在AOP适配的时候会导致service注入失败,并且同一个service在其他的public方法中没有这种情况。
改成public或者protected均能解决问题。
问题又来了
@Autowired背后实现的原理是怎样的?
为啥aop能影响我的@Autowired注入失败?
Spring默认AOP代理方式是什么?
动态代理原理是啥来着?
我改成@Resource还会注入失败吗?
@Autowired和@Resource的区别又是啥呢?
我为啥啥都不知道?
解答
@Autowired背后实现的原理是怎样的?
看这个大佬讲的就完事了。@Autowired注解的实现原理
为啥aop能影响我的@Autowired注入失败?
定义在切面AOP下的Controller类会走代理,不管private还是public方法bean都是null值,是因为CGLIB在做初始化的时候本身是没有bean属性注入的。
当方法为private的时候,由于没有被AOP拦截,它继续使用代理类,代理类中的 bean=null。
因此我们可以判定public方法在AOP过程中有其他的操作,不然bean的属性也是null。
org.springframework.aop.framework.CglibAopProxy类中有一个静态内部类CglibMethodInvocation,其中有一个方法invokeJoinpoint()
当publicMethod=true的时候,就会用实际对象来进行反射调用,实际对象的bean属性值我们之前已经看到了,是已经注入的。
因此public方法的bean会重新赋值。
不禁让我感叹:CSDN大佬还是多呀。 另外:百度真TM辣鸡,有条件的谷歌助手安排一下吧,谷歌前两条直接解决我的疑惑。