在最近的一次项目上线之后,遇到了大面积客户,报告系统服务异常的情况.查看服务器的日志发现了空指针异常,发现是该类的所有注入的service都为null.但是无法在短时间快速的找到问题,并且修复,只能回滚本次上线代码....
回滚之后,开始紧锣密鼓的排查工作,一开始猜测是因为抽象类原因导致注入失败(虽然不太可能,因为之前都是正常运行的代码),但是后来查阅资料发现,spring在为bean注入属性的时候,会将其父类的属性也一并注入了,所以这里问题的产生和抽象类没有关系.
因为实在没有头绪,只能开始排查本次上线的改动点,最后发现有一个点比较可疑,本次上线中增加了一个配置,在applicationContext.xml中增加了这样一行配置.
当时这是为了解决注入失败的问题而增加的配置(乌龙事件,注入类的时候,一个类不小心写成了实现类,而非接口,导致jdk动态代理注入失败),将动态代理强制改为了CGLIB.为了验证猜想将配置去掉,发现注入成功,不再报错(这里有个误区,一直以为是注入失败的问题,导致排查问题走了很多弯路).问题已经找到, 于是开始排查原因,排查过程不再赘述,这里直接说最后的原因.
CGLIB动态代理在创建代理的,会将静态方法,final方法等排除在外.
这导致,cglib的代理根本不会去拦截final和静态方法.在我们的项目中,调用的正是final方法
由于这个execute是final方法,所以cglib不会拦截.在spring中,cglib的代理最终执行的方法,是通过被代理对象去执行的(假设方法被拦截到的话),而被代理的对象中,这些注入的属性都是有值的,所以执行成功.而本例中,由于是final方法,不会被拦截,所以直接通过代理类对象本身去调用execute方法,而不是通过被代理对象去执行,而问题就出在代理对象中的属性是从来没有被注入过的,所以出现了空指针的情况.问题到此已经一清二楚.
仅作记录!