(原创)spring mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法

项目中没用spring 的restTemplate 而是采用 jersey来做rest 的实现,一直用着,也没发现有什么不对,后来加入了,以quartz用硬编码方式实现,结果启动项目的时候报错 ,具体信息为job id重复。后来经排查是因为:jersey依赖于org.springframework.web.context.ContextLoaderListener初始化 的ApplicationContext,而spring mvc 依赖于org.springframework.web.servlet.DispatcherServlet初始化的ApplicationContext,也就是说jersey和spring mvc 虽然是共用一个ApplicationContext但是ApplicationContext被初始化了两次,每次都会调用 beanFactory.preInstantiateSingletons()方法,导致了单例的类被初始化两次,平常使用是没问题的,只是每个单例类都实例化了两个对像(bean工厂中,你访问到的是第二次实例化的),恰巧我们的项目中,SchedulJobManager实例化后我们要设置一些JOB ,且这个JOB的ID是不能重复的,就触发了这个BUG。jersey版本比较老1.4.1,不知新版本的 jersey会不会不存在这问题,且最后我通过修改spring AbstractApplicationContext源码 解决了这问题,具体排查解决过程如下如下图(原创)spring   mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法

很是奇怪,然后在构造函数中加了一个日志输出,下如图所示,结果发现 Schedul Initializing 这行条了两次

(原创)spring   mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法

接下来,检查web.xml 的配置 如下图所示

(原创)spring   mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法

后来还怀疑过是不是 jersey这个springServlet搞的鬼,去掉他,还是有同样的错 ,当时对这事,有个临时的解决办法,加一个全局静态变量 haveInit,在构造函中设置它为true PostConstruct标签的方法run方法中,如haveInit为true 就什么也不错返回。问题是解决了,但不是从根本上解决,于是我在代码中加了调用栈的打印。如图所示

(原创)spring   mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法

打印出来的结果是  ,org.springframework.web.context.ContextLoaderListener和org.springframework.web.servlet.DispatcherServlet分别都初始化了一次 appcationContext导致的,请看下图

(原创)spring   mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法

(原创)spring   mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法

解决办法是修改 spring AbstractApplicationContext类,做这样的修改:加一个全局静态变量 haveInitFlg缺省值为0 ,在finishBeanFactoryInitialization方法中

最后一行代码beanFactory.preInstantiateSingletons();  修改为

if(haveInitFlg==0){
            beanFactory.preInstantiateSingletons();
            haveInitFlg = 1;
        }

即可

上一篇:【UOJ348】【WC2018】州区划分 状压DP FWT


下一篇:node论坛练手