背景:公司使用的还是jdk7,早就想升级到jdk8,但是很坑爹的是,公司的框架使用的是Netty3.2.7和spring3.x,不能升级,jdk8必须使用spring4.x才可以,当然,spring4.x可以向下兼容jdk7.思考再三,长痛不如短痛,升级Netty3.2.7到Netty4.1.31(Netty最新版本是5.x但是废弃了,不建议使用),spring3.x升级到spring4.3.20,这样就可以升级到jdk8了
Netty4.x居然不兼容Netty3.x,连包名都换了,升级到4.1.31的过程是痛苦的,代码各种红,各种踩坑,这不是本篇重点,后面写博客一遍Netty升级的踩坑记录
问题:升级以后,Controller注入service失败,跟踪发现为null,如下图:
最初猜测是spring没有加载到,因此写了工具类来验证,如下图:
可以看到,的确是拿到了注入的service,但是为啥是null呢?
难道拿到的controller和当前controller不是同一个嘛?
居然还真不是同一个,那么注入失败,也就找到原因了,下面排查为啥不是同一个controller
跟踪公司框架源码,发现如下代码:
用反射获取的Controller,然后反射调用:
那么问题就在这里了,最初调试的this controller是反射获取的,当然注入失败,无法调用了
尝试解决:
(1)反射获取的bean,如何注入spring bean对象呢?
先获取spring中的controller,然后,修改调用参数,如下所示:
invokeBizMethod(course,messsage);修改为:
invokeBizMethod((BusinessCourse) ApplicationContextHelper.getBean(ClassUtil.getClassLowerName(course.getClass())), message);
调试发现也不行,因为这个时候Controller不一定被Spring加载到,因为,Spring中加载bean的顺序是不定的,当然,如果能控制Controller的加载顺序先于反射调用的地方,也是可以解决问题的,问题转化为(2)中的bean加载顺序问题。
(2)不用反射拿对象,直接问Spring要
不能框架层反射获取,那么就在项目中直接获取,因为用的是springBoot,没有配置文件,因此笨办法写一个ControllerCollect的辅助类去获取,然后赋值
需要赋值的地方如下:
这样可以解决问题,但是太low了
修改如下:在Controller的基类BaseController中直接获取
然后赋值语句 更新为 httpBizEntry.setCourses(BaseController.courses);
但是这样发现赋值为[],也就是没有赋值成功,分析原因,是spring中bean加载顺序问题。因为赋值的地方也是@Bean注解修饰的,
那么获取coureses的bean必须先于赋值地方的这个bean加载才可以,这样需要解决的就是如何控制spring中bean的加载顺序问题。
Spring中bean的加载顺序,根据需要有明显的加载依赖关系,首先,可以在代码中手动初始化加载,当然这个肯定不会用了,其次考虑用@DependOn注解来控制,但是Controller是多个,只要继承了BaseController的都是,并且需要指定bean name,分析以后,不符合要求。最后,考虑用@Order注解来控制,修改如下:
问题解决,其实如果使用配置文件,直接xml里面配置,就不会出现这个问题,现在虽然解决了问题,但是也需要在代码里面配置,还是不够友好,后面还是需要考虑如何在框架层处理掉,待完善。