spring framework を使ったデスクトップアプリ(standalone app)で maven-jar-plugin を使って作成した JAR を java コマンドで実行する

公開日: : 最終更新日:2014/01/28 Maven , ,

spring framework を使ったデスクトップアプリ(standalone app)で context から getBean でオブジェクトを取得するの記事で書いた Spring を使ったデスクトップアプリを JAR に固めて java コマンドで実行するまでの検証です。
単純に maven-jar-plugin を書くだけでは動かなかったので勉強になりました。
検証プログラムは Github に登録してあります。

icatch-maven

目次

1. 動作環境

1-1. Java

Java のバージョンは次の通りです。

$ java -version
java version "1.7.0_11"
Java(TM) SE Runtime Environment (build 1.7.0_11-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode)

ですが、いろいろ都合があって、pom.xml にはコンパイラのバージョンを 1.6 で定義しています。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.0</version>
  <configuration>
    <source>1.6</source>
    <target>1.6</target>
    <encoding>UTF-8</encoding>
  </configuration>
</plugin>

1-2. Maven

この検証プログラムは Maven を使ってビルドしています。 プログラム作成時に使用した Maven のバージョンは次の通りです。

$ mvn -v
Apache Maven 3.0.4 (r1232337; 2012-01-17 17:44:56+0900)
Maven home: C:\Users\xxx\maven-3.0.4
Java version: 1.7.0_11, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.7.0_11\jre
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"

1-3. Spring

pom.xml を見ればそこにバージョンは書いてありますが。

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>3.2.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>3.2.6.RELEASE</version>
</dependency>

2. プログラムについて

検証プログラムは次の3本です。

  • src/main/java/net/tomoyamkung/App.java
  • src/main/java/net/tomoyamkung/model/HogeModel.java
  • src/main/java/net/tomoyamkung/model/HogeModelImpl.java

それぞれのプログラムの JavaDoc を載せておきます。 どのような役割をもったプログラムなのか何となく分かると思います。

2-1. App.java

/**
 * 動作確認用の実行クラス。
 * 
 * @author tomoyamkung
 *
 */

2-2. HogeModel.java

/**
 * Context から取得するサンプル Bean のインタフェース。
 * 
 * @author tomoyamkung
 *
 */

2-3. HogeModelImpl.java

/**
 * Context から取得するサンプル Bean クラス。
 * 
 * @author tomoyamkung
 *
 */

3. pom.xml に何も追加しない状態で java コマンドを実行してみる

pom.xml に JAR 作成関係のプラグインを設定していないので動かないのは当然なんですが、違いを確認するために実行しておきます。
手順は次の通りです。

  1. maven を使ってプロジェクトをビルドする
  2. 生成された JAR を適当なディレクトリに移す
  3. java コマンドを実行する

ビルドすると target ディレクトリに JAR が作成されます。

