日々常々

ふつうのプログラマがあたりまえにしたいこと。

Javaで「ライブラリの最新版がある」と言うときの基礎知識

Log4j 2のバージョンアップのやりかた で "「Mavenリポジトリ」の指すもの" を軽く書きましたが、いい機会なのでもう少し書いておきます。

最新版は使える?

https://twitter.com/irof/status/1469139048954724354

こういうツイートをしまして。 見てる順番は Log4j 2のトップページMvnRepositoryのlog4j-coreGitHubのLog4j 2のタグ一覧Central Repositoryのlog4j-apiディレクトリです。

ツイートの状態から「Log4j 2はリリース成功してからタグ作るで運用してるんだなぁ」とか、リリース成功したら自動でタグ作ってるわけでもないのかなぁとか思いました。私はタグをトリガーにリリースのパイプライン動かすのが好きです。リリース失敗したら消したくなるけど。

基本的に「最新版が使える」は「公開されているMavenリポジトリから取得できる」であり、狭義では「Central Repositoryに公開されている」を指します。 ツイートの4枚目で 2.15.0 の存在を確認できているので「最新版が使える」状態でした。

現代ではMavenやGradleのようなビルドツールを使わないことは考えづらく、jarを手動でダウンロードすることはほとんどありません。 あるとしても一部のAntでのビルドを保守している文脈か、ライセンス等の問題でCentral Repositoryなどで公開できない一部のライブラリを使用する場合です。

たとえば Log4j 2サイトのダウンロードページから最新版のjarがダウンロードできたとしても、それを使用するようにビルドツールを設定してあげる必要があります。 最近ではほとんど用途のないlibディレクトリに配置してのパス指定や、後述のインハウスリポジトリへの一時的な登録などになります。これらをしなければ「自分の手元ではビルドできてもCIではビルドできない」となったりして、前時代的だし、どちらも面倒。やらずに済むならやりたくないのが今日この頃です。やらずに済んでよかった。

インデックスサイト

リポジトリの階層をたどるのは面倒なので、 https://central.sonatype.comhttps://search.maven.org から変わった) や https://mavenrepository.com のようなMavenリポジトリの検索を助けてくれるサービスを使用することが多いでしょう。Googleとかで検索してもこれらが先に出てくるはずです。

私はインデックスサイトとか呼んでますが、共通の呼び名は知りません。インデックスサイトはそれぞれのサイト次第であり、別に mvn コマンドが使用する最新のリポジトリの状態を示すものではありません。

ここになくても、使えるものは使えます。検索を助けてくれるだけ。

Mavenリポジトリ

mvn コマンドはMavenリポジトリを使用します。 Mavenリポジトリはローカルリポジトリとリモートリポジトリに分けられますが、基本的にリモートリポジトリが原本、ローカルはキャッシュくらいの感覚でOKです。

mvn install とか叩くとローカルリポジトリに登録されますが、使えるのは自分だけです。リモートリポジトリへの登録は mvn deploy とかですが、サーバーのURLとか認証情報とかが必要になってきます。

リポジトリの場所は ~/.m2/settings.xml とか pom.xml とかコマンド実行時の引数とかで設定できますが、何も設定しなければローカルは ~/.m2/repository で、リモートリポジトリは https://repo.maven.apache.org/maven2/ です。

プロジェクトで使ってるリモートリポジトリがわからなかったら、存在しないライブラリ落とそうとしたらエラーログに出てきたりします。

修飾なしで「Mavenリポジトリ」と言うと、基本的にはCentral Repositoryを指すと思って大丈夫です。 他は「SpringのMavenリポジトリ」のように修飾(「Springの」)をつけて呼ぶはずです。Central Repository以外のリポジトリを使用する動機は、そのリポジトリでしか公開されていないものを使用したい場合で、多くはSNAPSHOTやMilestoneなリリースを使いたい場合になります。他は作者が何かしらの理由によりCentral Repositoryで公開していない場合でしょう。(「めんどくさい」って理由で上げないことも多いと思います。)

ライブラリごとのリポジトリの場所

たとえばLog4j 2のリリースリポジトリhttps://repository.apache.org/service/local/staging/deploy/maven2 で、SNAPSHOTリポジトリhttps://repository.apache.org/content/repositories/snapshots のようです。 なのでSNAPSHOTはSNAPSHOTリポジトリorg/apache/logging/log4j/log4j-core にあります。

これはLog4j 2のpom.xml を読めばわかることです。 org.apache.logging.log4j:log4j-core -> org.apache.logging.log4j:log4j -> org.apache.logging:logging-parent -> org.apache:apache とparentを辿れば <distributionManagement>に書かれています。4階層もあって面倒なので、自力でpom読むよりは手元のpomでmvn help:effective-pom する方が確実ですし、結局<property>なのでビルド時に上書きできるんですけども。

