Before we use sqlSession, we need to get the configuration file, get the InputStream InputStream, and get the sqlSessionFactory object through SqlSessionFactoryBuilder to get the sqlSession.

InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
Copy the code

1. Resources. GetResourceAsStream (” mybatis. XML “) what did?

1. First let’s look at an InputStream is = Resources. GetResourceAsStream (” mybatis. XML “); Call (‘ resource ‘, ‘resource’, ‘global’);

public static InputStream getResourceAsStream(String resource) throws IOException {
    // Pass an empty class loader into the global configuration file
    // Read the configuration file and convert it to an input stream
    return getResourceAsStream((ClassLoader)null, resource);
  }
Copy the code

The getResourceAsStream() method calls an instance of the ClassLoaderWrapper class. How did the ClassLoaderWrapper come from? This is a member property of Resources.class, so what is this ClassLoaderWrapper thing?

In resources.class we just use private static ClassLoaderWrapper ClassLoaderWrapper = new ClassLoaderWrapper(); Create a classLoaderWrapper object. ClassLoaderWrapper is a wrapper for ClassLoader that contains several ClassLoader objects, one for defaultClassLoader and one for systemClassLoader. You can ensure that the correct class loader is returned to the system for use. We can think of mybatis as a custom class loader.

public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
    if (in == null) {
      throw new IOException("Could not find resource " + resource);
    } else {
      returnin; }}Copy the code

3. We can see that the following internal method is called, which calls the wrapped method, one is to get the current class loader, and the other is to pass the file name:

  public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    return this.getResourceAsStream(resource, this.getClassLoaders(classLoader));
  }
Copy the code

GetClassLoaders () initializes an array of class loaders, including the default class loaders, the current thread’s context class loaders, the system class loaders, and so on.

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

GetResourceAsStream (String Resource, ClassLoader[] ClassLoader) ¶ We can know it is the first choice for the class loader, if we do not pass the class loader, so the first define your own class loader is null, then it will be the default choice of the second the default class loader, and we can know if there is no add “/” in front of the file name, access to an empty object, automatically add “/” to visit it again:

 InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    ClassLoader[] arr$ = classLoader;
    int len$ = classLoader.length;
    for(int i$ = 0; i$ < len$; ++i$) {
      ClassLoader cl = arr$[i$];
      if (null! = cl) { InputStream returnValue = cl.getResourceAsStream(resource);if (null == returnValue) {
          returnValue = cl.getResourceAsStream("/" + resource);
        }
        if (null! = returnValue) {returnreturnValue; }}}return null;
  }
Copy the code

OpenStream () = openStream(); openStream() = openStream();

public InputStream getResourceAsStream(String name) {
    URL url = getResource(name);
    try {
        returnurl ! =null ? url.openStream() : null;
    } catch (IOException e) {
        return null; }}Copy the code

GetResource (name) = getResource(); getBootstrapResource(name) = getResource(name); Get it from the getBootstrapResource(name) method.

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;
    }
Copy the code

GetBootstrapResource (name);

private static URL getBootstrapResource(String name) {
        URLClassPath ucp = getBootstrapClassPath();
        Resource res = ucp.getResource(name);
        returnres ! =null ? res.getURL() : null;
    }
Copy the code

6.1.1.1 we see getBootstrapClassPath(), which calls the imported package and reads the path of the class loader. This method stops here, and there is no going back further :).

static URLClassPath getBootstrapClassPath(a) {
        return sun.misc.Launcher.getBootstrapClassPath();
    }
Copy the code

6.1.1.2 Ucp.getResource (name) = ucp.getResource(name) = ucp.getResource(name)

public Resource getResource(String var1, boolean var2) {
    if (DEBUG) {
      System.err.println("URLClassPath.getResource(\"" + var1 + "\")");
    }

    int[] var4 = this.getLookupCache(var1);

    URLClassPath.Loader var3;
    for(int var5 = 0; (var3 = this.getNextLoader(var4, var5)) ! =null; ++var5) {
      Resource var6 = var3.getResource(var1, var2);
      if(var6 ! =null) {
        returnvar6; }}return null;
  }
