这是一个隐形的坑。
先贴出项目中一个listerner源代码,仔细观察:
public class SystemConfigInitListener implements ServletContextListener{ @Override public void contextInitialized(ServletContextEvent sce) { String prefix = sce.getServletContext().getRealPath("/"); String file = sce.getServletContext().getInitParameter("systemConfigLocation"); Properties props = new Properties(); InputStream is = null; try { if (file.startsWith("classpath:")) { is = SystemConfigInitListener.class.getClassLoader().getResourceAsStream(file.substring(10)); } else { String filePath = prefix + file; is = new FileInputStream(filePath); } props.load(is); for(Enumeration<Object> it = props.keys(); it.hasMoreElements();){ String key = (String)it.nextElement(); System.setProperty(key, props.getProperty(key)); sce.getServletContext().setAttribute(key, props.getProperty(key)); } } catch (Exception e) { }finally{ if(is != null){ try{ is.close(); }catch(Exception e){} } } file = sce.getServletContext().getInitParameter("systemConfigLocationOverride"); Properties props2 = new Properties(); InputStream is2 = null; try { if (file.startsWith("file:")) { is2 = new FileInputStream(file.substring(5).replaceAll("\\$\\{user.home\\}", System.getProperty("user.home"))); } else { String filePath = prefix + file; is2 = new FileInputStream(filePath); } props2.load(is2); for(Enumeration<Object> it = props2.keys(); it.hasMoreElements();){ String key = (String)it.nextElement(); System.setProperty(key, props2.getProperty(key)); sce.getServletContext().setAttribute(key, props2.getProperty(key)); } } catch (Exception e) { }finally{ if(is != null){ try{ is2.close(); }catch(Exception e){} } } } @Override public void contextDestroyed(ServletContextEvent sce) { // TODO Auto-generated method stub } }
这段代码在线上,测试服务器上运行是没有问题的,在苹果电脑上运行也是没有问题的,在windows电脑上运行表面上看起来也是没有问题的,其实是又问题的,因为异常被吃掉了,没有打印出来,被你忽略掉了。
web.xml中有这样一个配置:
<context-param> <param-name>systemConfigLocationOverride</param-name> <param-value>file:${user.home}/config/sigma-release.properties</param-value> </context-param>
该配置的作用就是listerner代码在服务启动初始化的时候,将config目录下的配置项替换为真正的配置。
服务器上的config目录: /home/www/config 没有问题
假如你的config目录是这个 C:\\Users\\用户名\\config 恭喜你,你踩到坑了
因为listerner的下面这行代码会报错,但是错误信息又被吃掉,你没有及时发现,导致在本地测试的时候,没有达到你期望的效果。
如果我们在异常中加上打印信息,例如e.printStackTrace();
会报下面的错误信息的:
导致上面异常的真正原因是下面这行代码:
is2 = new FileInputStream(file.substring(5).replaceAll("\\$\\{user.home\\}", System.getProperty("user.home")));
这行代码在linux平台,苹果电脑上运行是没有问题的。
但是如果你是windows,而你的config目录又是C:
\\Users\\用户名\\config,可以通过下面这行代码打印出来
String userhomePath = System.getProperty("user.home"); System.out.println("===userhomePath===" +userhomePath);
我本地打印的是c:,我早就修改成了
根目录,所以不会有任何问题。而不是c:/xxx/xxx/xxx很深的目录,(修改参考:http://cfyme.iteye.com/blog/2209012)
解决方案1:将斜杠替换掉,replaceAll("\\\\", "/")));
例如:
is2 = new FileInputStream(file.substring(5).replaceAll("\\$\\{user.home\\}", System.getProperty("user.home").replaceAll("\\\\", "/")));
解决方案2:直接将user.home目录设置成根目录,设置方法参考:http://cfyme.iteye.com/blog/2209012
总结:1,异常不要被吃掉,不然遇到一些问题难以发现。
2,环境配置项的问题最后在系统启动初始化的时候全部加载打印到日志文件中,方便查看是否我们真正所期望的值。