2017幎に1぀のラむブラリの耇数のバヌゞョンでJavaアプリケヌションを実行する方法

2017幎に1぀のラむブラリの耇数のバヌゞョンでJavaアプリケヌションを実行する方法


KDPV、䜕も面癜い


私が盎面しなければならなかった1぀の問題の解決策ず、Java 9のコンテキストでのこの問題の調査を共有したいず思いたす。


免責事項

私の䜜家はただです私は初めお曞いおいたすので、投げたす おいしい 理由を瀺すトマトは倧歓迎です。
蚘事が以䞋のガむドずしお適切ではないこずに盎ちに同意したす。


  • Java 9
  • Elasticsearch
  • メむノン

ネットワヌク内の情報の姓がいっぱいの堎合、最初に...が衚瀺されたす 。少なくずも必芁な情報がありたす。


単玔な状況を想像しおください。Elasticsearchクラスタヌをデプロむし、そこにデヌタをロヌドしたす。 このクラスタヌを怜玢するアプリケヌションを䜜成しおいたす。 Elasticsearchの新しいバヌゞョンが絶えずリリヌスされおいるため、新しいバヌゞョンをクラスタヌに導入したす 問題 ロヌリングアップグレヌドを䜿甚する機胜。 しかし、ここに問題がありたす-ある時点で、保存されたデヌタの圢匏を倉曎したずえば、新しい機胜の1぀を最倧限に掻甚するため、むンデックスの再䜜成を䞍適切にしたした。 このオプションは私たちに適しおいたす同じマシンに新しいクラスタヌをむンストヌルしたす-叀いデヌタスキヌムを持぀最初のクラスタヌは怜玢のためだけに残り、新しいデヌタスキヌムを持぀受信デヌタは2番目にロヌドされたす。 次に、怜玢コンポヌネントは2぀のクラスタヌに接続する必芁がありたす。


このアプリケヌションはJava APIを䜿甚しおクラスタヌず通信したす。぀たり、Elasticsearch自䜓を䟝存関係にプルしたす。 5番目のバヌゞョンずずもにRest Clientがリリヌスされたこずで、このような問題Elasticsearchの䟿利なAPIからもを節玄できたこずは泚目に倀したすが、2番目のバヌゞョンのリリヌス時に察応する予定です。


Elasticsearch 1.7および2.4の2぀のクラスタヌでドキュメントを怜玢するずいう単玔なアプリケヌションの䟋を䜿甚しお、可胜な解決策を考えおみたしょう。 コヌドはgithubで入手でき、この蚘事の構造を繰り返したすOSGiのみが欠萜しおいたす。


ビゞネスに取り掛かろう。 次の構造を持぀Mavenプロゞェクトを䜜成したす。


+---pom.xml +---core/ | +---pom.xml | +---src/ | +---main/ | | +---java/ | | | +---elasticsearch/ | | | +---client/ | | | +---SearchClient.java | | | +---Searcher.java | | +---resources/ | +---test/ | +---java/ +---es-v1/ | +---pom.xml | +---src/ | +---main/ | | +---java/ | | | +---elasticsearch/ | | | +---client/ | | | +---v1/ | | | +---SearchClientImpl.java | | +---resources/ | +---test/ | +---java/ +---es-v2/ +---pom.xml +---src/ +---main/ | +---java/ | | +---elasticsearch/ | | +---client/ | | +---v2/ | | +---SearchClientImpl.java | +---resources/ +---test/ +---java/ 

明らかに、1぀のモゞュヌルで同じラむブラリの耇数のバヌゞョンを接続しおも機胜しないため、プロゞェクトはマルチモゞュヌルである必芁がありたす。



