mabatis配置文件加载过程

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命令行调试就可成功。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值