
動的な依存関係の解決が必要な理由を尋ねるかもしれません。 これを行うのが簡単なものもあれば、可能なものもあります。
私はそれについて話し、habrの出版物のサイクルの例を示しました
この出版物には、Groovyの単一のjarファイルとしての実用的なソリューションと、JavaアプリケーションのMavenリポジトリーからのクラスローダーがあります。 すぐに使えるグレープの機能について学びます。 根拠がないように、そしてグレープの可能性が明確になったために...
公式ガイドから例を挙げます:
@Grapes([ @Grab(group='org.eclipse.jetty.aggregate', module='jetty-server', version='8.1.7.v20120910'), @Grab(group='org.eclipse.jetty.aggregate', module='jetty-servlet', version='8.1.7.v20120910'), @Grab(group='javax.servlet', module='javax.servlet-api', version='3.0.1')]) import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.* import groovy.servlet.* def runServer(duration) { def server = new Server(8080) def context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS); context.resourceBase = "." context.addServlet(TemplateServlet, "*.gsp") server.start() sleep duration server.stop() } runServer(10000)
このスクリプトは、リモートリポジトリからjettyサーバーアーティファクトをダウンロードし、スクリプトクラスパスに追加し、httpサーバークラスのインスタンスを作成し、gspページハンドラーを追加します(これはグルーブ自体にある強力なテンプレートメカニズムです)。サーバーが起動し、10秒待機して停止します。 つまり スクリプトを記述する時点では、これらの依存関係は不要です。リポジトリへのアクセスのみが必要であり、次回にjetty依存関係が既にローカルファイルシステムにあり、ネットワークからダウンロードする必要はありません。
私にとっては、言語自体に組み込まれた独創的なメカニズムです!!!
jettyサーバーでスクリプトを実行するには、クラスパスでgroovyおよびivyプロバイダークラスのみが必要です。 クラスは、ivyを使用してMavenリポジトリーからロードされます。
溝の荒野では、最初にローカルファイルシステム$ {user.home} /。Groovy / grapesで依存関係を探し、次に$ {user.home} /。M2 / repository /で探してから検索する必要があるという構成が非表示になっています最初にjcenterで、次にibiblioで、最後にjava.net2リポジトリで検索します
同じ構成
<ivysettings> <settings defaultResolver="downloadGrapes"/> <resolvers> <chain name="downloadGrapes" returnFirst="true"> <filesystem name="cachedGrapes"> <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/> <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision](-[classifier]).[ext]"/> </filesystem> <ibiblio name="localm2" root="file:${user.home}/.m2/repository/" checkmodified="true" changingPattern=".*" changingMatcher="regexp" m2compatible="true"/> <!-- todo add 'endorsed groovy extensions' resolver here --> <ibiblio name="jcenter" root="https://jcenter.bintray.com/" m2compatible="true"/> <ibiblio name="ibiblio" m2compatible="true"/> <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/> </chain> </resolvers> </ivysettings>
しかし、Grapeの広範囲にわたる使用を妨げるニュアンスが1つあります。これは、Ivyへの依存関係を解決するメカニズムの実装であり、グルーブと同じjar内のプロバイダークラスの欠如です。 私が話していることは次のとおりです。
igor @ igor-comp:〜/ dev / projects / groovy-grape-aether $ java -jar /home/igor/.m2/repository/org/codehaus/groovy/groovy-all/2.4.5/groovy-all-2.4 .5.jar〜/ dev / projects / jetty.groovy
キャッチ:java.lang.NoClassDefFoundError:org / apache / ivy / Ivy
java.lang.NoClassDefFoundError:org / apache / ivy / Ivy
原因:java.lang.ClassNotFoundException:org.apache.ivy.Ivy
複雑な推移的な依存関係、バージョン範囲、またはMavenリポジトリのスナップショットバージョンでIvyを使用しようとした人は、複数のバンプを埋めました。
groovyプロジェクトのGrape.javaのソースコードにはそのような行があります
// by default use GrapeIvy //TODO META-INF/services resolver? instance = (GrapeEngine) Class.forName("groovy.grape.GrapeIvy").newInstance();
この検索により、Springブートプロジェクトが始まりました。このプロジェクトでは、ボンネットの下でGrapeが使用されていますが、Aetherに実装されているMavenプロバイダーが犠牲になります。 エーテルは、リポジトリにアクセスしてアーティファクトを公開するための単一のライブラリです。 Maven、Nexus、M2Eclipseで使用されます。 アイビーは同じ戦場で彼女と競うことはできそうにない。 ブドウにエーテルを使用するのは素晴らしいことです!
GrapeEngineInstallerは、TODOコメントを書いたときにgroovyの作成者が考えていたほとんどのことを行います。ハードコーディングされたGrapeIvyグルーブの代わりにGrape.instanceフィールドをAetherGrapeEngineプロバイダーに割り当てます。
public abstract class GrapeEngineInstaller { public static void install(GrapeEngine engine) { synchronized (Grape.class) { try { Field field = Grape.class.getDeclaredField("instance"); field.setAccessible(true); field.set(null, engine);
また、リフレクションを使用して「ダーティハック」がブートに実装されることは重要ではありません)「TODO META-INF /サービスリゾルバー」の作成者のアイデアは、特にアプリケーションを調整する場合、Grooveも最適ではなく、そのようなリゾルバーは確かにOSGI環境の痛みになります。
完全な幸福のために、すべてのbootクラスとspringクラスがなく、その作業に必要なすべてのAetherクラスがなくても、AetherGrapeEngineが必要です。
これにより、AetherGrapeEngineとmvn- classloaderクラスローダーをわずか3 MBの別のアーティファクトに組み合わせて、スプリングブートプロジェクトと分離の手術に至りました。 これらの3メガバイトは、Groove言語と私のAspectJスクリプトプロジェクトの両方に役立ちます! 結果を共有できることを嬉しく思います。このプロジェクトがあなたにも役立つことを願っています。
mvn-classloaderとgroovy-allを組み合わせた後、groovy-allを置き換える9.8 MBのアーティファクトが得られ、AetherGrapeEngine依存関係リゾルバーを使用してGroovyアプリケーションでGrapeメカニズムを使用できるようになりました。
中央リポジトリgroovy-grape-aether-2.4.5.1.jarからダウンロードします。 groovy-grape-aetherプロジェクトに基づいて組み立てられました。
グルーブスクリプトcarash.groovyでsshサーバーを初期化します。
@Grab(group='org.crashub', module='crash.connectors.ssh', version='1.3.1') import org.crsh.standalone.Bootstrap import org.crsh.vfs.FS.Builder import org.crsh.vfs.spi.url.ClassPathMountFactory def classLoader = Bootstrap.getClassLoader(); def classpathDriver = new ClassPathMountFactory(classLoader); def cmdFS = new Builder().register("classpath", classpathDriver).mount("classpath:/crash/commands/").build(); def confFS = new Builder().register("classpath", classpathDriver).mount("classpath:/crash/").build(); def bootstrap = new Bootstrap(classLoader, confFS, cmdFS); def config = new java.util.Properties(); config.put("crash.ssh.port", "2000"); config.put("crash.ssh.auth_timeout", "300000"); config.put("crash.ssh.idle_timeout", "300000"); config.put("crash.auth", "simple"); config.put("crash.auth.simple.username", "admin"); config.put("crash.auth.simple.password", "admin"); bootstrap.setConfig(config); bootstrap.bootstrap(); sleep 60000 bootstrap.shutdown();
このスクリプトを実行して、コマンドjava -jar groovy-grape-aether-2.4.5.1.jar carash.groovyを実行します
そして、コンソールで、スクリプトがリポジトリ内の依存関係を見つけて動作する様子を観察します
これを確認するには、次のサーバーに接続します:ssh admin@127.0.0.1 -p 2000
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティからプロパティvfs.refresh_period = 1を設定しています
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= SSHPlugin、インターフェイス= SSHPlugin]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= SSHInlinePlugin、インターフェイス= CommandPlugin]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= KeyAuthenticationPlugin、インターフェイス= KeyAuthenticationPlugin]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= CRaSHShellFactory、インターフェイス= ShellFactory]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= GroovyLanguageProxy、インターフェース=言語]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= JavaLanguage、インターフェース=言語]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= ScriptLanguage、インターフェイス=言語]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= JaasAuthenticationPlugin、インターフェイス= AuthenticationPlugin]
2015年11月5日1:01:50 AM org.crsh.plugin.ServiceLoaderDiscovery getPlugins
情報:ロードされたプラグインプラグイン[タイプ= SimpleAuthenticationPlugin、インターフェイス= AuthenticationPlugin]
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティからプロパティssh.port = 2000を設定しています
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティからのプロパティssh.auth_timeout = 300000の構成
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティからプロパティssh.idle_timeout = 300000を設定しています
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティssh.default_encoding = UTF-8をプロパティから設定しています
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティauth =プロパティからシンプルを設定
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティauth.simple.username = adminをプロパティから設定しています
2015年11月5日1:01:50 org.crsh.plugin.PluginLifeCycle configureProperty
情報:プロパティauth.simple.password = adminをプロパティから設定しています
SLF4J:クラス「org.slf4j.impl.StaticLoggerBinder」のロードに失敗しました。
SLF4J:デフォルトの無操作(NOP)ロガー実装
SLF4J:詳細については、 www.slf4j.org / codes.html#StaticLoggerBinderを参照してください。
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= KeyAuthenticationPlugin、インターフェイス= KeyAuthenticationPlugin]
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= JaasAuthenticationPlugin、インターフェイス= AuthenticationPlugin]
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= SimpleAuthenticationPlugin、インターフェイス= AuthenticationPlugin]
2015年11月5日1:01:50 org.crsh.ssh.SSHPlugin init
情報:SSHDの起動
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= GroovyLanguageProxy、インターフェース=言語]
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= JavaLanguage、インターフェース=言語]
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= ScriptLanguage、インターフェイス=言語]
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= CRaSHShellFactory、インターフェイス= ShellFactory]
2015年11月5日1:01:50 AM org.crsh.ssh.term.SSHLifeCycle init
情報:CRaSSHDを開始しようとしています
2015年11月5日1:01:50 AM org.crsh.ssh.term.SSHLifeCycle init
情報:ポート2000でCRaSSHDが開始されました
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= SSHPlugin、インターフェイス= SSHPlugin]
2015年11月5日1:01:50 org.crsh.plugin.PluginManager getPlugins
情報:初期化されたプラグインプラグイン[タイプ= SSHInlinePlugin、インターフェイス= CommandPlugin]
2015年11月5日1:01:56 AM org.crsh.ssh.SSHPlugin destroy
情報:SSHDをシャットダウンしています
これを確認するには、次のサーバーに接続します:ssh admin@127.0.0.1 -p 2000

