在工作中遇到过一个这样的线上问题:在执行某个功能的时候,返回了非此次业务处理的数据。然后去看代码发现,这个功能的代码返回的集合是这个service的成员变量,而不是这个业务方法的局部变量,且这个成员变量在业务方法中没有初始化。具体看下这样写会有什么问题。
根据这个问题,我写了个测试代码,来验证这个问题。如下图:
这段代码中,方法testse1() 和testse2()方法都是重新去spring容器中获取bean,调用其test()方法,往bean的成员变量articleNumbers中添加字符串。在图3的JUnit测试方法中,使用线程池让testse1() 和testse2()方法是单独的线程执行,上面的gc()和sleep()是希望在执行之前能触发jvm的垃圾回收(System.gc()指令只是告诉JVM尽快GC一次,但不会立即执行GC,具体视情况而定)。运行下代码,看testse1() 和testse2()分别打印什么样的信息,如下图:
从图4的运行结果可以看到,testse2()在打印返回数据信息时,将testse1()方法添加到成员变量的数据也打印出来了。说明在testse2()从spring容器中获取Bean的时候没有对articleNumbers进行初始化(这个可以去看看spring bean 的生命周期),也没有被垃圾回收。
总结:默认情况下,一个spring bean 从创建开始就会长期保存在spring容器中,以方便获取。由于这个bean 一直存在spring容器中,其成员变量对内存空间的引用是强引用,且一直存在,直到spring 容器关闭。所以Spring Bean 中的成员变量不会被垃圾回收。在使用spring bean的成员变量时候需要注意哦。
回到上面的问题,如果需要将正确返回数据且使用Bean的成员变量,那可以在返回数据之后对成员变量进行清理,具体代码,如下图:
运行结果如下图:
从结果中可以看出,testse2得到的返回数据,没有不需要的数据,说明已经没有上面所说的问题了。除了对成员变量进行清理,也可以在使用成员变量前进行初始化。
领取专属 10元无门槛券
私享最新 技术干货