コアモゞュヌルには、 es-v1およびes-v2モゞュヌルの「テスト」であるSearcherクラスが含たれおいたす。


 public class Searcher { public static void main(String[] args) throws Exception { List<SearchClient> clients = Arrays.asList( getClient("1"), getClient("2") ); for (SearchClient client : clients) { System.out.printf("Client for version: %s%n", client.getVersion()); Map doc = client.search("test"); System.out.println("Found doc:"); System.out.println(doc); System.out.println(); } clients.forEach(SearchClient::close); } private static SearchClient getClient(String desiredVersion) throws Exception { return null; // .  } } 

超自然的なこずは䜕もありたせん。モゞュヌルで䜿甚されるElasticsearchのバヌゞョンが衚瀺され、それを介したテスト怜玢が実行されたす-これで十分です。


実装の1぀を芋おみたしょう。2぀目はほずんど同じです。


 public class SearchClientImpl implements SearchClient { private final Settings settings = ImmutableSettings.builder() .put("cluster.name", "es1") .put("node.name", "es1") .build(); private final Client searchClient = new TransportClient(settings) .addTransportAddress(getAddress()); private InetSocketTransportAddress getAddress() { return new InetSocketTransportAddress("127.0.0.1", 9301); } @Override public String getVersion() { return Version.CURRENT.number(); } @Override public Map search(String term) { SearchResponse response = searchClient.prepareSearch("*") .setQuery(QueryBuilders.termQuery("field", term)) .execute() .actionGet(); if (response.getHits().getTotalHits() > 0) { return response.getHits().getAt(0).getSource(); } else { return null; } } @Override public void close() { searchClient.close(); } } 

すべおが簡単です。珟圚のバヌゞョンは、Elasticsearchで配線され、すべおのむンデックス * のフィヌルドfieldで怜玢され、最初に芋぀かったドキュメントがあればそれを返したす。


ここでの問題は、 Searcher#getClientでSearchClientむンタヌフェむスのSearchClientを呌び出しお、目的の結果を取埗するSearcher#getClientです。


たぶんClass.forName


あなたがJavaの専門家でなくおも、 ClassLoaderのルヌルを聞いたこずがあるはずです。 デフォルトのたたにするず、蚈画を完了できなくなりたす。そのため、このような゜リュヌションは機胜したせん。


 private static SearchClient getClient(String desiredVersion) throws Exception { String className = String.format("elasticsearch.client.v%s.SearchClientImpl", desiredVersion); return (SearchClient) Class.forName(className).newInstance(); } 

収集し、実行しお結果を確認したす...たずえば、次のように、かなり䞍確かです。


 Exception in thread "main" java.lang.IncompatibleClassChangeError: Implementing class at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) at java.net.URLClassLoader.access$100(URLClassLoader.java:73) at java.net.URLClassLoader$1.run(URLClassLoader.java:368) at java.net.URLClassLoader$1.run(URLClassLoader.java:362) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:361) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at elasticsearch.client.Searcher.getClient(Searcher.java:28) at elasticsearch.client.Searcher.main(Searcher.java:10) 

ClassNotFoundException ...たたは䜕か他のものをスロヌする可胜性がありたすが...


URLClassLoaderは、指定されたjarファむルずディレクトリのセットから指定された名前を持぀最初のクラスを芋぀けおロヌドするため、これは必須のクラスではありたせん。 この堎合、 elasticsearch-2.4.5.jarがクラスパスリスト内のelasticsearch-1.7.5.jar elasticsearch-2.4.5.jarするため、この゚ラヌが発生し、すべおのクラス名前で䞀臎するが2.4.5でロヌドされたす。 。 Searcherは最初にElasticsearch 1.7.5 getClient("1") のモゞュヌルをロヌドしようずするため、URLClassLoaderは間違ったクラスをロヌドしたす...


クラスロヌダヌのクラスが名前およびファむル名で亀差しおいる堎合、この状態はjar hellたたはclass-path hellず呌ばれたす。


カスタムClassLoader


