markdown

はじめに (対象読者・この記事でわかること)

この記事は、SpringMVCをEclipseで開発・実行しようとしているが「なぜかクラスが見つからない」「プロパティファイルが読めない」「ローカル環境では動くのに本番で動かない」といったclasspath関連のエラーに悩まされているJavaエンジニアを対象としています。

読み進めることで以下のことがわかります。

  • Eclipseが参照する「ビルドパス」と、Tomcatが参照する「ランタイムclasspath」の違い
  • Spring Boot時代に忘れがちな「WEB-INF/lib」「WEB-INF/classes」の正しい置き方
  • ソース・リソース・設定ファイルを正しい場所に置くための3つのチェックリスト
  • よくある4つのエラー(ClassNotFound/FileNotFound/NoSuchBeanDefinition/Resource not found)の原因特定&即解決手順

前提知識

  • Java SE 8以上の文法が読める
  • EclipseにてDynamic Web Projectの作成経験がある
  • SpringMVC(@Controller/@RequestMapping)の基本概念を知っている
  • MavenまたはGradleで依存ライブラリを解決したことがある

Eclipseの「ビルドパス」とTomcatの「classpath」は別物だった!

SpringMVCをEclipseで動かすとき、まず勘違いするのが「ビルドが通れば実行も大丈夫」という発想です。Eclipseはコンパイル時に必要なjarを「ビルドパス」で解決しますが、TomcatなどのServletコンテナは独自のクラスローダ階層を持っています。つまり、

  • Eclipse上で赤エラーが出ない=ランタイムでも見える ✕
  • WEB-INF/libに入っていれば必ず見える △(後述の「階層の罠」あり)

SpringMVCはフレームワーク起動時にDispatcherServletWebApplicationContextを初期化します。このとき、設定ファイル(xml/@Configuration)やMessageSource、静的リソースがクラスローダのclasspath経由で読み込まれます。Eclipseのデフォルトでは、プロジェクト出力ディレクトリ(通常はbinまたはtarget/classes)がビルドパスに含まれていますが、これがWAR展開時に正しくWEB-INF/classesにコピーされているかがカギになります。

SpringMVC+Eclipseでclasspathを正しく設定する実践ガイド

ステップ1:プロジェクト構造を「分かりやすく」組み立てる

  1. Mavenを使う場合はm2e-wtpプラグインをインストールしておきます。
    Eclipse MarketPlace →「m2e-wtp」と検索 → Install
  2. プロジェクト作成時にpackaging=warを指定し、Dynamic Web Module 4.0を有効にします。
  3. 以下のディレクトリを手動で作成(存在しない場合)
    src/main/java → コンパイル後、WEB-INF/classesへ src/main/resources → 同上(xml/properties/messages.propertiesなど) src/main/webapp → ここがWebContentルート。WEB-INF以下は直接配置
  4. .settings/org.eclipse.wst.common.componentを開き、以下のようにdeploy-pathを確認: xml <wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/> <wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/> これが間違っていると「Eclipse上で動くのにWARエクスポートすると動かない」現象が起きます。

ステップ2:依存ライブラリを「正しい場所」に置く

  1. Maven/Gradleを使う
    pom.xmlprovidedスコープを間違えない。
    - spring-webmvccompile(WARに含める) - tomcat-embed-jasperprovided(サーバが提供)
  2. 手動でjarを追加したい場合
  3. jarをWebContent/WEB-INF/lib(古い表記)またはsrc/main/webapp/WEB-INF/libに直置き
  4. Eclipseでプロジェクト右クリック → Build Path → Configure Build Path → Libraries → Add JARs...で上記フォルダのjarを選択
  5. 同じjarが二重でビルドパスに入るとClassNotFoundExceptionの原因になるため、必ず「Order and Export」で重複を排除
  6. ランタイム確認
    ServersビューからTomcatを右クリック →「Modules」タブで該当Webアプリを選択 →「Open launch configuration」→ ArgumentsタブのVM arguments末尾に
    -Djava.class.path=%CLASSPATH%を付けてデバッグ出力すると、実際に読み込まれているclasspathがcatalina.outに出力されます。

