スクリプトのストリートマジック、またはGroovy、Ivy、Mavenをリンクするものは何ですか?

複雑なMVELスクリプト+ MavenClassloaderのデバッグで苦労した後、動的依存関係解決のメカニズムがGroovyにあることを発見しました。 さらに、IdeaとEclipseの両方でGroovyスクリプトのデバッグが可能です。







動的な依存関係の解決が必要な理由を尋ねるかもしれません。 これを行うのが簡単なものもあれば、可能なものもあります。



この出版物には、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を実行します

そして、コンソールで、スクリプトがリポジトリ内の依存関係を見つけて動作する様子を観察します
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を使用する方法を学びます。



All Articles