と、pom.xmlを見たら書いてたりするという、あまり役に立たない知識を書いておきたかっただけです。 公式サイトのSnapshot buildsに書いてあるので、素直にこっち見た方がいいです。

インハウスリポジトリ

リモートリポジトリのうち、組織内部でのみ使用する目的で作られたリポジトリをインハウスリポジトリと言ったりします。

私が使ったことがあるのはSonatypeのNexus(Central Repositoryが使用している)や、JFrogのArtifactory(Springが使用している)。最近ではGitHub PackagesAWS CodeArtifactなども選択肢に入るかもしれません。

自分達だけが使うライブラリを登録したい場合はもちろん、クローズドなCentral Repositoryにアクセスできない環境や、Central Repositoryが落ちた時に備えるとか、ネットワーク的に近いところにキャッシュしてビルド時間を短縮したいとか、いろんな理由で使われます。

インハウスリポジトリを使用する場合、開発端末の ~/.m2/settings.xml に書くことが多いと思います。

Central Repository

Central Repsitoryは、Sonatypeが運営しており、世界中で使われ、あちこちでミラーリングされてたりするリポジトリです。

「セントラルリポジトリ」の他、「Mavenセントラルリポジトリ」とか、「セントラル」とか、先にも書きましたが単に「Mavenリポジトリ」と呼ばれたりします。いずれもCentral Repositoryのことです。JVM界隈では「ここで公開されているライブラリはだいたいどこでも使える」と言っていいです。

逆にここで公開されていないライブラリを使うには、個別の対応が必要になる認識です。

Central RepositoryのURL

Central RepotiroyのURLは https://repo1.maven.org/maven2https://repo.maven.apache.org/maven2 があり、公式で並列してアナウンスされているもの です。なのでどっちでもいい。

内容微妙に違うし(正確には「違うことがある」かな。この記事書いた時違ったけど、今みたら同じになってた。)、確かrepo1.maven.orgからrepo.maven.apache.orgに変更された経緯があった気がするんだけど、混乱したからどっちでもいいを維持することにしたんでしょうかね。Central Repotitoryを運営しているSonatypeの運営するインデックスサイト https://central.sonatype.com のリンクがrepo1向いてるんで、インターネットで示すのはrepo1がいいかなと思っています。リリースしたら両方に反映されるし。

Central Repositoryへの反映

CentralRepositoryへの反映は(個人の場合は)図のようにOpenSourceSoftwareRepositoryHostingというサービスを使用し、複数ステップで行われます。

デプロイとリリースは別ですが、プラグインでの自動化も可能。リリース時にjavadocやsourceがあるかとか署名の検証とかが行われ、ダメだったら跳ねられます。一度リリースしたものは削除できません。分かれてるのは最終確認みたいな感じですね。

Log4j 2はApacheなのでLarge Organization向けのものになるんでしょうかね。同期にどれくらい時間がかかるかはよくわかりません。

Central Repositoryへの反映ですが、少なくともOSSRHでは図で書いているように制御不可です。数時間かかる時もあれば、さきほどは10分くらいで反映されました。この時間が問題になることは少ないですが、JIGのようにGradlePluginPortal(ほぼ即時反映)とCentral Repositoryとの同時リリースすると、「GradlePluginPortalにはあるけどCentral Repositoryにないので使えない時間」があったり、単一リポジトリのマルチモジュールでなく複数リポジトリに分かれているライブラリはCentral Repositoryに反映されてからでないとリリース作業が行えない、とかがあったりします。

Central Repositoryでのライブラリ公開は一度やっておくとこの辺りの事情がイメージしやすくなるのかなと。

Gradleの話

GradleもなんだかんだでCentral Repositoryを使います。いっとき jcenter() を使う流れはありましたが、JCenterのサービス終了に伴い、Central Repositoryに戻りました。サービス終了が発表された時は騒ぎになりましたが、想定していたよりも混乱は少なかったように思います。今でもドキュメントに jcenter() と記述されたままのライブラリは多数ありますが、適宜読み替えましょう。

Gradleはbuild.gradleで以下のように書く必要があるので「Mavenセントラル」と言う言葉に馴染みはあるのではないでしょうか。

repositories {
    mavenCentral()
}

逆にデフォルトで使われるMavenの方がCentral Repsitoryは意識しないのかもしれないなぁ、と。

変更メモ

  • 2021-12-15T12:13
    • タイトルを 「Mavenリポジトリに最新版がある」とは から 「Mavenリポジトリに最新版がある」と言うときの基礎知識 に変えました。
  • 2021-12-15T15:50
    • さらにタイトルを Javaで「ライブラリの最新版がある」と言うときの基礎知識 に変えました。
  • 2023-04-20T14:50
    • s/セントラリリポジトリ/セントラルリポジトリ/g
    • jcenter() 周りを終了予定から終了後の内容に書き換え
    • https://search.maven.org の代わりに https://central.sonatype.com を使用する(画像は面倒だから変えてない)