Copy the code

GetBootstrapResource (name) contains the url (the path of the file resource) and uses url.openstream () to fetch the stream:

public final InputStream openStream(a) throws java.io.IOException {
        return openConnection().getInputStream();
    }
Copy the code

Let’s look at the openConnection() method, which calls an abstract method and gets an URLConnection:

public URLConnection openConnection(a) throws java.io.IOException {
        return handler.openConnection(this);
    }
Copy the code

Looking at the getInputStream() method, we can see that this is an interface method, and we find the FileURLConnection method, which is a single-threaded inputStream for file urls:

  public synchronized InputStream getInputStream(a) throws IOException {
    this.connect();
    if (this.is == null) {
      if (!this.isDirectory) {
        throw new FileNotFoundException(this.filename);
      }
      FileNameMap var3 = java.net.URLConnection.getFileNameMap();
      StringBuffer var4 = new StringBuffer();
      if (this.files == null) {
        throw new FileNotFoundException(this.filename);
      }
      Collections.sort(this.files, Collator.getInstance());
      for(int var5 = 0; var5 < this.files.size(); ++var5) {
        String var6 = (String)this.files.get(var5);
        var4.append(var6);
        var4.append("\n");
      }
      this.is = new ByteArrayInputStream(var4.toString().getBytes());
    }
    return this.is;
  }
Copy the code

At this point, the entire process of getting the InputStream is complete, and you can simply return the value one level up to get the InputStream required by the configuration file.

2. New SqlSessionFactoryBuilder().build(is

First, the parameterless constructor of the SqlSessionFactoryBuilder does nothing:

public SqlSessionFactoryBuilder() {
  }
Copy the code

The build(is) method calls an inputStream, a string, and a property object:

public SqlSessionFactory build(InputStream inputStream) {
    return this.build((InputStream)inputStream, (String)null, (Properties)null);
  }
Copy the code

Following through, we can see that xmlConfigBuilder, the XML configuration constructor, is used to instantiate an XML configuration object. As you can imagine, mybatis. XML’s corresponding configuration object constructor calls another build() method inside:

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      var5 = this.build(parser.parse());
    } catch (Exception var14) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    } finally {
      ErrorContext.instance().reset();

      try {
        inputStream.close();
      } catch(IOException var13) { ; }}return var5;
  }
Copy the code

We can see the other build method called, which uses the configuration object to build a DefaultSqlSessionFactory object and returns this object above, our sqlsessionFactory.

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
Copy the code

3. SqlSessionFactory. OpenSession sqlSession ()

DefaultSqlSessionFactory (sqlSessionFactory);

  public SqlSession openSession(a) {
    return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null.false);
  }
Copy the code

We see openSessionFromDataSource () this method, the name can probably know loading Sqlsession from data source, it can specify the type of actuator, isolation level, and whether submitted automatically, if not set, the default is null and false, The main thing to do in the method is to take out the environment of the configuration file object to construct the transaction factory, configure the executor, etc., and return an instance of DefaultSqlSession.

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    DefaultSqlSession var8;
    try {
      Environment environment = this.configuration.getEnvironment();
      TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      Executor executor = this.configuration.newExecutor(tx, execType);
      var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
    } catch (Exception var12) {
      this.closeTransaction(tx);
      throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
    } finally {
      ErrorContext.instance().reset();
    }
    return var8;
  }
Copy the code

At this point, a SQLSession object is created from the configuration file.

This article only represents their own (this rookie) learning accumulation record, or learning notes, if there is infringement, please contact the author to delete. No one is perfect, the article is the same, the writing style is immature, I am not talented, do not spray, if there is a mistake, also hope to point out, grateful ~

The road of technology is not at that time, the mountain is high and the water is long, even if it is slow, and not stop. Public account: Qinhuai Grocery store