$ mvn clean package
$ ls target/*.jar
target/spring-standalone-sample.jar

この JAR をどこか適当なディレクトリに移します。
ここではプロジェクト直下に hoge ディレクトリを作って、そこに移しました。

$ mkdir hoge
$ cp target/*.jar ./hoge 
$ ls hoge 
spring-standalone-sample.jar

で、実行すると、当然次のように怒られます。

$ java -jar hoge/spring-standalone-sample.jar 
hoge/spring-standalone-sample.jarにメイン・マニフェスト属性がありません

4. pom.xml に maven-jar-plugin を追加した状態で java コマンドを実行してみる

「マニフェストファイルがない」と怒られたので pom.xml に maven-jar-plugin を追加します。

plugins タグ内に次を追加します。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <version>2.4</version>
  <configuration>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath>
        <addExtensions>true</addExtensions>
        <mainClass>net.tomoyamkung.App</mainClass>
        <classpathPrefix>lib</classpathPrefix>
      </manifest>
    </archive>
  </configuration>
</plugin>

manifest タグに設定を書くのですが、詳細は次のページがわかりやすかったです。


では、再びビルドして JAR を実行してみます。

$ mvn clean package
$ cp target/*.jar ./hoge 
$ java -jar hoge/spring-standalone-sample.jar 
java.lang.NoClassDefFoundError: org/springframework/context/support/AbstractApplicationContext
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.getMethod0(Unknown Source)
        at java.lang.Class.getMethod(Unknown Source)
        at sun.launcher.LauncherHelper.getMainMethod(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.springframework.context.support.AbstractApplicationContext
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 6 more
Exception in thread "main" %

Spring 関係のクラスが見つからないと怒られました。
JAR を解凍してみると確かに Spring 関係のライブラリがありませんでした。

$ cd hoge
$ jar -xf spring-standalone-sample.jar
$ find ./ -name "*.jar"
./spring-standalone-sample.jar  # JAR はこのプロジェクトのものだけ
find ./ -name "*.class"  # class ファイルもこのプロジェクトのものだけ
./net/tomoyamkung/App.class
./net/tomoyamkung/model/HogeModel.class
./net/tomoyamkung/model/HogeModelImpl.class

5. pom.xml に maven-shade-plugin を追加した状態で java コマンドを実行してみる

Spring 関係のライブラリが欠けていたので、それっぽいキーワードで検索すると次のページを見つけました。

次は上記サイトからの引用です。

Maven2 では maven-shade-plugin を利用することで依存するライブラリも含んだ jar を作成することができる。

探し求めていたのはコレです!


が、単純に上記サイトの設定をコピペしただけでは動かず、maven-shade-plugin やら spring といったキーワードで調べつつ試行錯誤を繰り返した結果の設定が次のものです。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>2.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <artifactSet>
          <excludes>
            <exclude>junit:junit</exclude>
          </excludes>
        </artifactSet>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformer"/>
          <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/spring.handlers</resource>
          </transformer>
          <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/spring.schemas</resource>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

三度ビルドして JAR を実行してみます。

$ mvn clean package
$ cp target/*.jar ./hoge 
$ java -jar hoge/spring-standalone-sample.jar 
2014-01-xx xx:xx:xx,xxx DEBUG net.tomoyamkung.model.HogeModelImpl.printLog:22 - Hello, spring-standalone-sample!!

今度は依存関係が解消されて正常に実行できました。

6. まとめ

今回追加した設定をバージョン 0.2 としてタグ付けしました。

よかったら参考にしてみてください。

7. その他の Spring に関する記事

Spring に関する記事は次の通りです。
気になる記事があったらぜひチェックしてみてください!

Googleアドセンス用(PC)

  • このエントリーをはてなブックマークに追加
  • follow us in feedly

関連記事

no image

Exec Maven Plugin で maven コマンドでアプリを起動する

packaging タグに "jar" を指定した Maven プロジェクトをコマンドラインから起動

記事を読む

icatch-maven-create_mini

Maven で Web アプリ用のプロジェクトを作成してからコーディングを着手するまでにやること

Java を使った開発プロジェクトでは Maven を使っています。 archetype:crea

記事を読む

icatch-maven_5928412787

Maven で作成したプロジェクトのソースコードを JAR にする方法

Maven で作成したプロジェクトのソースコードを JAR にまとめて公開する方法を調べてみました。

記事を読む

Googleアドセンス用(PC)

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


4 − = 一

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Googleアドセンス用(PC)

icatch-jersey_multi_pathparams
Jerseyの@PathParamはスラッシュの間に複数指定できる

http://hoge-api/user/{id}.{format}

icatch-vagrant_box_customize
VagrantのBoxファイルをカスタマイズして独自のBoxファイルを作成する

配布されている Vagrant の Box ファイルを使って検証環境を

icatch-2015-006-1
バリデーションチェックにJava8のOptionalを使ってスマートに書く(自分比)

Web アプリのバリデーションチェックにアノテーションを使うことが増え

icatch-2015-005-1
ユニットテストの偏りを防ぐ命名規則の付け方

ユニットテスト名に以下の命名規則を付けるようにして二ヶ月ぐらい経った。

icatch-2015-004-1
Vagrantで起動したCentOS上のOctopressをホストOSから確認する設定

タイトルの通りだが、Vagrant を使って起動した CentOS に

→もっと見る

PAGE TOP ↑