モゞュヌルずその䟝存関係を異なるクラスロヌダヌに分散する必芁があるこずが明らかになりたす。 es-v *モゞュヌルごずにURLClassLoaderを䜜成し、jarファむルを䜿甚しお各ディレクトリに指定したす。


 private static SearchClient getClient(String desiredVersion) throws Exception { String className = String.format("elasticsearch.client.v%s.SearchClientImpl", desiredVersion); Path moduleDependencies = Paths.get("modules", "es-v" + desiredVersion); URL[] jars = Files.list(moduleDependencies) .map(Path::toUri) .map(Searcher::toURL) .toArray(URL[]::new); ClassLoader classLoader = new URLClassLoader(jars); // parent = app's class loader return (SearchClient) classLoader.loadClass(className).newInstance(); } 

すべおのモゞュヌルを収集しお適切なmodules/es-v*/ディレクトリにコピヌする必芁がありたす。これには、 es-v1およびes-v2モゞュヌルのmaven-dependency-pluginを䜿甚したす。


プロゞェクトを組み立おたしょう


 mvn package 

そしお実行


 . 29, 2017 10:37:08  org.elasticsearch.plugins.PluginsService <init> INFO: [es1] loaded [], sites [] . 29, 2017 10:37:12  org.elasticsearch.plugins.PluginsService <init> INFO: [es2] modules [], plugins [], sites [] Client for version: 1.7.5 Found doc: {field=test 1} Client for version: 2.4.5 Found doc: {field=test 2} 

ビンゎ


1.7はJRE 9では機胜したせん

Elasticsearch 1.7の再構築で埌述するように、JvmInfoにパッチを適甚しない堎合。


非垞に筋金入りのケヌスでは、 コアモゞュヌルもElasticsearchラむブラリのナヌティリティメ゜ッドを䜿甚するこずを想定しおいたす。 クラスのロヌド順序が原因で、珟圚の゜リュヌションは機胜しなくなりたす。


  1. findLoadedClassStringを呌び出しお、クラスがすでにロヌドされおいるかどうかを確認したす。
  2. 芪クラスロヌダヌでloadClassメ゜ッドを呌び出したす。 芪がnullの堎合、代わりに仮想マシンに組み蟌たれおいるクラスロヌダヌが䜿甚されたす。
  3. findClassStringメ゜ッドを呌び出しお、クラスを芋぀けたす。

぀たり、この堎合、 es-v *ではなく、 コアのElasticsearchクラスがロヌドされたす。 ブヌト順序を詳しく芋るず、回避策がありたす。手順2ず3を逆にしお、この順序に違反するクラスロヌダヌを䜜成したす。このようなロヌダヌは、 es-v *モゞュヌルだけでなく、 coreのクラスも読み蟌むこずができたす。


URLClassLoaderを䜜成しお、ParentLastURLClassLoaderなどの名前を付けたしょう。


 public class ParentLastURLClassLoader extends URLClassLoader { ... } 

そしおloadClass(String,boolean)を再定矩し、ClassLoaderからコヌドをコピヌし、䞍芁なものをすべお削陀したす。


 @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { Class<?> c = findLoadedClass(name); if (c == null) { try { if (getParent() != null) { c = getParent().loadClass(name); } } catch (ClassNotFoundException e) { } if (c == null) { c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } } 

getParent().loadClass(String) 、 findClass(String)の呌び出しを入れ替えお、次を取埗したす。


 @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { Class<?> c = findLoadedClass(name); if (c == null) { try { c = findClass(name); } catch (ClassNotFoundException ignored) { } if (c == null) { c = getParent().loadClass(name); if(c == null) { throw new ClassNotFoundException(name); } } } if (resolve) { resolveClass(c); } return c; } } 

アプリケヌションはモゞュヌルクラスを手動でロヌドするため、クラスがどこにも芋぀からない堎合、ロヌダヌはClassNotFoundExceptionをスロヌする必芁がありたす。


ロヌダヌが䜜成されたので、これを䜿甚しお、 getClient(String)メ゜ッドのURLClassLoaderを眮き換えたす。


 ClassLoader classLoader = new URLClassLoader(jars); 

ParentLastURLClassLoader 


 ClassLoader classLoader = new ParentLastClassLoader(jars); 

アプリケヌションを再床起動するず、同じ結果が衚瀺されたす。


 . 29, 2017 10:42:41  org.elasticsearch.plugins.PluginsService <init> INFO: [es1] loaded [], sites [] . 29, 2017 10:42:44  org.elasticsearch.plugins.PluginsService <init> INFO: [es2] modules [], plugins [], sites [] Client for version: 1.7.5 Found doc: {field=test 1} Client for version: 2.4.5 Found doc: {field=test 2} 

ServiceLoader API


Java 6では、 java.util.ServiceLoaderクラスが远加されたした。これは、むンタヌフェむス/抜象クラスによっお実装をロヌドするメカニズムを提䟛したす。 このクラスは問題を解決したす


 private static SearchClient getClient(String desiredVersion) throws Exception { Path moduleDependencies = Paths.get("modules", "es-v" + desiredVersion); URL[] jars = Files.list(moduleDependencies) .map(Path::toUri) .map(Searcher::toURL) .toArray(URL[]::new); ServiceLoader<SearchClient> serviceLoader = ServiceLoader.load(SearchClient.class, new URLClassLoader(jars)); return serviceLoader.iterator().next(); } 

すべおが非垞に簡単です



ServiceLoaderがむンタヌフェむスの実装を確認するには、 META-INF/servicesディレクトリにむンタヌフェむスのフルネヌムでファむルを䜜成する必芁がありたす。


 +---es-v1/ | +---src/ | +---main/ | +---resources/ | +---META-INF/ | +---services/ | +---elasticsearch.client.spi.SearchClient +---es-v2/ +---src/ +---main/ +---resources/ +---META-INF/ +---services/ +---elasticsearch.client.spi.SearchClient 

そしお、各行にこのむンタヌフェむスを実装するクラスの完党な名前を曞きたす。この堎合、モゞュヌルごずに1぀のSearchClientImplです。
es-v1の堎合 、ファむルに次の行がありたす。


 elasticsearch.client.v1.SearchClientImpl 

es-v2の堎合 


 elasticsearch.client.v2.SearchClientImpl 

たた、 maven-dependency-pluginを䜿甚しお、 es-v * modules/es-v*/をmodules/es-v*/にコピヌしmodules/es-v*/ 。 プロゞェクトをリビルドしたす。


 mvn clean package 

そしお実行


 . 29, 2017 10:50:17  org.elasticsearch.plugins.PluginsService <init> INFO: [es1] loaded [], sites [] . 29, 2017 10:50:20  org.elasticsearch.plugins.PluginsService <init> INFO: [es2] modules [], plugins [], sites [] Client for version: 1.7.5 Found doc: {field=test 1} Client for version: 2.4.5 Found doc: {field=test 2} 

すばらしい、望たしい結果が再び埗られたす。


前述のハヌドコアの堎合、 SearchClientむンタヌフェむスを別のspiモゞュヌルにSearchClient 、次のロヌダヌチェヌンを䜿甚する必芁がありたす。


 core: bootstrap -> system spi: bootstrap -> spi es-v1: bootstrap -> spi -> es-v1 es-v2: bootstrap -> spi -> es-v2 

぀たり


  1. spi甚に別のブヌトロヌダヌを䜜成したす芪ではnullをスロヌしたす-ブヌトストラップブヌトロヌダヌが䜿甚されたす。
  2. spi  SearchClientむンタヌフェヌスでロヌドし、
  3. 次に、 es-v *モゞュヌルごずにロヌダヌを䜜成したす。これには、 spiロヌダヌが芪ずしお含たれたす
  4. ...
  5. 利益

OSGiモゞュヌル


私はすぐに正盎に告癜したす-私はOSGiフレヌムワヌクに出䌚ったこずがありたせんそれは良いこずですか。 Apache FelixずEclipse Equinoxの初心者マナを芋るず、これらは手動でバンドルがロヌドされるコンテナに䌌おいたす。 埋め蟌みの実装があったずしおも、これは単玔なアプリケヌションにずっおは面倒です。 私が間違っおいる堎合は、反察の芖点をコメントで衚珟したす実際、誰かがそれをどのように䜿甚しおいるかを芋たいです 。


私はこの問題に深く入りたせんでした、なぜなら Java 9では、モゞュヌルはすぐに䜿甚できるようになりたした。これに぀いお説明したす。


Javaのネむティブモゞュヌル


先週、プラットフォヌムの9番目のバヌゞョンがリリヌスされたした。䞻な革新は、ランタむムずプラットフォヌム自䜓の゜ヌスコヌドのモゞュヌル化でした。 たさに必芁なものです


ヒントモゞュヌルを䜿甚するには、 JDK 9をただダりンロヌドしおいない堎合は、たずダりンロヌドしおむンストヌルする必芁がありたす 。


ここで唯䞀耇雑なのは、9の䞋でモゞュヌルずしお実行するために䜿甚されるラむブラリの機胜です実際、IntelliJ IDEAでmodule-pathずずもにclass-pathを指定する方法が芋぀からなかったため、module-pathのコンテキストですべおを実行したす。


モゞュラヌシステムの仕組み


モゞュラヌシステム甚にアプリケヌションのコヌドを倉曎する前に、たずそれがどのように機胜するかを芋぀けたす私自身はこの問題を理解し始めたばかりなので、間違っおいるかもしれたせん。


䞊蚘のモゞュヌルに加えお、それらを含むレむダヌもありたす。 アプリケヌションがbootず、アプリケヌションを構成する--module-pathで指定されたすべおのモゞュヌルがロヌドされるboot局が䜜成され、それらの䟝存関係すべおのモゞュヌルは自動的にjava.baseモゞュヌルに䟝存したす。 他のレむダヌはプログラムで䜜成できたす。


各局には独自のクラスロヌダヌたたは階局がありたす。 ブヌトロヌダヌず同様に、モゞュラヌレむダヌも階局的に構築できたす。 このような階局では、ある局のモゞュヌルは、芪局にある他のモゞュヌルを芋るこずができたす。


モゞュヌル自䜓は互いに分離されおおり、デフォルトでは、モゞュヌル内のパッケヌゞずクラスは他のモゞュヌルからは芋えたせん。 モゞュヌル蚘述子 module-info.java を䜿甚するず、各モゞュヌルが開くこずができるパッケヌゞず、䟝存するモゞュヌルずそのパッケヌゞを指定できたす。 さらに、モゞュヌルは、䜜業䞭に特定のむンタヌフェむスを䜿甚しおいるこずを通知し、これらのむンタヌフェむスの利甚可胜な実装を通知する堎合がありたす。 この情報は、モゞュヌルからむンタヌフェむス実装をロヌドするためにServiceLoader APIによっお䜿甚されたす。


モゞュヌルは明瀺的か぀自動ですさらに倚くのタむプがありたすが、これらに限定したす。



これで、この情報をプロゞェクトに適甚するのに十分になりたす。


  1. ブヌトレむダヌには、 コアモゞュヌルのみがありたす。 es-v *モゞュヌルが含たれる堎合、 elasticsearch.shaded掚移的モゞュヌルが競合するため、アプリケヌションは起動したせん。
  2. Searcherクラスは、ServiceLoader APIを䜿甚しお、クラスロヌダヌでes-v *モゞュヌルを個別の子レむダヌに手動でロヌドしたす。

それは簡単ですか...


パッケヌゞ地獄


モゞュヌルは少なくずも1぀のレむダヌでパッケヌゞ名を重耇させるこずはできたせん。


たずえば、パブリッククラスFunctionsある皮のAPIを提䟛する特定のラむブラリがありたす。 このラむブラリには、バッチスコヌプを持぀Helpersクラスがありたす。 ここにありたす


 com.foo.bar public class Functions class Helpers 

2番目のラむブラリがシヌンに入り、最初のラむブラリの機胜を補完したす。


 com.foo.baz public class Additional 

そしお、圌女は閉じたHelpersクラスの機胜を必芁ずしたす。 同じパッケヌゞにいく぀かのクラスを配眮するこずで、状況から抜け出したす。


 com.foo.baz public class Additional com.foo.bar public class AccessorToHelpers 

おめでずうございたす-モゞュラヌシステムの芳点から分割パッケヌゞの問題を䜜成したした。 そのようなラむブラリで䜕ができたすか このようなラむブラリをクラスパスに残し 、自動モゞュヌルをブリッゞずしお䜿甚しお、モゞュヌルからそれらに到達するこずが提案されおいたす。 しかし、簡単な方法を探しおいるわけではないので、別のオプションを䜿甚したす。すべおの䟝存関係をラむブラリに報告し、単䞀のjarアヌカむブファットjarおよびuber jarずしお知られおいたすを取埗し、モゞュヌルパスで自動モゞュヌルずしお䜿甚できたす。クラスパスをバむパスしたす。 問題は、このようなオヌルむンワンjarを䜜成するこずです。


Elasticsearchの再組み立お手順

Elasticsearchは、パッケヌゞプラむベヌトメ゜ッド/フィヌルドぞのアクセスを積極的に䜿甚しお、䞀郚のLucene機胜にアクセスしたす。 それを自動モゞュヌルずしお䜿甚するには、それをuber jarにしお、プロゞェクトでさらに䜿甚するためにelasticsaerch-shadedずいう名前でロヌカルリポゞトリにむンストヌルしたす。


Elasticsearch 1.7をビルドする


最初のバヌゞョンでは、アプリケヌションプロゞェクトが唯䞀のMavenモゞュヌルであるため、ここで問題は発生したせんpom.xml番目のモゞュヌルをpom.xml堎合、 pom.xmlずいく぀かのクラスを修正する必芁がありたす。


リポゞトリをあるディレクトリに耇補し、v1.7.5タグをチェックアりトしおv1.7.5を開始しv1.7.5 。


  • このプロゞェクトはすでにmaven-shade-plugin䜿甚しおいるため、uberjarをビルドするには、いく぀かのパッケヌゞが含たれおいるこずをコメントアりトしお、すべおが含たれるようにする必芁がありたす。

 <!-- <includes> <include>com.google.guava:guava</include> <include>com.carrotsearch:hppc</include> <include>com.fasterxml.jackson.core:jackson-core</include> ... </includes> --> 

できれば元の、動きのないもの


 <!-- <relocations> <relocation> <pattern>com.google.common</pattern> <shadedPattern>org.elasticsearch.common</shadedPattern> </relocation> <relocation> <pattern>com.carrotsearch.hppc</pattern> <shadedPattern>org.elasticsearch.common.hppc</shadedPattern> </relocation> ... </relocations> --> 

  • コメントアりトされた<includes>ノヌドの盎埌に<excludes>远加するこずにより、Groovy このようなあいたいさのために負荷を䞭断したすずロガヌそれらの蚭定はありたせん。JULはデフォルトで正垞に動䜜したすを削陀する必芁がありたす。

 <excludes> <exclude>org.codehaus.groovy:groovy-all</exclude> <exclude>org.slf4j:*</exclude> <exclude>log4j:*</exclude> </excludes> 

  • 未䜿甚クラスの切断をオフにしたす-プラグむンはServiceLoader / Reflection APIを認識したせん

 <!--<minimizeJar>true</minimizeJar>--> 

  • そしお、ServiceLoader APIの実装クラスを持぀サヌビスファむルの接着をプラグむンの<configuration>ノヌドに远加したす。

 <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> 

  • pom.xml完成したため、 java.lang.management.RuntimeMXBean#getBootClassPathをスロヌするUnsupportedOperationExceptionを排陀するために残っおいjava.lang.management.RuntimeMXBean#getBootClassPath 。 これを行うには、 JvmInfoクラスで次の行を芋぀けたす。

 info.bootClassPath = runtimeMXBean.getBootClassPath(); 

それを「正しいもの」に守る


 if (runtimeMXBean.isBootClassPathSupported()) { info.bootClassPath = runtimeMXBean.getBootClassPath(); } else { info.bootClassPath = ""; } 

この情報は統蚈にのみ䜿甚されたす。


完了、jarをビルドできるようになりたした


 $ mvn package 

コンパむルずアセンブリの埌、必芁なelasticsearch-1.7.5.jarをtargetディレクトリにelasticsearch-1.7.5.jarしたす。 次に、たずえばelasticsearch-shadedずいう名前で、ロヌカルリポゞトリにむンストヌルする必芁がありたす。


 $ mvn install:install-file \ > -Dfile=elasticsearch-1.7.5.jar \ > -DgroupId=org.elasticsearch \ > -DartifactId=elasticsearch-shaded \ > -Dversion=1.7.5 \ > -Dpackaging=jar \ > -DgeneratePom=true 

これで、このアヌティファクトをes-v1 Mavenモゞュヌルの自動モゞュヌルずしお䜿甚できたす。


 <dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch-shaded</artifactId> <version>1.7.5</version> </dependency> ... </dependencies> 

Elasticsearch 2.4をビルドする


ロヌカルの倉曎をロヌルバックし、 v2.4.5タグにタグを付けたす。 2番目のバヌゞョンから、プロゞェクトはモゞュヌルに分割されたす。 elasticsearch-2.4.5.jar発行するために必芁なモゞュヌルがコアモゞュヌルです。


  • 最初にスナップショットを削陀したす。リリヌスが必芁です。

 $ mvn versions:set -DnewVersion=2.4.5 

  • ここで、シェヌドプラグむンがどこで蚭定されおいるかを芋おみたしょう...そしお、そのようなドックに遭遇したす

シェヌディングずパッケヌゞの再配眮が削陀されたした



Elasticsearchは、䟝存関係をシェヌディングし、パッケヌゞを再配眮するために䜿甚されおいたした。 シェヌディングや再配眮は䜿甚しなくなりたした。
むンポヌトを元のパッケヌゞ名に倉曎する必芁がある堎合がありたす。
  • com.google.commonはorg.elasticsearch.common
  • com.carrotsearch.hppcはorg.elasticsearch.common.hppc
  • jsr166eはorg.elasticsearch.common.util.concurrent.jsr166e
    ...

コアモゞュヌルに再床シェヌドプラグむンを远加し、サヌビスファむルのトランスフォヌマヌずロガヌの陀倖を蚭定に远加する必芁がありたす。


 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> <artifactSet> <excludes> <exclude>org.slf4j:*</exclude> <exclude>log4j:*</exclude> </excludes> </artifactSet> </configuration> </plugin> 

  • コアモゞュヌルのcom.twitter:jsr166e 9-keには存圚しないsun.misc.Unsafe䜿甚を削陀したす。

 <!-- <dependency> <groupId>com.twitter</groupId> <artifactId>jsr166e</artifactId> <version>1.1.0</version> </dependency> --> 

むンポヌトcom.twitter.jsr166eをjava.util.concurrent.atomic倉曎したす。


  • animal-sniffer-maven-plugin前のステップの倉曎animal-sniffer-maven-plugin怜出し7-keにはjsr166eはありたせん、削陀したす

 <!-- <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>animal-sniffer-maven-plugin</artifactId> </plugin> --> 

完了、 es-v1ず同じアセンブリおよびむンストヌル手順を実行しおいたすが、わずかな違いがありたす。


  • バヌゞョンを2.4.5に倉曎し、
  • コアモゞュヌルをビルドするだけです。

 $ mvn clean package -pl org.elasticsearch:parent,org.elasticsearch:elasticsearch -DskipTests=true 

私たちのプロゞェクトのモゞュヌル


䜿甚するラむブラリがモゞュラヌJavaシステムで機胜するこずがわかった埌、Mavenモゞュヌルから明瀺的なJavaモゞュヌルを䜜成したす。 これを行うには、゜ヌス src/main/java を䜿甚しお各ディレクトリにmodule-info.javaファむルを䜜成し、それらのモゞュヌル間の関係を蚘述する必芁がありたす。


コアモゞュヌルは他のモゞュヌルに䟝存せず、他のモゞュヌルが実装する必芁があるむンタヌフェむスのみを含むため、説明は次のようになりたす。


 //   - elasticsearch.client.core module elasticsearch.client.core { // ,     , //       exports elasticsearch.client.spi; //    ,     SearchClient //    ServiceLoader' uses elasticsearch.client.spi.SearchClient; } 

es-v1およびes-v2モゞュヌルに぀いおも同様の説明がありたす。



es-v1の合蚈


 //   - elasticsearch.client.v1 module elasticsearch.client.v1 { //  core  SearchClient requires elasticsearch.client.core; //   requires elasticsearch.shaded; //   core,        provides elasticsearch.client.spi.SearchClient with elasticsearch.client.v1.SearchClientImpl; } 

es-v2の堎合、ほずんどすべおが同じであり、バヌゞョンv2のみが名前に衚瀺されたす。


次に、そのようなモゞュヌルをロヌドする方法は この質問に察する答えは、FSからモゞュヌルをロヌドする小さな䟋を含むModuleLayerクラスの説明にありたす。 すべおのes-v *モゞュヌルが同じディレクトリmodules/es-v*/にあるず仮定するず、次のように曞くこずができたす。


 private static SearchClient getClient(String desiredVersion) throws Exception { Path modPath = Paths.get("modules", "es-v" + desiredVersion); ModuleFinder moduleFinder = ModuleFinder.of(modPath); ModuleLayer parent = ModuleLayer.boot(); Configuration config = parent.configuration().resolve(moduleFinder, ModuleFinder.of(), Set.of("elasticsearch.client.v" + desiredVersion)); ModuleLayer moduleLayer = parent.defineModulesWithOneLoader(config, Thread.currentThread().getContextClassLoader()); ServiceLoader<SearchClient> serviceLoader = ServiceLoader.load(moduleLayer, SearchClient.class); Optional<SearchClient> searchClient = serviceLoader.findFirst(); if (searchClient.isPresent()) { return searchClient.get(); } throw new Exception("Module 'elasticsearch.client.v" + desiredVersion + "' not found on " + modPath); } 

ModuleLayer#defineModulesWithManyLoaders , es-v* .


, . maven-compiler-plugin , — 3.7.0:


 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> </plugin> 

Java 9 :


 <properties> <maven.compiler.source>1.9</maven.compiler.source> <maven.compiler.target>1.9</maven.compiler.target> </properties> 

maven-dependency-plugin , :


 $ mvn clean package 

, :


 . 29, 2017 10:59:01  org.elasticsearch.plugins.PluginsService <init> INFO: [es1] loaded [], sites [] . 29, 2017 10:59:04  org.elasticsearch.plugins.PluginsService <init> INFO: [es2] modules [], plugins [], sites [] Client for version: 1.7.5 Found doc: {field=test 1} Client for version: 2.4.5 Found doc: {field=test 2} 

, — , , Java 8 .


終わり


, /. :



PS Java 9!



Source: https://habr.com/ru/post/J339026/


All Articles