ステップ3:Spring設定ファイル・プロパティの読み込みパスを整理

xmlベースの場合
web.xml

Xml
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> </servlet>

spring-mvc.xml

Xml
<!-- プロパティファイルをclasspath上から読む --> <context:property-placeholder location="classpath:app.properties"/>

このときapp.propertiessrc/main/resources直下に置き、ビルド後WEB-INF/classes/app.propertiesに存在することが必須です。

JavaConfigの場合

Java
@Configuration @PropertySource("classpath:app.properties") public class AppConfig { }

ハマった点1:「resources」フォルダがビルドパスに含まれていない

症状
ClassPathResource("app.properties").exists()が常にfalseを返す
原因
Eclipseのデフォルト構成ではsrc/main/resourcesが「Excluded」になっている
解決策
プロジェクト右クリ → Properties → Java Build Path → Sourceタブ → src/main/resourcesを選択 → Excludedを空にする

ハマった点2:Lombokなどのannotation processorが出力したクラスが見えない

症状
@Slf4jを付けたクラスでlog変数が解決できない
原因
EclipseのJDT APTが有効でない/出力先がtarget/generated-sourcesのまま
解決策
1. Help → Eclipse MarketPlace →「m2e-apt」インストール 2. Preferences → Maven → Annotation Processing →「Automatically configure JDT APT」にチェック 3. プロジェクト右クリ → Maven → Update Project →「Resolve Workspace projects」にチェック後更新

ハマった点3:WARエクスポート時にWEB-INF/libが空

症状
エクスポートしたWARをTomcatスタンドアローンにデプロイするとClassNotFoundException
原因
Mavenのprovidedスコープを誤用、あるいは「Export」を無効化
解決策
pom.xmlで本当にサーバが提供するライブラリ(servlet-api、jsp-apiなど)のみprovidedにし、あとはcompileに変更。Eclipseの「Export」チェックを付け直してからWARエクスポート

ハマった点4:ローカルでは動くのに本番Linuxでプロパティファイルが読めない

症状
@PropertySource("classpath:db.properties")で本番のみFileNotFoundException
原因
Windowsでは大文字小文字無視、Linuxでは厳密
解決策
ファイル名を正確に合わせる。DB.propertiesdb.propertiesにリネームしてclean package

まとめ

本記事では、EclipseでSpringMVCを開発・実行する際の「ビルドパス」と「ランタイムclasspath」の違いを整理し、実際にプロジェクトを作成・設定・トラブルシューティングする手順を解説しました。

  • Eclipseが解決するビルドパスと、Servletコンテナが参照するclasspathは別物
  • Maven/Gradleを使う場合でもprovidedスコープとWARパッケージの含まれ方を意識する
  • resourcesフォルダが正しくデプロイパスに含まれているかを.settings/org.eclipse.wst.common.componentでチェック
  • 4つのハマりポイント(resources除外、APT無効、WAR空、大文字小文字)を押さえると90%のclasspathエラーが解消

正しいclasspath管理は、Spring Bootに代表される「すべてをjarに詰め込む」時代においても、レガシーWebアプリや独自サーバ環境では依然として必須スキルです。次回は「Gradle+VS CodeでSpring Bootをコンテナビルドする」というテーマで、よりモダンな開発環境でのclasspath・レイヤードJarの話を掘り下げていきます。

参考資料

  • Eclipse公式Wiki「WTP Tutorials – Building and Running a Web Application」
  • Spring Framework Reference「Resources」章
  • m2e-wtpプロジェクトGitHub https://github.com/eclipse-m2e/m2e-wtp
  • 山田祥寛『Spring MVCアプリ開発の王道』(翔泳社)