mabatis配置文件加载过程

来源:互联网 发布:上海停车软件 编辑:程序博客网 时间:2024/06/05 09:29

mabatis配置文件加载过程

第一次写尝试用markdown写个人博客,万事开头难,后期针对某一主题反复迭代吃透

程序运行过程

程序结构

测试类

    @Test    public void test08() throws IOException{/*      Logger logger=Logger.getLogger(Mytest.class);                logger.fatal("fatal msg");                logger.error("error msg");*/     List<Student> students=dao.selectStudentsByName("张");     for (Student student:students)     {            System.out.println(student);      }    }

Dao层实现

@Override    public List<Student> selectStudentsByName(String name) {        // TODO Auto-generated method stub        List<Student> students=null;        try {            sqlSession=MyBatisUtils.getSqlSession();            students=sqlSession.selectList("selectStudentsByName", name);        }   finally{            if(sqlSession!=null){                    sqlSession.close();                                    }                }           return students;    }

MyBatisUtils类

public class MyBatisUtils {    private static SqlSessionFactory sqlSesssionFactory;    public static SqlSession getSqlSession(){        try {            InputStream is = Resources.getResourceAsStream("mybatis.xml");             if (sqlSesssionFactory==null) {                sqlSesssionFactory = new SqlSessionFactoryBuilder().build(is);            }            /* dirty*/            return sqlSesssionFactory.openSession();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return null;    }

重点分析getResourceAsStream(“mybatis.xml”)是如何获取文件完整路径

整个读取过程围绕org.apache.ibatis.io.Resources整个类展开

InputStream is = Resources.getResourceAsStream("mybatis.xml");

进一步调用org.apache.ibatis.io.Resources.getResourceAsStream(String resource)

  public static InputStream getResourceAsStream(String resource) throws IOException {    return getResourceAsStream(null, resource);  }
  public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {//由上可知此处loader为null    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);    if (in == null) {      throw new IOException("Could not find resource " + resource);    }    return in;  }

此处classLoaderWrapper为Resources类的静态成员变量,类型为ClassLoaderWrapper

public class Resources {  private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();    }

跟踪ClassLoaderWrapper.getResourceAsStream(resource, loader),记住此处loader仍然为null

 public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {    return getResourceAsStream(resource, getClassLoaders(classLoader));  }

getClassLoaders(classLoader)应该就是通过获取类加载路径,得到根路径classpath ;
getClassLoaders(classLoader)返回ClassLoader[]数组
classLoader为null
defaultClassLoader在此过程中没有初始化也为null
Thread.currentThread().getContextClassLoader().getResource(“”)得到当前的classpath的绝对路径

  ClassLoader[] getClassLoaders(ClassLoader classLoader) {    return new ClassLoader[]{        classLoader,        defaultClassLoader,        Thread.currentThread().getContextClassLoader(),        getClass().getClassLoader(),        systemClassLoader};  }

跟踪进入ClassLoaderWrapper.getResourceAsStream
至此cl.getResourceAsStream(resource);中resource仍然为文件名,此函数执行完毕则会结合构建路径返回文件输入流InputStream returnValue ;
也就是说绝对路径的合成是在cl.getResourceAsStream(resource)中完成

  InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {    for (ClassLoader cl : classLoader) {      if (null != cl) {        // try to find the resource as passed        InputStream returnValue = cl.getResourceAsStream(resource);        // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource        if (null == returnValue) {          returnValue = cl.getResourceAsStream("/" + resource);        }        if (null != returnValue) {          return returnValue;        }      }    }    return null;  }

此处有一个疑惑为什么会进入URLClassLoader类 java.net.URLClassLoader.getResourceAsStream(String name);应该是根据cl(ClassLoader )类型得到。

    public InputStream getResourceAsStream(String name) {        URL url = getResource(name);        try {            if (url == null) {                return null;            }            URLConnection urlc = url.openConnection();            InputStream is = urlc.getInputStream();            if (urlc instanceof JarURLConnection) {                JarURLConnection juc = (JarURLConnection)urlc;                JarFile jar = juc.getJarFile();                synchronized (closeables) {                    if (!closeables.containsKey(jar)) {                        closeables.put(jar, null);                    }                }            } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {                synchronized (closeables) {                    closeables.put(is, null);                }            }            return is;        } catch (IOException e) {            return null;        }    }

此处parent 为ClassLoader类定义的 private final ClassLoader parent;
class.getResource(“/”) == class.getClassLoader().getResource(“”)
其实,Class.getResource和ClassLoader.getResource本质上是一样的,都是使用ClassLoader.getResource加载资源的。
参考以下文章
Class.getResource和ClassLoader.getResource的区别分析

    public URL getResource(String name) {        URL url;        if (parent != null) {            url = parent.getResource(name);        } else {            url = getBootstrapResource(name);        }        if (url == null) {            url = findResource(name);//最后由此行获得底层路径        }        return url;    }

此处需要进一步研究:为什么经由 url = findResource(name)?

紧接跟进ucp.findResource(name, true),此处ucp(The search path for classes and resources)为URLClassLoader成员变量private final URLClassPath ucp;

    public URL findResource(final String name) {        /*         * The same restriction to finding classes applies to resources         */        URL url = AccessController.doPrivileged(            new PrivilegedAction<URL>() {                public URL run() {                    return ucp.findResource(name, true);// 跟踪                }            }, acc);        return url != null ? ucp.checkURL(url) : null;    }

重点关注:public class URLClassPath

    public URL findResource(String name, boolean check) {        Loader loader;        for (int i = 0; (loader = getLoader(i)) != null; i++) {  //跟踪            URL url = loader.findResource(name, check);            if (url != null) {                return url;            }        }        return null;    }
    public Enumeration<URL> findResources(final String name,                                     final boolean check) {        return new Enumeration<URL>() {            private int index = 0;            private URL url = null;            private boolean next() {                if (url != null) {                    return true;                } else {                    Loader loader;                    while ((loader = getLoader(index++)) != null) {                        url = loader.findResource(name, check);                        if (url != null) {                            return true;                        }                    }                    return false;                }            }            public boolean hasMoreElements() {                return next();            }            public URL nextElement() {                if (!next()) {                    throw new NoSuchElementException();                }                URL u = url;                url = null;                return u;            }        };    }
     private synchronized Loader getLoader(int index) {        if (closed) {            return null;        }         // Expand URL search path until the request can be satisfied         // or the URL stack is empty.        while (loaders.size() < index + 1) {            // Pop the next URL from the URL stack            URL url;            synchronized (urls) {                if (urls.empty()) {                    return null;                } else {                    url = urls.pop();                }            }            // Skip this URL if it already has a Loader. (Loader            // may be null in the case where URL has not been opened            // but is referenced by a JAR index.)            String urlNoFragString = URLUtil.urlNoFragString(url);            if (lmap.containsKey(urlNoFragString)) {                continue;            }            // Otherwise, create a new Loader for the URL.            Loader loader;            try {                loader = getLoader(url);                // If the loader defines a local class path then add the                // URLs to the list of URLs to be opened.                URL[] urls = loader.getClassPath();                if (urls != null) {                    push(urls);                }            } catch (IOException e) {                // Silently ignore for now...                continue;            }            // Finally, add the Loader to the search path.            loaders.add(loader);            lmap.put(urlNoFragString, loader);        }        return loaders.get(index);    }
 URL url =  getClass().getClassLoader().getResource("mybatis.xml");     System.out.println(url);

mabaits文件加载过程首先获取绝对路径,

关于Class.getResource和ClassLoader.getResource的路径问题参考

总结

JAVA获取classpath路径:
ClassLoader 提供了两个方法用于从装载的类路径中取得资源:

public URL  getResource (String name);          public InputStream  getResourceAsStream (String name);  

这里name是资源的类路径,它是相对与“/”根路径下的位置。getResource得到的是一个URL对象来定位资源,而getResourceAsStream取得该资源输入流的引用保证程序可以从正确的位置抽取数据。但是**

真正使用的不是ClassLoader的这两个方法,而是Class的 getResource和getResourceAsStream方法

**,因为Class对象可以从你的类得到(如YourClass.class或 YourClass.getClass()),而ClassLoader则需要再调用一次YourClass.getClassLoader()方法,不过根据JDK文档的说法,

Class对象的这两个方法其实是“委托”(delegate)给装载它的ClassLoader来做的,所以只需要使用
Class对象的这两个方法就可以了。 因此,直接调用this.getClass().getResourceAsStream(String
name);获取流,静态化方法中则使用ClassLoader.getSystemResourceAsStream (String name) ; 。

下面是一些得到classpath和当前类的绝对路径的一些方法。你可能需要使用其中的一些方法来得到你需要的资源的绝对路径。

1.this.getClass().getResource(”“)
得到的是当前类class文件的URI目录。不包括自己!
如:file:/D:/workspace/jbpmtest3/bin/com/test/

2.this.getClass().getResource(”/”) ====this.getClass() .getClassLoader().getResource(”“)
得到的是当前的classpath的绝对URI路径
如:file:/D:/workspace/jbpmtest3/bin/
???可否理解为包外,待进一步研究

3.this.getClass() .getClassLoader().getResource(”“)
得到的也是当前ClassPath的绝对URI路径 。
如:file:/D:/workspace/jbpmtest3/bin/

4.ClassLoader.getSystemResource(”“)
得到的也是当前ClassPath的绝对URI路径 。
如:file:/D:/workspace/jbpmtest3/bin/

5.Thread.currentThread().getContextClassLoader ().getResource(”“)
得到的也是当前ClassPath的绝对URI路径 。
如:file:/D:/workspace/jbpmtest3/bin/

6.ServletActionContext.getServletContext().getRealPath(“/”)
Web应用程序 中,得到Web应用程序的根目录的绝对路径。这样,我们只需要提供相对于Web应用程序根目录的路径,就可以构建出定位资源的绝对路径。
如:file:/D:/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/WebProject

注意点:

1.尽量不要使用相对于System.getProperty(”user.dir”)当前用户目录的相对路径。这是一颗定时炸 弹,随时可能要你的命。

2.

尽量使用URI形式的绝对路径资源。

它可以很容易的转变为URI,URL,File对象。

3.尽量使用相对classpath的相对路径。不要使用绝对路径。使用上面ClassLoaderUtil类的public static URL getExtendResource(String relativePath)方法已经能够使用相对于classpath的相对路径定位所有位置的资源。

4.

绝对不要使用硬编码的绝对路径。

因为,我们完全可以使用ClassLoader类的getResource(”“)方法得到当前classpath的绝对路径。如果你一定要指定一个绝对路径,那么使用配置文件,也比硬编码要好得多!

获得CLASSPATH之外路径的方法:
URL base = this.getClass().getResource(”“); //先获得本类的所在位置,如/home/popeye/testjava/build/classes/net/
String path = new File(base.getFile(), “……/……/……/”+name).getCanonicalPath(); //就可以得到/home/popeye/testjava/name

另外,如果从ANT启动程序,this.getClass().getResource(“”)取出来的比较怪,直接用JAVA命令行调试就可成功。

原创粉丝点击