これで、groovyスクリプトでMavenリポジトリーの依存関係を使用できるようになりました。 これを行うには、アーティファクトでAetherGrapeEngineと組み合わせてgroovy-all-2.4.5のみが必要です。
<dependency> <groupId>com.github.igor-suhorukov</groupId> <artifactId>groovy-grape-aether</artifactId> <version>2.4.5.1</version> </dependency>
同じアーティファクトには、Javaプログラム用のクラスローダーcom.github.igorsuhorukov.smreed.dropship.MavenClassLoaderがあります。 そのため、プロジェクトでGroovyを使用することが不可能な場合、Javaプロジェクトで動的クラスローディングを使用した同様の機能を利用できます。 しかし、このためだけに使用する方が便利です
<dependency> <groupId>com.github.igor-suhorukov</groupId> <artifactId>mvn-classloader</artifactId> <version>1.3</version> </dependency>
以下は、Mavenリポジトリからorg.crsh.standalone.Bootstrapクラスを取得するためのJavaコードの例です。
URLClassLoader sshServerClassloader= MavenClassLoader.forMavenCoordinates("org.crashub:crash.connectors.ssh:1.3.1"); Class<?> bootstrapClass = sshServerClassloader.loadClass("org.crsh.standalone.Bootstrap");
記事で述べられたことを要約すると、Grapeは、Mavenリポジトリーから依存関係を動的にロードするための組み込みメカニズムです。 私は、スプリングブートからGrapeEngineプロバイダーに必要な部分のみを抽出し、それをAetherおよび最低限必要な依存関係のセットと組み合わせました。 問題のあるIvyプロバイダーは不要になりました。 私のプロジェクトでは、むしろMVELからGroovyに切り替えます。 そして、Grapeによる実験の成功と、Groovyでの新しい自由度とプログラミングの容易さを願っています。
Groovy、Ivy、およびMavenは、依存関係を動的に接続する技術であるGrapeグルーブ言語の一部をバインドすることを発見し、スクリプトでGrapeを使用する方法を学びます。