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はフレームワーク起動時にDispatcherServletがWebApplicationContextを初期化します。このとき、設定ファイル(xml/@Configuration)やMessageSource、静的リソースがクラスローダのclasspath経由で読み込まれます。Eclipseのデフォルトでは、プロジェクト出力ディレクトリ(通常はbinまたはtarget/classes)がビルドパスに含まれていますが、これがWAR展開時に正しくWEB-INF/classesにコピーされているかがカギになります。
SpringMVC+Eclipseでclasspathを正しく設定する実践ガイド
ステップ1:プロジェクト構造を「分かりやすく」組み立てる
- Mavenを使う場合は
m2e-wtpプラグインをインストールしておきます。
Eclipse MarketPlace →「m2e-wtp」と検索 → Install - プロジェクト作成時に
packaging=warを指定し、Dynamic Web Module 4.0を有効にします。 - 以下のディレクトリを手動で作成(存在しない場合)
src/main/java → コンパイル後、WEB-INF/classesへ src/main/resources → 同上(xml/properties/messages.propertiesなど) src/main/webapp → ここがWebContentルート。WEB-INF以下は直接配置 .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:依存ライブラリを「正しい場所」に置く
- Maven/Gradleを使う
pom.xmlでprovidedスコープを間違えない。
-spring-webmvc→compile(WARに含める) -tomcat-embed-jasper→provided(サーバが提供) - 手動でjarを追加したい場合
- jarを
WebContent/WEB-INF/lib(古い表記)またはsrc/main/webapp/WEB-INF/libに直置き - Eclipseでプロジェクト右クリック → Build Path → Configure Build Path → Libraries → Add JARs...で上記フォルダのjarを選択
- 同じjarが二重でビルドパスに入ると
ClassNotFoundExceptionの原因になるため、必ず「Order and Export」で重複を排除 - ランタイム確認
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.propertiesはsrc/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.properties→db.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アプリ開発の王道』(翔泳社)
