spring+mybatis无网启动时,java.net.UnknownHostException: mybatis.org 异常

spring+mybatis无网启动报错

提示加载不到xsd或dtd文件

    项目改造时,遇到了项目在无外网环境下无法启动的问题。启动时抛出java.net.UnknownHostException: mybatis.org 异常。

原因是spring在加载mybatis-config.xml 文件时,无法找到
mybatis-3-config.dtd 这个文件。一般遇到这种项目加载不到本地dtd或xsd文件时,只要检查引入的jar包版本是否与xml文件中声明的dtd或xsd文件是否相匹配即可。
于是,我检查了一下引入的mybatis版本3.2.3,xml文件中声明的是mybatis-3-config.dtd,jar包中是存在的。这就有点困惑了,那就看一下spring是怎么加载dtd文件的吧。
这个文件在


mybatis配置文件.png



    
    
       ······
    
    
       ·······
    

  1. spring加载dtd文件
    spring 使用 org.springframework.beans.factory.xml.BeansDtdResolver这个类来加载dtd文件,这个文件的注释是这么写的:
/**
 * EntityResolver implementation for the Spring beans DTD,
 * to load the DTD from the Spring class path (or JAR file).
 *
 * 

Fetches "spring-beans-2.0.dtd" from the class path resource * "/org/springframework/beans/factory/xml/spring-beans-2.0.dtd", * no matter whether specified as some local URL that includes "spring-beans" * in the DTD name or as "http://www.springframework.org/dtd/spring-beans-2.0.dtd". * * @author Juergen Hoeller * @author Colin Sampaleanu * @since 04.06.2003 * @see ResourceEntityResolver */ public class BeansDtdResolver implements EntityResolver { private static final String DTD_EXTENSION = ".dtd"; private static final String DTD_FILENAME = "spring-beans-2.0"; private static final String DTD_NAME = "spring-beans"; private static final Log logger = LogFactory.getLog(BeansDtdResolver.class); @Override public InputSource resolveEntity(String publicId, String systemId) throws IOException { if (logger.isTraceEnabled()) { logger.trace("Trying to resolve XML entity with public ID [" + publicId + "] and system ID [" + systemId + "]"); } if (systemId != null && systemId.endsWith(DTD_EXTENSION)) { int lastPathSeparator = systemId.lastIndexOf("/"); //看这里,该类只加载以spring-beans开头的dtd文件 int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator); if (dtdNameStart != -1) { String dtdFile = DTD_FILENAME + DTD_EXTENSION; if (logger.isTraceEnabled()) { logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath"); } try { Resource resource = new ClassPathResource(dtdFile, getClass()); InputSource source = new InputSource(resource.getInputStream()); source.setPublicId(publicId); source.setSystemId(systemId); if (logger.isDebugEnabled()) { logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile); } return source; } catch (IOException ex) { if (logger.isDebugEnabled()) { logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex); } } } } // Use the default behavior -> download from website or wherever. return null; } @Override public String toString() { return "EntityResolver for spring-beans DTD"; } }

这个类很简单,只有一个resolveEntity方法。我们看注释和源码知道这个方法只加载spring-beans开头的dtd文件,所以mybatis-3-config.dtd文件当然不会从本地加载。

看到这里,我们就知道了mybatis-config.xml这个文件不应该交给spring来解析,应该由mybatis自己解析。所以我们修改一下项目配置,在classpath下单独给mybatis-config.xml 建一个目录,配置spring 只解析config目录下的xml文件
配置修改.png

给mybatis的SqlSessionFactoryBean配置新的mybatis-config.xml文件地址。


        
        
        
    

mybatis有自己的xml解析器


mybatis-xml解析器.png

这个类也非常简单,也是只实现了EntityResolver接口。有兴趣可以看一下。
改完,断网启动,没有问题。齐活,溜。


/*
 * Offline entity resolver for the iBATIS DTDs
 */
public class XMLMapperEntityResolver implements EntityResolver {

  private static final Map doctypeMap = new HashMap();

  private static final String IBATIS_CONFIG_DOCTYPE = "-//ibatis.apache.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH);
  private static final String IBATIS_CONFIG_URL = "http://ibatis.apache.org/dtd/ibatis-3-config.dtd".toUpperCase(Locale.ENGLISH);

  private static final String IBATIS_MAPPER_DOCTYPE = "-//ibatis.apache.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH);
  private static final String IBATIS_MAPPER_URL = "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH);

  private static final String MYBATIS_CONFIG_DOCTYPE = "-//mybatis.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH);
  private static final String MYBATIS_CONFIG_URL = "http://mybatis.org/dtd/mybatis-3-config.dtd".toUpperCase(Locale.ENGLISH);

  private static final String MYBATIS_MAPPER_DOCTYPE = "-//mybatis.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH);
  private static final String MYBATIS_MAPPER_URL = "http://mybatis.org/dtd/mybatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH);

  private static final String IBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
  private static final String IBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";

  static {
    doctypeMap.put(IBATIS_CONFIG_URL, IBATIS_CONFIG_DTD);
    doctypeMap.put(IBATIS_CONFIG_DOCTYPE, IBATIS_CONFIG_DTD);

    doctypeMap.put(IBATIS_MAPPER_URL, IBATIS_MAPPER_DTD);
    doctypeMap.put(IBATIS_MAPPER_DOCTYPE, IBATIS_MAPPER_DTD);

    doctypeMap.put(MYBATIS_CONFIG_URL, IBATIS_CONFIG_DTD);
    doctypeMap.put(MYBATIS_CONFIG_DOCTYPE, IBATIS_CONFIG_DTD);

    doctypeMap.put(MYBATIS_MAPPER_URL, IBATIS_MAPPER_DTD);
    doctypeMap.put(MYBATIS_MAPPER_DOCTYPE, IBATIS_MAPPER_DTD);
  }

  /*
   * Converts a public DTD into a local one
   *
   * @param publicId Unused but required by EntityResolver interface
   * @param systemId The DTD that is being requested
   * @return The InputSource for the DTD
   * @throws org.xml.sax.SAXException If anything goes wrong
   */
  public InputSource resolveEntity(String publicId, String systemId)
      throws SAXException {

    if (publicId != null) publicId = publicId.toUpperCase(Locale.ENGLISH);
    if (systemId != null) systemId = systemId.toUpperCase(Locale.ENGLISH);

    InputSource source = null;
    try {
      String path = doctypeMap.get(publicId);
      source = getInputSource(path, source);
      if (source == null) {
        path = doctypeMap.get(systemId);
        source = getInputSource(path, source);
      }
    } catch (Exception e) {
      throw new SAXException(e.toString());
    }
    return source;
  }

  private InputSource getInputSource(String path, InputSource source) {
    if (path != null) {
      InputStream in;
      try {
        in = Resources.getResourceAsStream(path);
        source = new InputSource(in);
      } catch (IOException e) {
        // ignore, null is ok
      }
    }
    return source;
  }

}

你可能感兴趣的:(spring+mybatis无网启动时,java.net.UnknownHostException: mybatis.org 异常)