Mybatis [2.1]-ストリームの読み取りからSqlSessionの作成までに何が起こったのですか?

[目次]
pexels-pixabay-459225

使用sqlSessionする前、構成ファイルを取得し、InputStream入力ストリームを取得SqlSessionFactoryBuildersqlSessionFactoryオブジェクトを取得して取得する必要がありますsqlSession

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

1. Resources.getResourceAsStream( "mybatis.xml")は正確に何をしましたか?

1.まず、InputStream is = Resources.getResourceAsStream("mybatis.xml");この文が私たちのためにをしたかを見てみましょう。次の文は、別の内部メソッドが呼び出されていることを示しています。リソースは、グローバル構成のファイル名です。

public static InputStream getResourceAsStream(String resource) throws IOException {
    // 从这里字面意思是传一个空的类加载器进去,还有全局配置文件名,从方法名的意思就是
    // 将配置文件读取,转化成输入流
    return getResourceAsStream((ClassLoader)null, resource);
  }

2.フォローアップメソッドでClassLoaderWrapperは、クラスのインスタンスオブジェクトを呼び出すメソッドを知ることができますが、getResourceAsStream()これclassLoaderWrapperはどのようにし実現したのですか?これはResources.classメンバー属性ですが、これはClassLoaderWrapper何ですか?

ここResources.classではprivate static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();classLoaderWrapperオブジェクト作成するために使用します。
ClassLoaderWrapper実際、これはClassLoader(クラスローダー)ラッパークラスであり、内部制御を通じて複数のClassLoaderオブジェクトが1つdefaultClassLoader、1含まれsystemClassLoaderているため、正しいクラスローダーがシステムに返されて使用できるようになります。mybatisカスタマイズされたクラスローダーとして使用できます

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 {
      return in;
    }
  }

3.カプセル化されたメソッドを呼び出す次の内部メソッドが呼び出されていることがわかります。1つは現在のクラスローダーを取得するためのもので、もう1つは渡されたファイル名です。

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

4.getClassLoaders()このメソッドを見ると、クラスローダーの配列が初期化されており、デフォルトのクラスローダー、現在のスレッドのコンテキストクラスローダー、システムクラスローダーなど、多くのクラスローダーが存在することがわかります。

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

5.getResourceAsStream(String resource, ClassLoader[] classLoader)このメソッドを入力すると、すべてのクラスローダーをトラバースし、クラスローダーを使用してInputStreamオブジェクトをロードし、クラスローダーを渡さない場合、最初の適切なクラスローダーが選択されていることがわかります。次に、最初の自己定義クラスローダーがnullになり、2番目のデフォルトクラスローダーがデフォルトで選択されます。ファイル名の前に「/」が付いていない場合、空のオブジェクトが取得されると、自動的に選択されます。 " /"に再度アクセスを追加しました

 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) {
          return returnValue;
        }
      }
    }
    return null;
  }

6.クラスローダーのコードを入力してリソースファイルをロードします。最初にフルパスが取得されurl、次にopenStream()を呼び出します

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

6.1。getResource(name)このメソッドに従うと、親がすでにローダーである場合parentgetResource()メソッドを呼び出しいることがわかります。次にgetBootstrapResource(name)Getを使用し、空の場合はgetを使用してから、取得メソッドに従いますgetBootstrapResource(name)

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;
    }

6.1.1フォローアップしましょうgetBootstrapResource(name);

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

6.1.1.1getBootstrapClassPath()インポートされたパッケージを呼び出し、クラスローダーのロードパスを読み取るこのメソッドが表示されます。このメソッドはここで終了し、これ以上戻ることはできません:)。

static URLClassPath getBootstrapClassPath() {
        return sun.misc.Launcher.getBootstrapClassPath();
    }

6.1.1.2ucp.getResource(name)このメソッドを見ると、このメソッドが呼び出されていることがわかります。このメソッドは主にキャッシュを検索し、トラバースして取得する最初の修飾ローダーを検索しますresource。これまでのところ、これ以上の詳細は説明しません。 、前のレベルを振り返ってみる必要があります。

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) {
        return var6;
      }
    }

    return null;
  }

getBootstrapResource(name)これは主にurl(ファイルリソースのパス)であることがわかっており、それを使用しurl.openStream()てストリームを取得します。

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

抽象メソッドを呼び出し、URLConnection(URL接続オブジェクト)を取得するopenConnection()メソッドを見てみましょう。

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

getInputStream()メソッドをもう一度見ると、これがインターフェイスメソッドであることがわかります。FileURLConnectionのこのメソッドは、ファイルURLを処理するためのシングルスレッドのinputstreamメソッドです。

  public synchronized InputStream getInputStream() 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;
  }

この時点で、入力ストリームを取得するプロセス全体が終了しました。戻り値が上位層に返される限り、この構成ファイルに必要な入力ストリームを取得できます。

2.新しいSqlSessionFactoryBuilder()。build(is)の動作原理

まず、SqlSessionFactoryBuilderのパラメーターなしの構築メソッドには操作がありません。

public SqlSessionFactoryBuilder() {
  }

次にbuild(is)、カプセル化メソッドを呼び出すこのメソッドを見てみましょう。1つは入力ストリーム、1つは文字列、もう1つは属性オブジェクトです。

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

続いて、xml構成コンストラクターであるxmlconfigbuilderがxml構成オブジェクトをインスタンス化するために使用されていることがわかります。これは、別のbuild(と呼ばれるmybatis.xmlに対応する構成オブジェクトコンストラクターであると考えられます。 ) 方法:

  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;
  }

呼び出された別のビルドメソッドを見ることができます。これは、構成オブジェクトを使用してDefaultSqlSessionFactoryオブジェクトを構築し、そのオブジェクトにこのオブジェクトを返すことです。これがsqlsessionFactoryです。

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

3. sqlSessionFactory.openSession()を使用してsqlSessionを取得します

これは実際にsqlSessionFactoryはインターフェイスであり、その実装クラスはDefaultSqlSessionFactoryであることがわかります。メソッドは次のとおりです。

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

openSessionFromDataSource()このメソッドを確認します。名前から、Sqlsessionがデータソースからロードされていることが大まかにわかります。データソースは、アクチュエータタイプ、トランザクション分離レベル、および自動的に送信するかどうかを指定できます。設定されていない場合、デフォルトはnullおよびfalseです。主な方法は、設定ファイルオブジェクトの環境を取り出してトランザクションファクトリを構築したり、エグゼキュータを設定したりして、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;
  }

これまでのところ、sqlsessionオブジェクトは構成ファイルに基づいて作成されています。

この記事は、私自身(新人)の研究蓄積記録または研究ノートのみを表しています。侵害がある場合は、著者に連絡して削除してください。完璧な人はいないので、記事も未熟で、次の文章が苦手です。スプレーしないでください。間違いがあった場合は、指摘したいと思います。感謝しています〜

技術への道は一度ではなく、山は高く、川は長く、遅くても止まりません。
公開番号:秦淮食料品店

おすすめ

転載: blog.51cto.com/13604316/2668461