问题现象最近在本地调试公司的一个web项目时,无意中发现日志中有两条同一个服务的init记录。应该只有一个服务来加载日志。本着对工作认真负责的态度(没事做),一定要搞清楚。问题分析为什么同一个Bean被容器初始化了两次?首先我们来梳理一下web容器中bean的加载方式:在web容器中,ContextLoaderListener和DispatchServlet都会在容器启动的时候加载bean。不同的是DispatchServlet一般会加载MVC相关的bean,而ContextLoaderListener会加载Spring相关的bean。两者都会分别生成一个WebApplicationContext。根据web.xml的加载顺序,listener会在servlet之前加载。获取bean时,会先从DispatchServlet生成的WebApplicationContext中查找。如果找不到,则从ContextLoaderListener生成的WebApplicationContext中查找。那么如果这两个加载同一个Bean,应该使用谁的呢?如果两个配置文件中定义了同一个bean,实际使用时只会使用到DispatchServlet中的bean,而无法调用ContextLoaderListener中的bean,造成内存泄漏。接下来我们看一下项目中的web.xml配置。如下图,ContextLoaderListener和DispatchServlet加载相同的配置spring.xml,所以会出现两个Bean初始化现象。解决方案经过上面的分析,我们知道,同一个bean之所以会被加载两次,是因为我们在DispatchServlet和ContextLoaderListener中都定义了这个bean。因此,我们要做的就是让ContextLoaderListener和DispatcherServlet分别加载不同的bean:添加applicationContext.xml,声明ContextLoaderListener要加载的bean:修改spring.xml中的包扫描范围,让DispatcherServlet只加载mvc-相关bean:启动服务,查看初始化信息。该服务仅初始化一次:
