一、问题描述
WEB项目在继承Spring时候,默认的配置的是ContextLoaderListener
contextConfigLocation classpath:spring/spring-context.xml
org.springframework.web.context.ContextLoaderListener
这种配置会把Spring-context.xml配置的所有文件都加载进来,当spring-context.xml文件嵌入很多xml文件时候,加载非常的内容非常庞大,特别是涉及到后台定时任务时候,对开发来说非常不方便,还打印一大堆日志,影响开发效率,而且当发布项目的时候,可能在配置文件的修改忘记修改回来,导致发布出现BUG等。
二、问题分析:
在本地开发的大多时候,是不需要启动一些配置的,例如:quartz的配置,此种情况下,系统可以在配置文件中设置一个开关器,当配置的时候设置值的时候启动,不配置不启动,方便开发,提升效率。
通过开关器空值加载的spring文件,通过阅读ContextLoader源码发现,Spring在初始化Context的时候,获取到配置文件,只需要对:String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);这个地方修改即可:
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); if (idParam != null) { wac.setId(idParam); } else { // Generate default id... if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { // Servlet <= 2.4: resort to name specified in web.xml, if any. wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getServletContextName())); } else { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath())); } } } wac.setServletContext(sc); String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM); if (initParameter != null) { wac.setConfigLocation(initParameter); } customizeContext(sc, wac); wac.refresh();}
自定义ContextLoaderListener关系如下:
三、解决方案:
1、在web.xml配置文件时候,对配置文件拆分,分多个配置
contextConfigLocation classpath:spring/wms-jdbc.xml, classpath:spring/wms-job.xml
2、自定义ContextLoaderListener:
自定义的ContextLoaderListener,重写configureAndRefreshWebApplicationContext方法,通过配置文件控制获取配置XML的内容:
package com.oneplus.wms.mvc;import com.google.common.base.Joiner;import com.google.common.collect.Lists;import org.apache.commons.lang.ArrayUtils;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.support.PropertiesLoaderUtils;import org.springframework.util.ObjectUtils;import org.springframework.web.context.ConfigurableWebApplicationContext;import org.springframework.web.context.ContextLoaderListener;import javax.servlet.ServletContext;import java.io.IOException;import java.util.List;import java.util.Properties;/** * 功能描述:Spring启动时, WMS控制加载Spring配置文件 * * @author: Zhenbin.Li * Date: 16/1/8 Time: 10:45 */public class OneplusContextLoaderListener extends ContextLoaderListener { /** * sl4j */ private static final Logger LOGGER = LoggerFactory.getLogger(OneplusContextLoaderListener.class); /** * 配置文件名称 */ private static final String LOADER_CONFIG_FILE = "env-config.properties"; @Override protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); if (idParam != null) { wac.setId(idParam); } else { // Generate default id... if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { // Servlet <= 2.4: resort to name specified in web.xml, if any. wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getServletContextName())); } else { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath())); } } } wac.setServletContext(sc); String initParameter = assemblyInitParameter(sc.getInitParameter(CONFIG_LOCATION_PARAM)); if (initParameter != null) { wac.setConfigLocation(initParameter); } customizeContext(sc, wac); wac.refresh(); } /** * WMS对Spring启动设置开关加载配置文件 * * @param webXmlConfigInitParameter web.xml配置的Spring文件 * @return */ protected String assemblyInitParameter(String webXmlConfigInitParameter) { String initParameter = webXmlConfigInitParameter; ClassPathResource resource = new ClassPathResource(LOADER_CONFIG_FILE); Properties configureProps; try { configureProps = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException e) { throw new RuntimeException("加载" + LOADER_CONFIG_FILE + "配置文件失败!", e); } Object configJobDebug = configureProps.get(ContextLoaderListenerConfigType.JOB_DEBUG.getType()); if (configJobDebug == null) { LOGGER.debug("当前未配置加载Spring定时任务启动参数" + ContextLoaderListenerConfigType.JOB_DEBUG.getType() + ", 系统直接启动."); return initParameter; } String jobDebug = String.valueOf(configJobDebug).toUpperCase(); ContextLoaderListenerStatus listenerStatus = ContextLoaderListenerStatus.getByStatus(jobDebug); if (listenerStatus == null) { throw new RuntimeException("配置Spring定时任务启动参数" + ContextLoaderListenerConfigType.JOB_DEBUG.getType() + ", ON或者OFF, 当前配置:" + jobDebug); } String[] configures = StringUtils.split(initParameter, ","); if (ArrayUtils.isEmpty(configures)) { throw new RuntimeException("配置Spring启动文件为空!"); } LOGGER.debug(LOADER_CONFIG_FILE + "配置" + ContextLoaderListenerConfigType.JOB_DEBUG.getType() + "设置为:" + jobDebug); // 校验配置文件是否存在 Object jobFileName = configureProps.get(ContextLoaderListenerConfigType.JOB_CONFIG_FILE.getType()); if (jobFileName == null) { throw new RuntimeException(LOADER_CONFIG_FILE + "配置" + ContextLoaderListenerConfigType.JOB_CONFIG_FILE.getType() + "设置为空!"); } if (!StringUtils.contains(webXmlConfigInitParameter, String.valueOf(jobFileName))) { throw new RuntimeException("web.xml无" + jobFileName + "配置信息!"); } if (StringUtils.equals(jobDebug, ContextLoaderListenerStatus.OFF.getStatus())) { LOGGER.debug(LOADER_CONFIG_FILE + "配置" + ContextLoaderListenerConfigType.JOB_DEBUG.getType() + "设置为:" + jobDebug + ", WMS不加载配置文件" + jobFileName); // 获取过滤之后的配置文件 ListfilterConfigs = Lists.newArrayList(); for (String configure : configures) { if (!StringUtils.contains(configure, String.valueOf(jobFileName))) { filterConfigs.add(configure); } } initParameter = Joiner.on(",").join(filterConfigs); } return initParameter; } /** * 启动过滤配置文件类型 */ protected enum ContextLoaderListenerConfigType { JOB_DEBUG("JOB.DEBUG"), JOB_CONFIG_FILE("JOB.CONFIG.FILE"); private String type; ContextLoaderListenerConfigType(String type) { this.type = type; } public String getType() { return type; } } /** * 开关状态值 */ protected enum ContextLoaderListenerStatus { ON("ON"), OFF("OFF"); private String status; ContextLoaderListenerStatus(String status) { this.status = status; } public String getStatus() { return status; } public static ContextLoaderListenerStatus getByStatus(String statusCode) { if (StringUtils.isEmpty(statusCode)) { return null; } for (ContextLoaderListenerStatus status : ContextLoaderListenerStatus.values()) { if (status.getStatus().equals(statusCode)) { return status; } } return null; } }}
3、配置文件中开关配置:
# 开启定时任务调试,ON:打开,OFF:关闭JOB.DEBUG=OFFJOB.CONFIG.FILE=wms-job.xml
四、系统启动加载结果
1、设置为OFF
2016-01-12 18:56:25.827 [main] INFO /-Initializing Spring root WebApplicationContext2016-01-12 18:56:25.869 [main] DEBUG com.oneplus.wms.mvc.OneplusContextLoaderListener-env-config.properties配置JOB.DEBUG设置为:OFF2016-01-12 18:56:25.869 [main] DEBUG com.oneplus.wms.mvc.OneplusContextLoaderListener-env-config.properties配置JOB.DEBUG设置为:OFF, WMS不加载配置文件wms-job.xml
2、设置为ON
2016-01-12 18:57:22.081 [main] INFO /-Initializing Spring root WebApplicationContext2016-01-12 18:57:22.125 [main] DEBUG com.oneplus.wms.mvc.OneplusContextLoaderListener-env-config.properties配置JOB.DEBUG设置为:ON...2016-01-12 19:00:00.105 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] DEBUG org.mybatis.spring.SqlSessionUtils-Creating a new SqlSession20